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@1:db0c24aebb8a, 2017-07-03 (annotated)
- Committer:
- kkado
- Date:
- Mon Jul 03 08:35:31 2017 +0000
- Revision:
- 1:db0c24aebb8a
- Parent:
- 0:c5ca205c0a80
Corrected documentation placement.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kkado | 0:c5ca205c0a80 | 1 | #ifndef STMstation_synth_h |
kkado | 0:c5ca205c0a80 | 2 | #define STMstation_synth_h |
kkado | 0:c5ca205c0a80 | 3 | |
kkado | 0:c5ca205c0a80 | 4 | #include "mbed.h" |
kkado | 0:c5ca205c0a80 | 5 | #include "arm_math.h" |
kkado | 0:c5ca205c0a80 | 6 | #include "FastPWM.h" |
kkado | 0:c5ca205c0a80 | 7 | |
kkado | 1:db0c24aebb8a | 8 | #define AUDIO_PIN PB_0 |
kkado | 1:db0c24aebb8a | 9 | #define CHANNELS 5 |
kkado | 1:db0c24aebb8a | 10 | |
kkado | 1:db0c24aebb8a | 11 | /** Stores data for a song or sound effect |
kkado | 1:db0c24aebb8a | 12 | * @param notes Note frequency and timbre |
kkado | 1:db0c24aebb8a | 13 | * @param durations Duration (from 1/64th to 4 counts) |
kkado | 1:db0c24aebb8a | 14 | * @param AR Attack/Release (bits 7:4 - attack, 3:0 - release) |
kkado | 1:db0c24aebb8a | 15 | * @param vol Volume (0 - muted, 127 - 1x volume, 255 - 2x volume |
kkado | 1:db0c24aebb8a | 16 | * @param max Max index of each channel |
kkado | 1:db0c24aebb8a | 17 | * @param ended Has the channel completed playing? |
kkado | 1:db0c24aebb8a | 18 | * @param repeat Should the channel repeat or stop? |
kkado | 1:db0c24aebb8a | 19 | * @param bpm Tempo, in 1/4th counts per minute |
kkado | 1:db0c24aebb8a | 20 | */ |
kkado | 1:db0c24aebb8a | 21 | struct melody{ |
kkado | 1:db0c24aebb8a | 22 | const uint8_t * notes[CHANNELS]; |
kkado | 1:db0c24aebb8a | 23 | const uint8_t * durations[CHANNELS]; |
kkado | 1:db0c24aebb8a | 24 | const uint8_t * AR[CHANNELS]; |
kkado | 1:db0c24aebb8a | 25 | const uint8_t * vol[CHANNELS]; |
kkado | 1:db0c24aebb8a | 26 | uint16_t max[CHANNELS]; |
kkado | 1:db0c24aebb8a | 27 | bool ended[CHANNELS], repeat[CHANNELS]; |
kkado | 1:db0c24aebb8a | 28 | uint8_t bpm; |
kkado | 1:db0c24aebb8a | 29 | }; |
kkado | 1:db0c24aebb8a | 30 | |
kkado | 1:db0c24aebb8a | 31 | /** Stores data that is currently being played. So many members! A lot of these are just coefficients for waveform synthesis. |
kkado | 1:db0c24aebb8a | 32 | * @param notes (LOADED FROM MELODY) Note frequency and timbre |
kkado | 1:db0c24aebb8a | 33 | * @param durations (LOADED FROM MELODY) Duration (from 1/64th to 4 counts) |
kkado | 1:db0c24aebb8a | 34 | * @param AR (LOADED FROM MELODY) Attack/Release (bits 7:4 - attack, 3:0 - release) |
kkado | 1:db0c24aebb8a | 35 | * @param vol (LOADED FROM MELODY) Volume (0 - muted, 127 - 1x volume, 255 - 2x volume |
kkado | 1:db0c24aebb8a | 36 | * @param index Note currently being played |
kkado | 1:db0c24aebb8a | 37 | * @param max (LOADED FROM MELODY) Max index of each channel |
kkado | 1:db0c24aebb8a | 38 | * @param env (FOR SYNTHEESIS) Envelope value (between 0~1) |
kkado | 1:db0c24aebb8a | 39 | * @param sineCoef (FOR SYNTHEESIS) Coefficient for sine wave synthesis |
kkado | 1:db0c24aebb8a | 40 | * @param vSum (FOR SYNTHEESIS) Divider to prevent clipping |
kkado | 1:db0c24aebb8a | 41 | * @param atkSlope (FOR SYNTHEESIS) Attack slope for envelope |
kkado | 1:db0c24aebb8a | 42 | * @param relSlope (FOR SYNTHEESIS) Release slope for envelope |
kkado | 1:db0c24aebb8a | 43 | * @param relOffset (FOR SYNTHEESIS) Release offset for envelope |
kkado | 1:db0c24aebb8a | 44 | * @param volCoef (FOR SYNTHEESIS) Volume coefficient to control volume, prevent clipping |
kkado | 1:db0c24aebb8a | 45 | * @param halfPeriod (FOR SYNTHEESIS) Half period for square, triangle functions |
kkado | 1:db0c24aebb8a | 46 | * @param triSlope (FOR SYNTHEESIS) Triangle wave slope |
kkado | 1:db0c24aebb8a | 47 | * @param noiseVal (FOR SYNTHEESIS) Value returned from random noise generation |
kkado | 1:db0c24aebb8a | 48 | * @param triVal (FOR SYNTHEESIS) Value returned from triangle wave calculation |
kkado | 1:db0c24aebb8a | 49 | * @param counter Current sample value |
kkado | 1:db0c24aebb8a | 50 | * @param envAtkEnd (FOR SYNTHEESIS) Counter value at which attack ramp ends |
kkado | 1:db0c24aebb8a | 51 | * @param envRelStart (FOR SYNTHEESIS) Counter value at which release ramp starts |
kkado | 1:db0c24aebb8a | 52 | * @param val 8-bit sample value |
kkado | 1:db0c24aebb8a | 53 | * @timbre (FOR SYNTHEESIS) What kind of waveform is playing? 0 - sine, 1 - sq, 2 - tri, 3 - noise |
kkado | 1:db0c24aebb8a | 54 | * @freqIndex (FOR SYNTHEESIS) What frequency is playing? 0 - rest, 1~freqLength frequencies in ascending order |
kkado | 1:db0c24aebb8a | 55 | * @param bpm (LOADED FROM MELODY) Tempo, in 1/4th counts per minute |
kkado | 1:db0c24aebb8a | 56 | * @param repeat (LOADED FROM MELODY) Channel repeat |
kkado | 1:db0c24aebb8a | 57 | * @param endptr (LOADED FROM MELODY) Points to melody end value |
kkado | 1:db0c24aebb8a | 58 | */ |
kkado | 1:db0c24aebb8a | 59 | struct master{ |
kkado | 1:db0c24aebb8a | 60 | const uint8_t * notes[CHANNELS]; |
kkado | 1:db0c24aebb8a | 61 | const uint8_t * durations[CHANNELS]; |
kkado | 1:db0c24aebb8a | 62 | const uint8_t * AR[CHANNELS]; |
kkado | 1:db0c24aebb8a | 63 | const uint8_t * vol[CHANNELS]; |
kkado | 1:db0c24aebb8a | 64 | uint16_t index[CHANNELS], max[CHANNELS]; |
kkado | 1:db0c24aebb8a | 65 | float env[CHANNELS], sineCoef[CHANNELS], vSum, atkSlope[CHANNELS], relSlope[CHANNELS], relOffset[CHANNELS], volCoef[CHANNELS], halfPeriod[CHANNELS], triSlope[CHANNELS], noiseVal[CHANNELS], triVal[CHANNELS]; |
kkado | 1:db0c24aebb8a | 66 | uint32_t counter[CHANNELS], envAtkEnd[CHANNELS], envRelStart[CHANNELS]; |
kkado | 1:db0c24aebb8a | 67 | uint8_t val, timbre[CHANNELS], freqIndex[CHANNELS], bpm[CHANNELS]; |
kkado | 1:db0c24aebb8a | 68 | bool repeat[CHANNELS]; |
kkado | 1:db0c24aebb8a | 69 | bool* endptr[CHANNELS]; |
kkado | 1:db0c24aebb8a | 70 | }; |
kkado | 1:db0c24aebb8a | 71 | |
kkado | 0:c5ca205c0a80 | 72 | /** Basic synthesizer library for STM32F401RE Nucleo or STMstation P.1 development boards - may work with |
kkado | 0:c5ca205c0a80 | 73 | * other targets, but not tested yet. |
kkado | 0:c5ca205c0a80 | 74 | * |
kkado | 0:c5ca205c0a80 | 75 | * This is a multi-channel synthesizer, with sine, square, triangle, and noise waveform generation. Music is |
kkado | 0:c5ca205c0a80 | 76 | * stored as arrays in flash, but it is possible to use editable arrays in RAM. Standard number of channels is |
kkado | 0:c5ca205c0a80 | 77 | * 5, but additional channels can be added by changing the CHANNELS define. |
kkado | 0:c5ca205c0a80 | 78 | * |
kkado | 0:c5ca205c0a80 | 79 | * Audio signal is output as a PWM signal on PB_0, which MUST be fed into a 1-bit DAC to generate sound! |
kkado | 0:c5ca205c0a80 | 80 | * |
kkado | 0:c5ca205c0a80 | 81 | * Suggested setup: |
kkado | 0:c5ca205c0a80 | 82 | * @code |
kkado | 0:c5ca205c0a80 | 83 | * (PB_0)-----(R1)-----(C2) |
kkado | 0:c5ca205c0a80 | 84 | * | | |
kkado | 0:c5ca205c0a80 | 85 | * (C1) (SPEAKER) |
kkado | 0:c5ca205c0a80 | 86 | * | | |
kkado | 0:c5ca205c0a80 | 87 | * (GND) (GND) |
kkado | 0:c5ca205c0a80 | 88 | * |
kkado | 0:c5ca205c0a80 | 89 | * R1 = 150 Ohms, C1 = 47nF, C2 = 1uF, Speaker = 0.25W, 8 Ohms |
kkado | 0:c5ca205c0a80 | 90 | * @endcode |
kkado | 0:c5ca205c0a80 | 91 | */ |
kkado | 0:c5ca205c0a80 | 92 | class STMstation_synth{ |
kkado | 0:c5ca205c0a80 | 93 | public: |
kkado | 1:db0c24aebb8a | 94 | /** Create an instance of STMstation_synth |
kkado | 1:db0c24aebb8a | 95 | * @param audio_pin PWM output |
kkado | 1:db0c24aebb8a | 96 | */ |
kkado | 1:db0c24aebb8a | 97 | STMstation_synth(PinName audio_pin); |
kkado | 1:db0c24aebb8a | 98 | /** Create an instance of STMstation_synth |
kkado | 1:db0c24aebb8a | 99 | * Use default output for STMstation P.1, PB_0 |
kkado | 1:db0c24aebb8a | 100 | */ |
kkado | 0:c5ca205c0a80 | 101 | STMstation_synth(); |
kkado | 1:db0c24aebb8a | 102 | /** Play a track |
kkado | 1:db0c24aebb8a | 103 | * @param newMelody Melody to play |
kkado | 1:db0c24aebb8a | 104 | * @param refChannel If starting from nonzero index, specify reference channel |
kkado | 1:db0c24aebb8a | 105 | * @param newIndex Start index |
kkado | 1:db0c24aebb8a | 106 | */ |
kkado | 1:db0c24aebb8a | 107 | void play(melody &newMelody, uint8_t refChannel = 0, uint16_t newIndex = 0); |
kkado | 1:db0c24aebb8a | 108 | /** Clear all data from a selected channel |
kkado | 1:db0c24aebb8a | 109 | * @param channel Channel to clear |
kkado | 1:db0c24aebb8a | 110 | */ |
kkado | 1:db0c24aebb8a | 111 | void clear_channel(uint8_t _channel); |
kkado | 1:db0c24aebb8a | 112 | /** Stop playing a track |
kkado | 1:db0c24aebb8a | 113 | * @param newMelody Melody to stop |
kkado | 1:db0c24aebb8a | 114 | */ |
kkado | 1:db0c24aebb8a | 115 | void stop_track(melody &newMelody); |
kkado | 1:db0c24aebb8a | 116 | /** Check if a track is still playing |
kkado | 1:db0c24aebb8a | 117 | * @param newMelody Melody to check |
kkado | 1:db0c24aebb8a | 118 | */ |
kkado | 1:db0c24aebb8a | 119 | bool check_track(melody &newMelody); |
kkado | 1:db0c24aebb8a | 120 | |
kkado | 1:db0c24aebb8a | 121 | struct master Master; |
kkado | 1:db0c24aebb8a | 122 | private: |
kkado | 1:db0c24aebb8a | 123 | void begin(); |
kkado | 0:c5ca205c0a80 | 124 | void calc_coefs(int i); |
kkado | 1:db0c24aebb8a | 125 | void calc_vSum(); |
kkado | 0:c5ca205c0a80 | 126 | void calc_env(); |
kkado | 0:c5ca205c0a80 | 127 | int8_t square(float _halfperiod, uint16_t _counter); |
kkado | 0:c5ca205c0a80 | 128 | void calc_triangle(uint8_t _channel, float _halfperiod, float _trislope, uint32_t _counter); |
kkado | 0:c5ca205c0a80 | 129 | void calc_noise(uint8_t _channel, uint8_t _freq, uint32_t _counter); |
kkado | 1:db0c24aebb8a | 130 | void calc_val(); |
kkado | 0:c5ca205c0a80 | 131 | void check_end(); |
kkado | 0:c5ca205c0a80 | 132 | void check_start(); |
kkado | 1:db0c24aebb8a | 133 | void note(); |
kkado | 0:c5ca205c0a80 | 134 | |
kkado | 0:c5ca205c0a80 | 135 | Ticker sample; |
kkado | 0:c5ca205c0a80 | 136 | FastPWM tone; |
kkado | 0:c5ca205c0a80 | 137 | }; |
kkado | 0:c5ca205c0a80 | 138 | |
kkado | 0:c5ca205c0a80 | 139 | #endif |