multiefekt/main.cpp

356 lines
10 KiB
C++
Raw Permalink Normal View History

2022-06-01 08:34:17 +02:00
#include "effects.h"
#define TESTING 0
#define REVERB 1
#define CHORUS 2
#define FLANGER 3
#define ECHO 4
#define DISTORTION 5
#define TREMOLO 6
volatile uint8_t sampleReady = 0; //zmienna kotrolująca możliwość podania nowej wartości do DAC
volatile uint8_t adcVal = 0;
volatile uint8_t effect = REVERB; //wybrany efekt
volatile uint32_t counter = 0;
static const uint8_t sine [101] = {0,0,0,0,1,1,2,2,3,4,5,6,7,8,10,11,12,14,16,17,19,21,23,25,27,29,32,34,36,39,41,44,46,49,
2022-06-01 08:34:17 +02:00
52,55,57,60,63,66,69,72,75,78,81,84,87,91,94,97,100,103,106,109,113,116,119,122,125,128,131,134,137,140,143,145,148,
151,154,156,159,161,164,166,168,171,173,175,177,179,181,183,184,186,188,189,190,192,193,194,195,196,197,198,198,199,
199,200,200,200,200};
volatile uint8_t effectSetting = 5;
static const uint8_t effectSettingVector [9] = {0, 5, 15, 30, 55, 90, 130, 180, 255};
2022-06-01 08:34:17 +02:00
volatile uint8_t encoderDir = 0; //0 - w lewo, 1 - w prawo
volatile uint8_t encoderServed = 1;
//timer0 służy tylko do aktywacji odczytu przez ADC (i do debouncingu)
ISR(TIMER0_COMPA_vect){
counter++;
}
ISR(TIMER1_OVF_vect){
OCR1A = effectSettingVector[effectSetting -1];//20 * effectSetting - 15; //od 25 do 225
}
ISR(INT0_vect){
if(encoderServed){
if(!(PIND & 0x08)){
encoderDir = 0;
} else if(PIND & 0x08){
encoderDir = 1;
}
encoderServed = 0;
}
}
ISR(ADC_vect){
adcVal = ADCH;
sampleReady = 1; //dopiero po odczytaniu nowej wartości ADC uruchomiona jest możliwość podania nowej wartości do DAC
}
int main(void){
//wyprowadzenie do sterowania wejsciem sygnalu nieprzetworzonego
DDRC |= 1<<DDC5;
//enkoder do zmiany parametru efektu
DDRD &= ~(1<<DDD2 | 1<<DDD3);
//przycisk do zmiany efektu
DDRD &= (1<<DDD4);
PORTD |= (1<<DDD4);
//przycisk do aktywacji efektu
DDRD &= (1<<DDD1);
PORTD |= (1<<DDD1);
//diody sygnalizujące wybrany efekt
DDRD |= (1<<DDD5) | (1<<DDD6) | (1<<DDD7);
//dioda sygnalizująca aktywację efektu
DDRB |= (1<<DDB0);
//dioda, której intensywność świecenia wskazuje na parametr efektu
DDRB |= (1<<DDB1);
//TIMER0
//Prescaler = 64; pojemność bufora 1850;
//250 000 / 41,67 kHz = 6 ; 1850 / 41,67 kHz = 44,4 ms
//250 000 / 20,83 kHz = 12; 1850 / 20,83 kHz = 88,8 ms
//250 000 / 10 kHz = 25; 1850 / 10 kHz = 185 ms
//250 000 / 8,065 kHz = 31; 1850 / 8,065 kHz = 229,4 ms
//250 000 / 5 kHz = 50; 1850 / 5 kHz = 370 ms
TCCR0A = (1<<WGM01); //CTC
TCCR0B = (1<<CS01) | (1<<CS00); //prescaler = 64
OCR0A = 25;
TIMSK0 = (1<<OCIE0A);
//TIMER1
//Do sterowania diodą (PWM)
TCCR1A = (1<<COM1A1) | (1<<WGM10); //OC1A, Clear on compare match; Fast PWM 8-bit
TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10); //Fast PWM 8-bit; fosc/1024
OCR1A = 128;
TIMSK1 = (1<<TOIE1); //Przerwanie przy przepełnieniu do aktualizacji wartości wypełnienia.
//ADC
ADMUX = (1<<REFS0) | (1<<ADLAR); //Vref = AVcc, przesuniecie do lewej, ADC0
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) /*(1<<ADPS1) | (1<<ADPS0)*/; //częstotliwość zegara ADC = 1 MHz
ADCSRB = (1<<ADTS1) | (1<<ADTS0); //triggerowanie ADC przerwaniem od przepełnienia timera 0
DIDR0 = (1<<ADC0D);
//INT0
EICRA = 1<<ISC01; //wyzwalanie zboczem opadającym
EIMSK = 1<<INT0; //aktywacja
sei();
spiInit();
int16_t valueToSend = 128; //wartość do przekazania do DAC; int16_t (16 bitowy, ze znakiem) w celu implementacji nasycenia
//bufor na dane i jego inicjalizacja wartościami 128
uint8_t buffer [BUFFER_LENGTH] = {0};
for(uint16_t i = 0; i < BUFFER_LENGTH; i++){
buffer[i] = 128;
}
uint16_t bufferIndex = 0; //indeks najnowszej próbki
//Przyciski
uint32_t counterButton = 0;
uint8_t buttonPressed = 0;
uint32_t counterButton2 = 0;
uint8_t buttonPressed2 = 0;
uint8_t effectOn = 0;
//Enkoder
uint32_t counterEncoder = 0;
//Chorus
uint8_t sineIndex = 0; //indeks wartości z wektora z sinusem
uint8_t chorusCounter = 0; //licznik służacy do spowolnienia zmian w opóźnieniu
//użyty zamiast licznika od timera, żeby operować na wartości 8-bitowej zamiast 32-bitowej
uint8_t chorusDirChange = 0; //0 - inkrementacja, 1 - dekrementacja
//Flanger
uint8_t flangerDelayTime = _0MS;
uint8_t flangerCounter = 0;
uint8_t flangerDirChange = 0;
//Echo
uint16_t echoIndex = 0;
//Tremolo
uint8_t tremoloCounter = 0;
uint8_t tremoloDirChange = 0;
while(1){
//Obsługa przycisku od przełączania efektu
if(counter - counterButton >= _50MS){
if(!(PIND & 0x10) && !buttonPressed){
//Jeżeli przed zmianą na echo znajduje się coś w buforze, to istnieje ryzyko wystąpienia zapętlenia próbki,
//stąd zerowanie buforu.
if(effect == ECHO - 1) {
for(uint16_t i = 0; i < BUFFER_LENGTH; i++){
buffer[i] = 128;
}
}
effect++;
if(effect > TREMOLO) effect = REVERB;
buttonPressed = 1;
} else if(PIND & 0x10 && buttonPressed) buttonPressed = 0;
counterButton = counter;
}
//obsługa przycisku od aktywacji efektu i diody sygnalizującej aktywację efektu
if(counter - counterButton2 >= _50MS){
if(!(PIND & 0x02) && !buttonPressed2){
if(effectOn){
effectOn = 0;
PORTB &= ~(1<<PORTB0);
} else {
effectOn = 1;
PORTB |= (1<<PORTB0);
}
buttonPressed2 = 1;
} else if(PIND & 0x02 && buttonPressed2) buttonPressed2 = 0;
counterButton2 = counter;
}
if(counter - counterEncoder >= _20MS && !encoderServed){
if(encoderDir == 1){
if(effectSetting < 9) effectSetting++;
} else {
if(effectSetting > 1) effectSetting--;
}
counterEncoder = counter;
encoderServed = 1;
}
if(sampleReady){
if(effect < ECHO) buffer[bufferIndex] = adcVal; //zapisanie aktualnej próbki na najnowszą pozycję w buforze
//pod warunkiem że efekt to REVERB, CHORUS lub FLANGER
if(effect == TESTING){
valueToSend = adcVal;
PORTD &= ~((1<<PORTD7) | (1<<PORTD6) | (1<<PORTD5));
//PORTC &= ~(1<<PORTC5);
PORTC |= 1<<PORTC5;
} else if(effect == REVERB){
PORTC |= 1<<PORTC5;
valueToSend = reverb(buffer, bufferIndex, effectSetting);
PORTD |= (1<<PORTD5);
PORTD &= ~((1<<PORTD7) | (1<<PORTD6));
} else if(effect == CHORUS){
PORTC |= 1<<PORTC5;
valueToSend = chorusFlanger(buffer, bufferIndex, sine[sineIndex] + _40MS, 10 - effectSetting);
chorusCounter++;
if(chorusCounter >= 200){
if(chorusDirChange == 0){
sineIndex++;
if(sineIndex >= 100) chorusDirChange = 1;
} else {
sineIndex--;
if(sineIndex == 0) chorusDirChange = 0;
}
chorusCounter = 0;
}
PORTD |= (1<<PORTD6);
PORTD &= ~((1<<PORTD7) | (1<<PORTD5));
} else if(effect == FLANGER){
PORTC |= 1<<PORTC5;
valueToSend = chorusFlanger(buffer, bufferIndex, flangerDelayTime, 10 - effectSetting);
flangerCounter++;
if(flangerCounter >= 100){
if(flangerDirChange == 0){
flangerDelayTime++;
if(flangerDelayTime >= _10MS) flangerDirChange = 1;
} else {
flangerDelayTime--;
if(flangerDelayTime == _0MS) flangerDirChange = 0;
}
flangerCounter = 0;
}
PORTD |= (1<<PORTD5) | (1<<PORTD6);
PORTD &= ~(1<<PORTD7);
} else if(effect == ECHO){
PORTC |= 1<<PORTC5;
echoIndex = bufferIndex + (_16MS * effectSetting) + _41MS; //obliczenie miejsca zapisu próbki "na później"
if(echoIndex > BUFFER_LENGTH) echoIndex -= BUFFER_LENGTH;
buffer[echoIndex] = (adcVal - 128)/2 + 2*(buffer[bufferIndex] - 128)/3 + 128; // wpisanie z opóźnieniem i tłumieniem aktualnej wartości
valueToSend = buffer[bufferIndex];
PORTD |= (1<<PORTD7);
PORTD &= ~((1<<PORTD6) | (1<<PORTD5));
} else if (effect == DISTORTION){
if(effectOn){
PORTC &= ~(1<<PORTC5);
} else {
PORTC |= (1<<PORTC5);
}
valueToSend = distortion(164 - effectSetting*4, adcVal);
PORTD |= (1<<PORTD7) | (1<<PORTD5);
PORTD &= ~((1<<PORTD6));
} else if(effect == TREMOLO){
if(effectOn){
PORTC &= ~(1<<PORTC5);
} else {
PORTC |= (1<<PORTC5);
}
valueToSend = tremolo(adcVal, sine[sineIndex]);
tremoloCounter++;
if(tremoloCounter >= 1 + effectSetting){
if(tremoloDirChange == 0){
sineIndex++;
if(sineIndex >= 100) tremoloDirChange = 1;
} else {
sineIndex--;
if(sineIndex == 0) tremoloDirChange = 0;
}
tremoloCounter = 0;
}
PORTD |= (1<<PORTD7) | (1<<PORTD6);
PORTD &= ~((1<<PORTD5));
} else {
effect = REVERB;
}
//implementacja przesterowania programowego
if(valueToSend > 255){
valueToSend = 255;
} else if(valueToSend < 0){
valueToSend = 0;
}
if (effectOn) {
analogWrite(valueToSend);
} else {
analogWrite(128);
}
sampleReady = 0;
//zmiana indeksu dla kolejnej próbki
bufferIndex++;
if(bufferIndex >= BUFFER_LENGTH) bufferIndex = 0;
}
}
}
//Wykorzystana pamięć
//sampleReady = 1 B
//adcVal = 1 B
//effect = 1 B
//counter = 4 B
//sine = 101 B
//effectSetting = 1 B
//effectSettingVector = 9 B
//encoderLeft = 1 B
//encoderRight = 1 B
//encoderServed = 1 B
//valueToSend = 2 B
//bufor = 1851 B
//bufferIndex = 2 B
//counterButton1 = 4 B
//buttonPressed1 = 1 B
//counterButton2 = 4 B
//buttonPressed2 = 1 B
//effectOn = 1 B
//counterEncoder = 4 B
//chorusSineIndex = 1 B
//chorusCounter = 1 B
//chorusDirChange = 1 B
//flangerDelayTime = 1 B
//flangerCounter = 1 B
//flangerDirChange = 1 B
//echoIndex = 2 B
//14 zmiennych w reverbie
//echo#Index... = 14 B (7x2 B)
//echo#Temp... = 14 B (7x2 B)
//3 zmienne w chorusie/flangerze
//echoIndex = 2 B
//echoTemp = 2 B
//W najgorszym przypadku łącznie: 2031 B
//Pozostaje: (2048 - 2031) B = 17 B