diff options
Diffstat (limited to 'libraries/Robot_Control/Squawk.h')
-rw-r--r-- | libraries/Robot_Control/Squawk.h | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/libraries/Robot_Control/Squawk.h b/libraries/Robot_Control/Squawk.h new file mode 100644 index 0000000..3481acf --- /dev/null +++ b/libraries/Robot_Control/Squawk.h @@ -0,0 +1,265 @@ +// Squawk Soft-Synthesizer Library for Arduino +// +// Davey Taylor 2013 +// d.taylor@arduino.cc + +#ifndef _SQUAWK_H_ +#define _SQUAWK_H_ +#include <stddef.h> +#include <inttypes.h> +#include "Arduino.h" + +#define Melody const uint8_t PROGMEM + +class SquawkStream { + public: + virtual ~SquawkStream() = 0; + virtual uint8_t read() = 0; + virtual void seek(size_t offset) = 0; +}; +inline SquawkStream::~SquawkStream() { } + +class SquawkSynth { + +protected: + // Load and play specified melody + void play(SquawkStream *melody); + +public: + SquawkSynth() {}; + + // Initialize Squawk to generate samples at sample_rate Hz + void begin(uint16_t sample_rate); + + // Load and play specified melody + // melody needs to point to PROGMEM data + void play(const uint8_t *melody); + + // Resume currently loaded melody (or enable direct osc manipulation by sketch) + void play(); + + // Pause playback + void pause(); + + // Stop playback (unloads song) + void stop(); + + // Tune Squawk to a different frequency - default is 1.0 + void tune(float tuning); + + // Change the tempo - default is 50 + void tempo(uint16_t tempo); +}; + +extern SquawkSynth Squawk; + +// oscillator structure +typedef struct { + uint8_t vol; + uint16_t freq; + uint16_t phase; +} osc_t; + +typedef osc_t Oscillator; + +// oscillator memory +extern osc_t osc[4]; +extern uint8_t pcm; +// channel 0 is pulse wave @ 25% duty +// channel 1 is square wave +// channel 2 is triangle wave +// channel 3 is noise + +// For channel 3, freq is used as part of its LFSR and should not be changed. +// LFSR: Linear feedback shift register, a method of producing a +// pseudo-random bit sequence, used to generate nasty noise. + +#ifdef __AVR_ATmega32U4__ +// Supported configurations for ATmega32U4 +#define SQUAWK_PWM_PIN5 OCR3AL +#define SQUAWK_PWM_PIN11 OCR0A +#define SQUAWK_PWM_PIN3 OCR0B +/* +// NOT SUPPORTED YET +#define SQUAWK_PWM_PIN6 OCR4D +#define SQUAWK_PWM_PIN9 OCR4B +#define SQUAWK_PWM_PIN10 OCR4B +*/ +#endif + +#ifdef __AVR_ATmega168__ +// Supported configurations for ATmega168 +#define SQUAWK_PWM_PIN6 OCR0A +#define SQUAWK_PWM_PIN5 OCR0B +#define SQUAWK_PWM_PIN11 OCR2A +#define SQUAWK_PWM_PIN3 OCR2B +#endif + +#ifdef __AVR_ATmega328P__ +// Supported configurations for ATmega328P +#define SQUAWK_PWM_PIN6 OCR0A +#define SQUAWK_PWM_PIN5 OCR0B +#define SQUAWK_PWM_PIN11 OCR2A +#define SQUAWK_PWM_PIN3 OCR2B +#endif + +/* +// NOT SUPPORTED YET +#define SQUAWK_SPI SPDR +#define SQUAWK_RLD_PORTB PORTB +#define SQUAWK_RLD_PORTC PORTC +*/ + +extern void squawk_playroutine() asm("squawk_playroutine"); + +// SAMPLE GRINDER +// generates samples and updates oscillators +// uses 132 cycles (not counting playroutine) +// ~1/3 CPU @ 44kHz on 16MHz +#define SQUAWK_CONSTRUCT_ISR(TARGET_REGISTER) \ +uint16_t cia, cia_count; \ +intptr_t squawk_register = (intptr_t)&TARGET_REGISTER; \ +ISR(TIMER1_COMPA_vect, ISR_NAKED) { \ + asm volatile( \ + "push r2 " "\n\t" \ + "in r2, __SREG__ " "\n\t" \ + "push r18 " "\n\t" \ + "push r27 " "\n\t" \ + "push r26 " "\n\t" \ + "push r0 " "\n\t" \ + "push r1 " "\n\t" \ +\ + "lds r18, osc+2*%[mul]+%[fre] " "\n\t" \ + "lds r0, osc+2*%[mul]+%[pha] " "\n\t" \ + "add r0, r18 " "\n\t" \ + "sts osc+2*%[mul]+%[pha], r0 " "\n\t" \ + "lds r18, osc+2*%[mul]+%[fre]+1" "\n\t" \ + "lds r1, osc+2*%[mul]+%[pha]+1" "\n\t" \ + "adc r1, r18 " "\n\t" \ + "sts osc+2*%[mul]+%[pha]+1, r1 " "\n\t" \ +\ + "mov r27, r1 " "\n\t" \ + "sbrc r27, 7 " "\n\t" \ + "com r27 " "\n\t" \ + "lsl r27 " "\n\t" \ + "lds r26, osc+2*%[mul]+%[vol] " "\n\t" \ + "subi r27, 128 " "\n\t" \ + "muls r27, r26 " "\n\t" \ + "lsl r1 " "\n\t" \ + "mov r26, r1 " "\n\t" \ +\ + "lds r18, osc+0*%[mul]+%[fre] " "\n\t" \ + "lds r0, osc+0*%[mul]+%[pha] " "\n\t" \ + "add r0, r18 " "\n\t" \ + "sts osc+0*%[mul]+%[pha], r0 " "\n\t" \ + "lds r18, osc+0*%[mul]+%[fre]+1" "\n\t" \ + "lds r1, osc+0*%[mul]+%[pha]+1" "\n\t" \ + "adc r1, r18 " "\n\t" \ + "sts osc+0*%[mul]+%[pha]+1, r1 " "\n\t" \ +\ + "mov r18, r1 " "\n\t" \ + "lsl r18 " "\n\t" \ + "and r18, r1 " "\n\t" \ + "lds r27, osc+0*%[mul]+%[vol] " "\n\t" \ + "sbrc r18, 7 " "\n\t" \ + "neg r27 " "\n\t" \ + "add r26, r27 " "\n\t" \ +\ + "lds r18, osc+1*%[mul]+%[fre] " "\n\t" \ + "lds r0, osc+1*%[mul]+%[pha] " "\n\t" \ + "add r0, r18 " "\n\t" \ + "sts osc+1*%[mul]+%[pha], r0 " "\n\t" \ + "lds r18, osc+1*%[mul]+%[fre]+1" "\n\t" \ + "lds r1, osc+1*%[mul]+%[pha]+1" "\n\t" \ + "adc r1, r18 " "\n\t" \ + "sts osc+1*%[mul]+%[pha]+1, r1 " "\n\t" \ +\ + "lds r27, osc+1*%[mul]+%[vol] " "\n\t" \ + "sbrc r1, 7 " "\n\t" \ + "neg r27 " "\n\t" \ + "add r26, r27 " "\n\t" \ +\ + "ldi r27, 1 " "\n\t" \ + "lds r0, osc+3*%[mul]+%[fre] " "\n\t" \ + "lds r1, osc+3*%[mul]+%[fre]+1" "\n\t" \ + "add r0, r0 " "\n\t" \ + "adc r1, r1 " "\n\t" \ + "sbrc r1, 7 " "\n\t" \ + "eor r0, r27 " "\n\t" \ + "sbrc r1, 6 " "\n\t" \ + "eor r0, r27 " "\n\t" \ + "sts osc+3*%[mul]+%[fre], r0 " "\n\t" \ + "sts osc+3*%[mul]+%[fre]+1, r1 " "\n\t" \ +\ + "lds r27, osc+3*%[mul]+%[vol] " "\n\t" \ + "sbrc r1, 7 " "\n\t" \ + "neg r27 " "\n\t" \ + "add r26, r27 " "\n\t" \ +\ + "lds r27, pcm " "\n\t" \ + "add r26, r27 " "\n\t" \ + "sts %[reg], r26 " "\n\t" \ +\ + "lds r27, cia_count+1 " "\n\t" \ + "lds r26, cia_count " "\n\t" \ + "sbiw r26, 1 " "\n\t" \ + "breq call_playroutine " "\n\t" \ + "sts cia_count+1, r27 " "\n\t" \ + "sts cia_count, r26 " "\n\t" \ + "pop r1 " "\n\t" \ + "pop r0 " "\n\t" \ + "pop r26 " "\n\t" \ + "pop r27 " "\n\t" \ + "pop r18 " "\n\t" \ + "out __SREG__, r2 " "\n\t" \ + "pop r2 " "\n\t" \ + "reti " "\n\t" \ + "call_playroutine: " "\n\t" \ +\ + "lds r27, cia+1 " "\n\t" \ + "lds r26, cia " "\n\t" \ + "sts cia_count+1, r27 " "\n\t" \ + "sts cia_count, r26 " "\n\t" \ +\ + "sei " "\n\t" \ + "push r19 " "\n\t" \ + "push r20 " "\n\t" \ + "push r21 " "\n\t" \ + "push r22 " "\n\t" \ + "push r23 " "\n\t" \ + "push r24 " "\n\t" \ + "push r25 " "\n\t" \ + "push r30 " "\n\t" \ + "push r31 " "\n\t" \ +\ + "clr r1 " "\n\t" \ + "call squawk_playroutine " "\n\t" \ +\ + "pop r31 " "\n\t" \ + "pop r30 " "\n\t" \ + "pop r25 " "\n\t" \ + "pop r24 " "\n\t" \ + "pop r23 " "\n\t" \ + "pop r22 " "\n\t" \ + "pop r21 " "\n\t" \ + "pop r20 " "\n\t" \ + "pop r19 " "\n\t" \ +\ + "pop r1 " "\n\t" \ + "pop r0 " "\n\t" \ + "pop r26 " "\n\t" \ + "pop r27 " "\n\t" \ + "pop r18 " "\n\t" \ + "out __SREG__, r2 " "\n\t" \ + "pop r2 " "\n\t" \ + "reti " "\n\t" \ + : \ + : [reg] "M" _SFR_MEM_ADDR(TARGET_REGISTER), \ + [mul] "M" (sizeof(Oscillator)), \ + [pha] "M" (offsetof(Oscillator, phase)), \ + [fre] "M" (offsetof(Oscillator, freq)), \ + [vol] "M" (offsetof(Oscillator, vol)) \ + ); \ +} + +#endif
\ No newline at end of file |