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.
STMstation_synth.h
- Committer:
- kkado
- Date:
- 2017-07-03
- Revision:
- 1:db0c24aebb8a
- Parent:
- 0:c5ca205c0a80
File content as of revision 1:db0c24aebb8a:
#ifndef STMstation_synth_h #define STMstation_synth_h #include "mbed.h" #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. * * This is a multi-channel synthesizer, with sine, square, triangle, and noise waveform generation. Music is * stored as arrays in flash, but it is possible to use editable arrays in RAM. Standard number of channels is * 5, but additional channels can be added by changing the CHANNELS define. * * Audio signal is output as a PWM signal on PB_0, which MUST be fed into a 1-bit DAC to generate sound! * * Suggested setup: * @code * (PB_0)-----(R1)-----(C2) * | | * (C1) (SPEAKER) * | | * (GND) (GND) * * R1 = 150 Ohms, C1 = 47nF, C2 = 1uF, Speaker = 0.25W, 8 Ohms * @endcode */ 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_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_val(); void check_end(); void check_start(); void note(); Ticker sample; FastPWM tone; }; #endif