attempt at tracker style music

Dependencies:   PokittoLib

Revision:
14:97a5deea7c94
Parent:
13:8ce494870ba6
--- a/main.cpp	Sat Nov 17 16:33:51 2018 +0000
+++ b/main.cpp	Sun Nov 25 08:58:30 2018 +0000
@@ -6,106 +6,56 @@
 Pokitto::Core mygame;
 Pokitto::Display d;
 
-//------------------------[ Button handling, very accurate ]------------------------
-#define HELD 0
-#define NEW 1
-#define RELEASE 2
-byte CompletePad, ExPad, TempPad, myPad;
-bool _A[3], _B[3], _C[3], _Up[3], _Down[3], _Left[3], _Right[3];
-
-DigitalIn _aPin(P1_9);
-DigitalIn _bPin(P1_4);
-DigitalIn _cPin(P1_10);
-DigitalIn _upPin(P1_13);
-DigitalIn _downPin(P1_3);
-DigitalIn _leftPin(P1_25);
-DigitalIn _rightPin(P1_7);
-
-void UPDATEPAD(int pad, int var) {
-  _C[pad] = (var >> 1)&1;
-  _B[pad] = (var >> 2)&1;
-  _A[pad] = (var >> 3)&1;
-  _Down[pad] = (var >> 4)&1;
-  _Left[pad] = (var >> 5)&1;
-  _Right[pad] = (var >> 6)&1;
-  _Up[pad] = (var >> 7)&1;
-}
-
-void UpdatePad(int joy_code){
-  ExPad = CompletePad;
-  CompletePad = joy_code;
-  UPDATEPAD(HELD, CompletePad); // held
-  UPDATEPAD(RELEASE, (ExPad & (~CompletePad))); // released
-  UPDATEPAD(NEW, (CompletePad & (~ExPad))); // newpress
-}
-
-byte updateButtons(byte var){
-   var = 0;
-   if (_cPin) var |= (1<<1);
-   if (_bPin) var |= (1<<2);
-   if (_aPin) var |= (1<<3); // P1_9 = A
-   if (_downPin) var |= (1<<4);
-   if (_leftPin) var |= (1<<5);
-   if (_rightPin) var |= (1<<6);
-   if (_upPin) var |= (1<<7);
-
-   return var;
-}
-
-
 typedef struct{
-    bool playSample;
-    int soundPoint;
-    const uint8_t *currentSound;
-    int currentSoundSize;
-    int volume;
-    int speed;
-    int repeat;
+    bool playSample;                // should this sound be playing now?
+    int soundPoint;                 // current position of sound
+    const uint8_t *currentSound;    // currend sound array playing
+    uint32_t currentSoundSize;      // length of current sound
+    int volume;                     // volume of sound, best to be 63 or lower
+    int speed;                      // how fast to play sound, 256 = 100%
+    bool repeat;                    // 1 to repeat 0 not to
+    int repeat_start;               // start point of repeat, default should be 0
+    int repeat_end;                 // end point of repeate, default should be currentSoundSize
+    char lastSample;                // previous sample played
 } sampletype;
 
-sampletype snd[4]; // up to 4 sounds at once?
+sampletype snd[4];                  // up to 4 sounds at once?
 int oldQuart;
 
-uint32_t nextBufferIndexToFill = 0;
-uint32_t nextT = 0;
-
 int currentLine=0;
 int mytick=0;
- 
- 
-// note_speed << octave. = speed to play sample
-
-int note_speed[]={ 27,30,16,18,20,21,24,     29,0 ,17,19,0 ,23,25};
-//                 A  B  C  D  E  F  G       A# B# C# D# E# F# G#
-
+int pattern=0; 
 
-void emptyBuffer(){
-    for(int t=0; t<SBUFSIZE;){
-        soundbuf[++t]=0;
-    }
-
-    for(int t=0; t<4; t++){
-        snd[t].playSample=0;
-    }
+Ticker soundPlay;
+Ticker musicTimer;
 
-}
+const float note_speed[]={
+// C, C#, D, D#, E, F, F#, G, G#, A, A#, B,
+16.00, 16.95, 17.96, 19.03, 20.16, 21.36, 22.62, 23.97, 25.40, 26.91, 28.51, 30.21, 
+32.00, 33.90, 35.92, 38.05, 40.31, 42.71, 45.25, 47.95, 50.79, 53.82, 57.02, 60.41, 
+64.00, 67.81, 71.84, 76.11, 80.64, 85.43, 90.51, 95.89, 101.60, 107.63, 114.03, 120.81, 
+128.00, 135.61, 143.67, 152.21, 161.26, 170.85, 181.02, 191.78, 203.18, 215.27, 228.06, 241.63, 
+256.00, 271.22, 287.34, 304.43, 322.54, 341.71, 362.03, 383.56, 406.36, 430.53, 456.13, 483.25, 
+511.99, 542.44, 574.69, 608.86, 645.06, 683.43, 724.07, 767.12, 812.74, 861.06, 912.27, 966.51, 
+1023.98, 1084.87, 1149.38, 1217.73, 1290.14, 1366.85, 1448.13, 1534.24, 1625.47, 1722.13, 1824.53, 1933.02, 
+2047.96, 2169.74, 2298.77, 2435.46, 2580.27, 2733.71, 2896.26, 3068.48, 3250.94, 3444.25, 3649.06, 3866.05, 
+4095.93, 4339.49, 4597.52, 4870.91, 5160.55, 5467.41, 5792.52, 6136.96, 6501.89, 6888.51, 7298.12, 7732.08
+};
 
-uint8_t playSound(int channel, const unsigned char *sound, uint16_t soundSize, int volume = 255, int speed=255, int repeat=0){
-/*
-    int channel=0;
-    for(int t=0; t<4; t++){
-        if(snd[t].playSample==0){
-            channel=t;
-        }
-    }
-*/
-    snd[channel].currentSound = sound;
-    snd[channel].currentSoundSize = (soundSize*255)/speed;
-    snd[channel].soundPoint = 0;
-    snd[channel].playSample = 1;
-    snd[channel].volume = volume;
-    snd[channel].speed = speed;
-    snd[channel].repeat = repeat;
+uint8_t playSound(int channel, const unsigned char *sound, uint32_t soundSize, int volume = 255, int speed=255, int repeat=0){
+
+    // to resample current sample rate to 44100, cheap and probably wrong way
+    float rate1 = 44100 / (float)sampleRates[channel];
+    // speed = 256 / rate1; // playback speed is 
+    speed = speed / rate1; // playback speed is 
+
+    snd[channel].currentSound = sound;                      // sound to play
+    snd[channel].currentSoundSize = (soundSize<<8)/speed;   // length of sound array adjusted for speed change
+    snd[channel].volume = 63;                               // volume, best kept below 64 as louder will cause clipping when playing multiple samples
+    snd[channel].speed = speed;                             // recalculated above
+    snd[channel].repeat = repeat;                           // 1 to repead, 0 to not
+    snd[channel].soundPoint = 0;                            // where the current sound is upto
+    snd[channel].playSample = 1;                            // 1 to play this sound, 0 not to
 
     return channel;
 }
@@ -116,7 +66,9 @@
     int ss[4];
 
     for(int s=0; s<4; s++){
+        
         ss[s] = (snd[s].currentSound[(snd[s].soundPoint*snd[s].speed)>>8]*snd[s].volume>>8) * snd[s].playSample;
+
         ++snd[s].soundPoint;
         if(snd[s].soundPoint >= snd[s].currentSoundSize){
             if(snd[s].repeat){
@@ -128,66 +80,43 @@
         }
      }    
 
-
-//    temp = (ss[0] + ss[1] + ss[2] + ss[3]) - (ss[0] * ss[1] * ss[2] * ss[3]);
-    temp = ((127 - ss[0] + ss[1] + ss[2] + ss[3])/4)+127;
+    temp = (ss[0] + ss[1] + ss[2] + ss[3]) - ((ss[0] * ss[1] * ss[2] * ss[3])/256);
     
     return temp;
 }
 
-// Fills an audio buffer with the samples generated by the Bytebeat function
-void generateBuffer(uint32_t bufferIndex, uint32_t nextT) {
-    
-    //bufferIndex = (currentBuffer + 2)&3;
+
+void updateAudioBuffer(){
+    // when updating the audio buffer, I split the buffer into 4 and fill
+    // a part that isn't being played, so there are no sync issues
     
-    uint32_t index= 0;
-    for(uint32_t t=0; t<BUFFER_SIZE; t++,index++){
-        uint8_t sample = mixSound(t);
-        buffers[bufferIndex][index] = sample;
-    }
-
-}
-
-
-void updateSample(){
-
- int quart = soundbufindex / 512;
- int sndOffset[]={512,1024,1536,0};
-
+    int quart = soundbufindex / 512;
+    int sndOffset[]={1024,1536,0,512};
+    
+    // only update if the current playback pointer is nowhere near where we want to fill
     if(oldQuart != quart){
         oldQuart = quart;
-        for(int t=0; t<SBUFSIZE/4;){
+        for(int t=0; t<=SBUFSIZE/4;){
             uint8_t sample = mixSound(t);
             soundbuf[t+sndOffset[quart]] = sample;
-
-            for(int s=0; s<4; s++){
-                ++snd[s].soundPoint;
-                if(snd[s].soundPoint >= snd[s].currentSoundSize){
-                    if(snd[s].repeat){
-                        snd[s].soundPoint=0;
-                    }else{
-                        snd[s].playSample=0;
-                    }
-                }
-            }
             t++;
         }
     }
-
 }
 
 void update_tune(){
 
+    char pat = my_pattern[pattern];
+
     for(int t=0; t<4; t++){
-        char note =       tune[pattern][currentLine][t][0];
-        char octave =     tune[pattern][currentLine][t][1];
-        char instrument = tune[pattern][currentLine][t][2];
-        char volume =     tune[pattern][currentLine][t][3] * 4;
+        int note =       tune[pat][currentLine][t][0];
+        int octave =     tune[pat][currentLine][t][1]; // no longer used
+        int volume =     tune[pat][currentLine][t][2];// max volume from xm/mod was 64
+        int instrument = tune[pat][currentLine][t][3];
                     
         if(note > 0){
-            
-            int speed = (note_speed[note-1] << octave); // >> 1
-                        
+            int speed = note_speed[(note-1)+12*octave];
+
             switch(instrument){
                 case 1:
                     playSound(t, s_01, sizeof(s_01), volume, speed, sampleRepeat[0]);
@@ -202,75 +131,43 @@
                     playSound(t, s_04, sizeof(s_04), volume, speed, sampleRepeat[3]);
                 break;
             }
+                        
         }
-                            
-        snd[t].volume = volume;
-                
+        if(volume >= 128){
+            snd[t].volume = volume-128;
+        }
     }
  
-    if(currentLine++==63){
+    if(currentLine++==patternLength){
         currentLine=0;
-        pattern++;
+        if(pattern++==sizeof(my_pattern))pattern=loopTo;
     }
 }
 
 
+
+
 int main ()
 {
     mygame.begin();
     mygame.setFrameRate(255);
-//    emptyBuffer(); // clear the sound buffer
-
-    // The audio engine uses 4 buffers. Generate all 4 buffers ahead.
-    uint32_t nextT = 0;
-    generateBuffer(0, nextT); nextT += BUFFER_SIZE;
-    generateBuffer(1, nextT); nextT += BUFFER_SIZE;
-    generateBuffer(2, nextT); nextT += BUFFER_SIZE;
-    generateBuffer(3, nextT); nextT += BUFFER_SIZE;
-
-    // Set global audio variables
-    currentBuffer = 0;
-    currentPtr = buffers[currentBuffer];
-    endPtr = currentPtr + BUFFER_SIZE;
 
     // Init audio stream.
     pokPlayStream(); // activate stream
     mygame.sound.ampEnable(true);
     mygame.sound.playMusicStream();
-    
+
+    // check and update the sound buffer as often as we can
+    soundPlay.attach(&updateAudioBuffer, 0.0001);
+    musicTimer.attach(&update_tune, 0.055);
     
-    uint32_t nextBufferIndexToFill = 0;
+    d.color = 1;
 
     while (mygame.isRunning())
     {
-//        updateSample();
-
-            // Fill the next buffer if it is not used currently 
-        if((uint32_t)currentBuffer != nextBufferIndexToFill) {
-            // Generate buffer
-            generateBuffer(nextBufferIndexToFill, nextT);
-
-            if(++nextBufferIndexToFill > 3)
-                nextBufferIndexToFill = 0;
-            nextT += BUFFER_SIZE;
-        }
-
-        if(++mytick==2){
-            mytick=0;
-            
-            update_tune();            
-        }        
-
         if (mygame.update())
         {
-            // update buttons
-            myPad = updateButtons(myPad);
-            UpdatePad(myPad);
-                        
-            d.color = 1;
-            d.printf("Tick %d", mytick);
-            d.printf("Line %d", currentLine);
-
+            
         }
     }
 }