Simple synthesizer for STM32F401RE/STMstation.
Dependencies: FastPWM mbed-dsp
This is a basic synthesizer to play music on the STM32F401RE Nucleo/STMstation development board:
Please see the API documentation for further details.
Here's a demo of the synthesizer at work in a music composing program on the STMstation. This one is "Miku" by Anamanaguchi.
Diff: STMstation_synth.h
- Revision:
- 1:db0c24aebb8a
- Parent:
- 0:c5ca205c0a80
diff -r c5ca205c0a80 -r db0c24aebb8a STMstation_synth.h --- a/STMstation_synth.h Mon Jul 03 08:16:42 2017 +0000 +++ b/STMstation_synth.h Mon Jul 03 08:35:31 2017 +0000 @@ -5,6 +5,70 @@ #include "arm_math.h" #include "FastPWM.h" +#define AUDIO_PIN PB_0 +#define CHANNELS 5 + +/** Stores data for a song or sound effect + * @param notes Note frequency and timbre + * @param durations Duration (from 1/64th to 4 counts) + * @param AR Attack/Release (bits 7:4 - attack, 3:0 - release) + * @param vol Volume (0 - muted, 127 - 1x volume, 255 - 2x volume + * @param max Max index of each channel + * @param ended Has the channel completed playing? + * @param repeat Should the channel repeat or stop? + * @param bpm Tempo, in 1/4th counts per minute + */ +struct melody{ + const uint8_t * notes[CHANNELS]; + const uint8_t * durations[CHANNELS]; + const uint8_t * AR[CHANNELS]; + const uint8_t * vol[CHANNELS]; + uint16_t max[CHANNELS]; + bool ended[CHANNELS], repeat[CHANNELS]; + uint8_t bpm; +}; + +/** Stores data that is currently being played. So many members! A lot of these are just coefficients for waveform synthesis. + * @param notes (LOADED FROM MELODY) Note frequency and timbre + * @param durations (LOADED FROM MELODY) Duration (from 1/64th to 4 counts) + * @param AR (LOADED FROM MELODY) Attack/Release (bits 7:4 - attack, 3:0 - release) + * @param vol (LOADED FROM MELODY) Volume (0 - muted, 127 - 1x volume, 255 - 2x volume + * @param index Note currently being played + * @param max (LOADED FROM MELODY) Max index of each channel + * @param env (FOR SYNTHEESIS) Envelope value (between 0~1) + * @param sineCoef (FOR SYNTHEESIS) Coefficient for sine wave synthesis + * @param vSum (FOR SYNTHEESIS) Divider to prevent clipping + * @param atkSlope (FOR SYNTHEESIS) Attack slope for envelope + * @param relSlope (FOR SYNTHEESIS) Release slope for envelope + * @param relOffset (FOR SYNTHEESIS) Release offset for envelope + * @param volCoef (FOR SYNTHEESIS) Volume coefficient to control volume, prevent clipping + * @param halfPeriod (FOR SYNTHEESIS) Half period for square, triangle functions + * @param triSlope (FOR SYNTHEESIS) Triangle wave slope + * @param noiseVal (FOR SYNTHEESIS) Value returned from random noise generation + * @param triVal (FOR SYNTHEESIS) Value returned from triangle wave calculation + * @param counter Current sample value + * @param envAtkEnd (FOR SYNTHEESIS) Counter value at which attack ramp ends + * @param envRelStart (FOR SYNTHEESIS) Counter value at which release ramp starts + * @param val 8-bit sample value + * @timbre (FOR SYNTHEESIS) What kind of waveform is playing? 0 - sine, 1 - sq, 2 - tri, 3 - noise + * @freqIndex (FOR SYNTHEESIS) What frequency is playing? 0 - rest, 1~freqLength frequencies in ascending order + * @param bpm (LOADED FROM MELODY) Tempo, in 1/4th counts per minute + * @param repeat (LOADED FROM MELODY) Channel repeat + * @param endptr (LOADED FROM MELODY) Points to melody end value + */ +struct master{ + const uint8_t * notes[CHANNELS]; + const uint8_t * durations[CHANNELS]; + const uint8_t * AR[CHANNELS]; + const uint8_t * vol[CHANNELS]; + uint16_t index[CHANNELS], max[CHANNELS]; + float env[CHANNELS], sineCoef[CHANNELS], vSum, atkSlope[CHANNELS], relSlope[CHANNELS], relOffset[CHANNELS], volCoef[CHANNELS], halfPeriod[CHANNELS], triSlope[CHANNELS], noiseVal[CHANNELS], triVal[CHANNELS]; + uint32_t counter[CHANNELS], envAtkEnd[CHANNELS], envRelStart[CHANNELS]; + uint8_t val, timbre[CHANNELS], freqIndex[CHANNELS], bpm[CHANNELS]; + bool repeat[CHANNELS]; + bool* endptr[CHANNELS]; +}; + /** Basic synthesizer library for STM32F401RE Nucleo or STMstation P.1 development boards - may work with * other targets, but not tested yet. * @@ -25,58 +89,49 @@ * R1 = 150 Ohms, C1 = 47nF, C2 = 1uF, Speaker = 0.25W, 8 Ohms * @endcode */ - -#define AUDIO_PIN PB_0 -#define CHANNELS 5 - -//Audio melody struct -struct melody{ - const uint8_t * notes[CHANNELS]; - const uint8_t * durations[CHANNELS]; - const uint8_t * AR[CHANNELS]; - const uint8_t * vol[CHANNELS]; - uint16_t max[CHANNELS]; - bool ended[CHANNELS], repeat[CHANNELS]; - uint8_t bpm; -}; - -//Audio master struct -struct master{ - const uint8_t * notes[CHANNELS]; - const uint8_t * durations[CHANNELS]; - const uint8_t * AR[CHANNELS]; - const uint8_t * vol[CHANNELS]; - uint16_t index[CHANNELS], max[CHANNELS]; - float env[CHANNELS], sineCoef[CHANNELS], vSum, atkSlope[CHANNELS], relSlope[CHANNELS], relOffset[CHANNELS], volCoef[CHANNELS], halfPeriod[CHANNELS], triSlope[CHANNELS], noiseVal[CHANNELS], triVal[CHANNELS]; - uint32_t counter[CHANNELS], envAtkEnd[CHANNELS], envRelStart[CHANNELS]; - uint8_t val, timbre[CHANNELS], freqIndex[CHANNELS], bpm[CHANNELS]; - bool repeat[CHANNELS]; - bool* endptr[CHANNELS]; -}; - class STMstation_synth{ public: + /** Create an instance of STMstation_synth + * @param audio_pin PWM output + */ + STMstation_synth(PinName audio_pin); + /** Create an instance of STMstation_synth + * Use default output for STMstation P.1, PB_0 + */ STMstation_synth(); - + /** Play a track + * @param newMelody Melody to play + * @param refChannel If starting from nonzero index, specify reference channel + * @param newIndex Start index + */ + void play(melody &newMelody, uint8_t refChannel = 0, uint16_t newIndex = 0); + /** Clear all data from a selected channel + * @param channel Channel to clear + */ + void clear_channel(uint8_t _channel); + /** Stop playing a track + * @param newMelody Melody to stop + */ + void stop_track(melody &newMelody); + /** Check if a track is still playing + * @param newMelody Melody to check + */ + bool check_track(melody &newMelody); + + struct master Master; + private: + void begin(); void calc_coefs(int i); - void calc_vSum2(); + void calc_vSum(); void calc_env(); int8_t square(float _halfperiod, uint16_t _counter); void calc_triangle(uint8_t _channel, float _halfperiod, float _trislope, uint32_t _counter); void calc_noise(uint8_t _channel, uint8_t _freq, uint32_t _counter); - void calc_val2(); - void clear_channel(uint8_t _channel); - void stop_track(melody &newMelody); - bool check_track(melody &newMelody); + void calc_val(); void check_end(); void check_start(); - void note2(); - void play(melody &newMelody, uint8_t refChannel = 0, uint16_t newIndex = 0); + void note(); - const uint16_t FSAMP; - const float period; - struct master Master; - private: Ticker sample; FastPWM tone; };