Simple synthesizer for STM32F401RE/STMstation.

Dependencies:   FastPWM mbed-dsp

This is a basic synthesizer to play music on the STM32F401RE Nucleo/STMstation development board:

/media/uploads/kkado/imgp1229.jpg

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.

Files at this revision

API Documentation at this revision

Comitter:
kkado
Date:
Mon Jul 03 08:35:31 2017 +0000
Parent:
0:c5ca205c0a80
Commit message:
Corrected documentation placement.

Changed in this revision

STMstation_synth.cpp Show annotated file Show diff for this revision Revisions of this file
STMstation_synth.h Show annotated file Show diff for this revision Revisions of this file
diff -r c5ca205c0a80 -r db0c24aebb8a STMstation_synth.cpp
--- a/STMstation_synth.cpp	Mon Jul 03 08:16:42 2017 +0000
+++ b/STMstation_synth.cpp	Mon Jul 03 08:35:31 2017 +0000
@@ -7,18 +7,29 @@
 const uint8_t   freqLength = sizeof(freqs)/sizeof(freqs[0]);
 const float     pi = 3.14159265359;
 
+//Sampling rate, uncomment one line only!
+//const uint16_t FSAMP = 44100; const float period = 0.000023;
+//const uint16_t FSAMP = 22050; const float period = 0.000045;
+const uint16_t FSAMP = 11025; const float period = 0.000091;
+
 //Constructor
-STMstation_synth::STMstation_synth():
-    //FSAMP(44100), period(0.000023),       //<<Only uncomment one of these lines!
-    //FSAMP(22050), period(0.000045),       //<<
-    FSAMP(11025), period(0.000091),         //<<
-    tone(AUDIO_PIN,1)
+STMstation_synth::STMstation_synth():tone(AUDIO_PIN,1)
 {     
-    tone.pulsewidth_ticks(1);
-    tone.period_ticks(256);
-    sample.attach(this,&STMstation_synth::note2,period);
+    begin();
 }
 
+//Constructor
+STMstation_synth::STMstation_synth(PinName audio_pin):tone(audio_pin,1)
+{     
+    begin();
+}
+
+//Set up PWM and timer interrupt
+void STMstation_synth::begin(){
+    tone.pulsewidth_ticks(128);
+    tone.period_ticks(256);
+    sample.attach(this,&STMstation_synth::note,period);
+}
 
 //Calculate the coefficients
 void STMstation_synth::calc_coefs(int i){  
@@ -46,7 +57,7 @@
 }
 
 //Calculate vSum
-void STMstation_synth::calc_vSum2(){
+void STMstation_synth::calc_vSum(){
     uint8_t active = 0; //Number of active channels
     uint16_t accum = 0; //Sum of volume channel values
     bool over = 0;      //Is any value over 127?
@@ -131,7 +142,7 @@
 }
 
 //Calculate values
-void STMstation_synth::calc_val2(){
+void STMstation_synth::calc_val(){
     Master.val = 128;
     for(int i=0; i<CHANNELS; i++){
         if(Master.notes[i] != NULL){
@@ -216,17 +227,17 @@
 void STMstation_synth::check_start(){
     for(int i=0; i<CHANNELS; i++){
         if(Master.counter[i] == 0){
-            calc_vSum2();
+            calc_vSum();
             calc_coefs(i);
         }
     }
 }
 
 //Play dat funky music
-void STMstation_synth::note2(){
+void STMstation_synth::note(){
     check_start();
     calc_env();
-    calc_val2();
+    calc_val();
     tone.pulsewidth_ticks(Master.val);
     check_end();
 }
@@ -275,7 +286,7 @@
             }            
         }
     }
-    calc_vSum2();
+    calc_vSum();
     for(uint16_t i=0; i<CHANNELS; i++){
         if(Master.notes[i]!=NULL){
             calc_coefs(i);
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;
 };