Étape 4: Le code
Auduino, la synthèse granulaire de Lo-Fi
//
par Peter Knight, Tinker.it http://tinker.it
//
Aide : http://code.google.com/p/tinkerit/wiki/Auduino
Plus d’aide : http://groups.google.com/group/auduino
//
Analogique à 0: 1 terrain de Grain
Analogique dans 1: décomposition de Grain 2
Analogique à 2: 1 désintégration du Grain
Analogique dans 3: terrain de Grain 2
Analogique 4: fréquence de répétition des céréales
//
3 numérique : Audio (numérique 11 sur ATmega8)
//
Changelog :
19 novembre 2008: ajout du support pour les planches de l’ATMEGA8.
21 mars 2009 : ajout du support pour les planches de l’ATmega328
7 avril 2009: le vecteur d’interruption fixe pour les planches de l’ATmega328
8 avril 2009: ajout du support pour cartes ATmega1280 (Arduino Mega)
#include < avr/io.h >
#include < avr/interrupt.h >
uint16_t syncPhaseAcc ;
uint16_t syncPhaseInc ;
uint16_t grainPhaseAcc ;
uint16_t grainPhaseInc ;
uint16_t grainAmp ;
uint8_t grainDecay ;
uint16_t grain2PhaseAcc ;
uint16_t grain2PhaseInc ;
uint16_t grain2Amp ;
uint8_t grain2Decay ;
Carte des canaux analogiques
#define SYNC_CONTROL (4)
#define GRAIN_FREQ_CONTROL (0)
#define GRAIN_DECAY_CONTROL (2)
#define GRAIN2_FREQ_CONTROL (3)
#define GRAIN2_DECAY_CONTROL (1)
Ce changement sera exige également réécriture audioOn()
#if defined(__AVR_ATmega8__)
//
Sur les anciennes commissions ATmega8.
Sortie est sur la broche 11
//
#define LED_PIN 13
#define LED_PORT PORTB
#define LED_BIT 5
#define PWM_PIN 11
#define PWM_VALUE OCR2
#define PWM_INTERRUPT TIMER2_OVF_vect
#elif defined(__AVR_ATmega1280__)
//
Sur l’Arduino Mega
Sortie est sur la broche 3
//
#define LED_PIN 13
#define LED_PORT PORTB
#define LED_BIT 7
#define PWM_PIN 3
#define PWM_VALUE OCR3C
#define PWM_INTERRUPT TIMER3_OVF_vect
#else
//
Pour les planches de ATmega168 et ATmega328 modernes
Sortie est sur la broche 3
//
#define PWM_PIN 3
#define PWM_VALUE OCR2B
#define LED_PIN 13
#define LED_PORT PORTB
#define LED_BIT 5
#define PWM_INTERRUPT TIMER2_OVF_vect
#endif
Cartographie logarithmique lisse
//
uint16_t antilogTable [] = {}
64830,64132,63441,62757,62081,61413,60751,60097,59449,58809,58176,57549,56929,56316,55709,55109,
54515,53928,53347,52773,52204,51642,51085,50535,49991,49452,48920,48393,47871,47356,46846,46341,
45842,45348,44859,44376,43898,43425,42958,42495,42037,41584,41136,40693,40255,39821,39392,38968,
38548,38133,37722,37316,36914,36516,36123,35734,35349,34968,34591,34219,33850,33486,33125,32768
};
uint16_t mapPhaseInc (entrée uint16_t) {}
Return (antilogTable [entrée & 0x3f]) >> (entrée >> 6) ;
}
A fait un pas de mappage chromatique
//
uint16_t midiTable [] = {}
17,18,19,20,22,23,24,26,27,29,31,32,34,36,38,41,43,46,48,51,54,58,61,65,69,73,
77,82,86,92,97,103,109,115,122,129,137,145,154,163,173,183,194,206,218,231,
244,259,274,291,308,326,346,366,388,411,435,461,489,518,549,581,616,652,691,
732,776,822,871,923,978,1036,1097,1163,1232,1305,1383,1465,1552,1644,1742,
1845,1955,2071,2195,2325,2463,2610,2765,2930,3104,3288,3484,3691,3910,4143,
4389,4650,4927,5220,5530,5859,6207,6577,6968,7382,7821,8286,8779,9301,9854,
10440,11060,11718,12415,13153,13935,14764,15642,16572,17557,18601,19708,20879,
22121,23436,24830,26306
};
uint16_t mapMidi (entrée uint16_t) {}
retour (midiTable[(1023-input) >> 3]) ;
}
Gradin cartographie pentatonique
//
uint16_t pentatonicTable [54] = {}
0,19,22,26,29,32,38,43,51,58,65,77,86,103,115,129,154,173,206,231,259,308,346,
411,461,518,616,691,822,923,1036,1232,1383,1644,1845,2071,2463,2765,3288,
3691,4143,4927,5530,6577,7382,8286,9854,11060,13153,14764,16572,19708,22121,26306
};
uint16_t mapPentatonic (entrée uint16_t) {}
uint8_t valeur = (1023-entrée) / (1024/53) ;
retour (pentatonicTable[value]) ;
}
void audioOn() {}
#if defined(__AVR_ATmega8__)
ATmega8 a différents registres
TCCR2 = _BV(WGM20) | _BV(COM21) | _BV(CS20) ;
TIMSK = _BV(TOIE2) ;
#elif defined(__AVR_ATmega1280__)
TCCR3A = _BV(COM3C1) | _BV(WGM30) ;
TCCR3B = _BV(CS30) ;
TIMSK3 = _BV(TOIE3) ;
#else
Mettre en place la PWM à 31,25 kHz, phase précise
TCCR2A = _BV(COM2B1) | _BV(WGM20) ;
TCCR2B = _BV(CS20) ;
TIMSK2 = _BV(TOIE2) ;
#endif
}
void setup() {}
pinMode(PWM_PIN,OUTPUT) ;
audioOn() ;
pinMode(LED_PIN,OUTPUT) ;
}
void loop() {}
La boucle est assez simple - il juste met à jour les paramètres pour les oscillateurs.
//
Évitez d’utiliser toutes les fonctions qui utilisent des interruptions ou désactiver les interruptions.
Qu’ils engendreront clics et fait ses besoins dans l’audio.
Cartographie de fréquence lisse
syncPhaseInc = mapPhaseInc(analogRead(SYNC_CONTROL)) / 4 ;
A fait un pas de mappage à notes MIDI: Db, D, Eb, C, E, F....
syncPhaseInc = mapMidi(analogRead(SYNC_CONTROL)) ;
A fait un pas de mappage pentatonique: D, E, G, A, B
syncPhaseInc = mapPentatonic(analogRead(SYNC_CONTROL)) ;
grainPhaseInc = mapPhaseInc(analogRead(GRAIN_FREQ_CONTROL)) / 2 ;
grainDecay = analogRead(GRAIN_DECAY_CONTROL) / 8 ;
grain2PhaseInc = mapPhaseInc(analogRead(GRAIN2_FREQ_CONTROL)) / 2 ;
grain2Decay = analogRead(GRAIN2_DECAY_CONTROL) / 4 ;
}
SIGNAL(PWM_INTERRUPT)
{
valeur d’uint8_t ;
uint16_t de sortie ;
syncPhaseAcc += syncPhaseInc ;
Si (syncPhaseAcc < syncPhaseInc) {}
Temps de commencer le prochain grain
grainPhaseAcc = 0 ;
grainAmp = 0x7fff ;
grain2PhaseAcc = 0 ;
grain2Amp = 0x7fff ;
LED_PORT ^ = 1 << LED_BIT ; Plus rapide que l’utilisation de digitalWrite
}
Incrémenter la phase des oscillateurs grain
grainPhaseAcc += grainPhaseInc ;
grain2PhaseAcc += grain2PhaseInc ;
Transformer une onde triangulaire de phase
valeur = (grainPhaseAcc >> 7) & 0xff ;
Si (grainPhaseAcc & 0 x 8000) valeur = ~ valeur ;
Multipliez par l’amplitude du courant grain pour obtenir l’échantillon
sortie = valeur * (grainAmp >> 8) ;
Répétez pour le second grain
valeur = (grain2PhaseAcc >> 7) & 0xff ;
Si (grain2PhaseAcc & 0 x 8000) valeur = ~ valeur ;
sortie valeur += * (grain2Amp >> 8) ;
Faire le grain amplitudes carie causée par un facteur de chaque échantillon (décroissance exponentielle)
grainAmp-= (grainAmp >> 8) * grainDecay ;
grain2Amp-= (grain2Amp >> 8) * grain2Decay ;
Échelle de sortie à la plage disponible, détourage si nécessaire
sortie >> = 9 ;
Si sortie (sortie > 255) = 255 ;
Sortie de PWM (c’est plus rapide que l’utilisation d’analogWrite)
PWM_VALUE = output ;
}