// Copyright 2012 Olivier Gillet.
//
// Author: Olivier Gillet (olivier@mutable-instruments.net)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
#include "avrlibx/system/init.h"
#include "avrlibx/system/time.h"
#include "avrlibx/system/timer.h"
#include "avrlibx/utils/op.h"
#include "edges/adc_acquisition.h"
#include "edges/audio_buffer.h"
#include "edges/digital_oscillator.h"
#include "edges/hardware_config.h"
#include "edges/midi.h"
#include "edges/midi_handler.h"
#include "edges/settings.h"
#include "edges/timer_oscillator.h"
#include "edges/ui.h"
using namespace avrlibx;
using namespace edges;
MidiIO midi_io;
MidiBuffer midi_in_buffer;
midi::MidiStreamParser midi_parser;
GateInputs gate_inputs;
DACSS dac_ss;
AudioDACInterface audio_dac;
ADCSS adc_ss;
ADCInterface adc;
AudioRateTimer audio_rate_timer;
SyncSwitch sync_switch;
TimerOscillator channel_0;
TimerOscillator channel_1;
TimerOscillator channel_2;
TimerOscillator channel_3;
DigitalOscillator channel_4;
// Channel 1 overflow. If sync is enabled, reset the phase of the channel 2.
ISR(TCD0_OVF_vect) {
Channel2Timer::Restart();
}
volatile uint16_t audio_interrupt_count = 0;
uint8_t channel_remapping[] = { 0, 1, 4, 5, 2, 3, 6, 7};
// Audio rate interrupt (48.048kHz).
ISR(TCE0_OVF_vect) {
// Shove a sample to the DAC.
uint16_t sample = audio_buffer.ImmediateRead();
audio_dac.Strobe();
Word sample_12bits;
sample_12bits.value = sample | 0x3000;
audio_dac.Overwrite(sample_12bits.bytes[1]);
audio_dac.Overwrite(sample_12bits.bytes[0]);
// Step through the ADC pipeline.
int8_t result = adc_acquisition.Cycle();
if (result != -1) {
uint16_t value = adc_acquisition.channel(result);
#ifdef OCTAL_ADC
value = 4095 - value;
result = channel_remapping[result];
#endif // OCTAL_ADC
ui.set_cv(result, value);
}
// When a conversion is finished, update the corresponding channel
// Note that the UI can take over the value read from the DAC, for example
// When programming an arpeggio
switch (result) {
case 0:
channel_1.UpdatePitch(
midi_handler.shift_pitch(0,
settings.dac_to_pitch(0, ui.cv(0))) +
settings.dac_to_fm(0, ui.cv(4)),
settings.pw(0));
channel_0.SubFollow(channel_1);
break;
case 1:
channel_2.UpdatePitch(
midi_handler.shift_pitch(1,
settings.dac_to_pitch(1, ui.cv(1))) +
settings.dac_to_fm(1, ui.cv(5)),
settings.pw(1));
break;
case 2:
channel_3.UpdatePitch(
midi_handler.shift_pitch(2,
settings.dac_to_pitch(2, ui.cv(2))) +
settings.dac_to_fm(2, ui.cv(6)),
settings.pw(2));
break;
case 3:
{
channel_4.UpdatePitch(
midi_handler.shift_pitch(3,
settings.dac_to_pitch(3, ui.cv(3))) +
settings.dac_to_fm(3, ui.cv(7)),
settings.shape(3));
#ifndef OCTAL_ADC
uint8_t cv_controlled_pw_8bit = U16ShiftRight4(ui.cv(3));
channel_1.set_cv_pw(cv_controlled_pw_8bit);
channel_2.set_cv_pw(cv_controlled_pw_8bit);
channel_3.set_cv_pw(cv_controlled_pw_8bit);
#endif // #ifndef OCTAL_ADC
}
break;
#ifdef OCTAL_ADC
case 4:
channel_1.set_cv_pw(U16ShiftRight4(ui.cv(4)));
break;
case 5:
channel_2.set_cv_pw(U16ShiftRight4(ui.cv(5)));
break;
case 6:
channel_3.set_cv_pw(U16ShiftRight4(ui.cv(6)));
break;
case 7:
channel_4.set_cv_pw(U16ShiftRight4(ui.cv(7)));
break;
#endif // #ifdef OCTAL_ADC
default:
{
// Otherwise, scan the gate.
uint8_t gate = ~gate_inputs.value();
bool g_1 = (gate & 1) || midi_handler.gate(0) || settings.arpeggio(0);
channel_0.Gate(g_1);
channel_1.Gate(g_1);
bool g_2 = (gate & 2) || midi_handler.gate(1) || settings.arpeggio(1);
channel_2.Gate(g_2);
bool g_3 = (gate & 4) || midi_handler.gate(2) || settings.arpeggio(2);
channel_3.Gate(g_3);
bool g_4 = (gate & 8) || midi_handler.gate(3) || settings.arpeggio(3);
channel_4.Gate(g_4);
// Read some MIDI bytes, but process them later.
if (midi_io.readable()) {
midi_in_buffer.NonBlockingWrite(midi_io.ImmediateRead());
}
}
break;
}
++audio_interrupt_count;
}
inline void Init() {
SysInit();
sync_switch.set_direction(INPUT);
sync_switch.set_mode(PORT_MODE_PULL_UP);
gate_inputs.set_direction(INPUT);
gate_inputs.set_mode(PORT_MODE_PULL_UP);
ui.Init();
// Reset to factory default if any switch is pressed during boot.
settings.Init(!(Switches::Read() & 8));
midi_io.Init();
midi_handler.Init();
audio_dac.Init();
audio_dac.Strobe();
audio_dac.Overwrite(0x1f);
audio_dac.Overwrite(0xff);
channel_0.Init();
channel_1.Init();
channel_2.Init();
channel_3.Init();
channel_4.Init();
adc_acquisition.Init();
audio_rate_timer.set_prescaler(TIMER_PRESCALER_CLK);
audio_rate_timer.set_period(665); // 48kHz
audio_rate_timer.set_mode(TIMER_MODE_NORMAL);
audio_rate_timer.EnableOverflowInterrupt(2);
}
int main(void) {
Init();
while (1) {
// Render audio.
channel_4.Render();
// Scan MIDI in.
while (midi_in_buffer.readable()) {
midi_parser.PushByte(midi_in_buffer.ImmediateRead());
}
// Do some UI stuff.
if (audio_interrupt_count >= 48) {
audio_interrupt_count -= 48;
uint8_t gate = ~gate_inputs.value();
// Detect new notes and forward to UI subsystem for calibration functions.
uint8_t mask = 1;
for (uint8_t channel = 0; channel < kNumChannels; ++channel) {
if ((gate & mask) && !(ui.gate() & mask)) {
settings.StepArpeggio(channel);
}
mask <<= 1;
}
ui.set_gate(gate);
ui.Poll();
}
// Check the status of the sync switch
if (sync_switch.value()) {
Channel1Timer::EnableOverflowInterrupt(3);
} else {
Channel1Timer::DisableOverflowInterrupt();
}
}
}