attempt at tracker style music

Dependencies:   PokittoLib

Revision:
15:209481812170
Parent:
13:8ce494870ba6
--- a/main.cpp	Sat Nov 17 16:33:51 2018 +0000
+++ b/main.cpp	Thu Feb 07 11:02:56 2019 +0000
@@ -2,62 +2,17 @@
 #include "HWSound.h"
 #include "snd.h"
 #include "tune.h"
+#include "gfx.h"
 
 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;
+    uint32_t currentSoundSize;
     int volume;
     int speed;
     int repeat;
@@ -68,57 +23,78 @@
 
 uint32_t nextBufferIndexToFill = 0;
 uint32_t nextT = 0;
+uint32_t oldBufIndex=0;
 
 int currentLine=0;
 int mytick=0;
- 
+int pattern=0; 
+
+uint32_t myDelay;
+uint32_t tempTime;
+uint32_t sndTime;
+
  
-// note_speed << octave. = speed to play sample
+Ticker sounder;
+Ticker sounder1;
+
+bool playMusic = 1;
+
+const char *noteNames[] = {"--","C ","C#","D ","D#","E ","F ","F#","G ","G#","A ","A#","B "};
 
-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#
-
+const int note_speed[]={
+16,17,18,19,20,21,23,24,25,27,29,30, // C, C#, D, D#, E, F, F#, G, G#, A, A#, B,
+32,34,36,38,40,43,45,48,51,54,57,60,
+64,68,72,76,81,85,91,96,102,108,114,121,
+128,136,144,152,161,171,181,192,203,215,228,242,
+256,271,287,304,323,342,362,384,406,431,456,483,
+512,542,575,609,645,683,724,767,813,861,912,967,
+1024,1085,1149,1218,1290,1367,1448,1534,1625,1722,1825,1933,
+2048,2170,2299,2435,2580,2734,2896,3068,3251,3444,3649,3866,
+4096,4339,4598,4871,5161,5467,5793,6137,6502,6889,7298,7732,};
 
-void emptyBuffer(){
-    for(int t=0; t<SBUFSIZE;){
-        soundbuf[++t]=0;
+// new playsound function
+uint8_t playSound(int channel, const unsigned char *sound, int volume = 255, int speed=255, int repeat=0){
+
+    // get sound length
+    int soundSize = 0;
+    for(int t=0; t<4; t++){
+        soundSize <<= 8;
+        soundSize |= sound[t] & 0xFF;
     }
 
-    for(int t=0; t<4; t++){
-        snd[t].playSample=0;
+    int sampleRate = 0;
+    for(int t=0; t<2; t++){
+        sampleRate <<= 8;
+        sampleRate |= sound[t+4] & 0xFF;
     }
 
+    float spd = (POK_AUD_FREQ / (float)sampleRate);
+
+    snd[channel].currentSound = sound;          // sound to play
+    snd[channel].volume = volume;               // volume
+    snd[channel].speed = (speed/spd);           // recalculated above
+    snd[channel].currentSoundSize = soundSize;  // length of sound array adjusted for speed change
+    snd[channel].soundPoint = 0;                // where the current sound is upto
+    snd[channel].repeat = repeat;               // repeat point
+    snd[channel].playSample = 1;                // trigger sample playing
+
+    return channel;
+
 }
 
-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;
-
-    return channel;
-}
 
 uint8_t mixSound(int samplePos)
 {
     int temp = 0;
-    int ss[4];
-
+    signed 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){
+        int currentPos = (snd[s].soundPoint*snd[s].speed)>>8;
+        ss[s] = snd[s].currentSound[currentPos] -127;
+        ss[s] *= snd[s].volume;
+        ss[s] /= 256;
+        ss[s] *= snd[s].playSample; // will be 1 or 0, if not playing, will silence
+        snd[s].soundPoint++;
+        if( currentPos >= snd[s].currentSoundSize){
             if(snd[s].repeat){
                 snd[s].soundPoint=0;
             }else{
@@ -126,91 +102,108 @@
                 snd[s].soundPoint=0;
             }
         }
-     }    
-
-
-//    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;
-    
-    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;
-    
-    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};
-
-    if(oldQuart != quart){
-        oldQuart = quart;
-        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++;
-        }
-    }
-
+     }
+    temp = (ss[0] + ss[1] + ss[2] + ss[3])/4;
+    return temp +127;
 }
 
 void update_tune(){
 
-    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;
-                    
-        if(note > 0){
-            
-            int speed = (note_speed[note-1] << octave); // >> 1
+    if(playMusic==1){
+
+        char pat = my_pattern[pattern];
+    
+        int special = 0;
+        for(int t=0; t<4; t++){
+            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];
+            special =    tune[pat][currentLine][t][4];
+
+            if(special == 22){
+                // 22 = F in MOD format. 0.02 = 1 'tick'
+                sounder.detach();
+                sounder.attach(&update_tune, 0.02 * tune[pat][currentLine][t][5]); // speed of song
+            }
+
+
+        // if valid volume change, change it, if not use previous
+        if(volume >=128){
+            volume -=128;
+            volume *= 4;
+        }else{
+            // don't change volume
+            volume = snd[t].volume;
+        }
+
                         
-            switch(instrument){
-                case 1:
-                    playSound(t, s_01, sizeof(s_01), volume, speed, sampleRepeat[0]);
-                break;
-                case 2:
-                    playSound(t, s_02, sizeof(s_02), volume, speed, sampleRepeat[1]);
-                break;
-                case 3:
-                    playSound(t, s_03, sizeof(s_03), volume, speed, sampleRepeat[2]);
-                break;
-                case 4:
-                    playSound(t, s_04, sizeof(s_04), volume, speed, sampleRepeat[3]);
-                break;
+            if(note > 0){
+                
+                //int speed = (note_speed[note-1] << octave) /2;
+                int speed = note_speed[note-1];
+                for(int s=1; s<octave; s++){
+                    speed *=2;
+                }
+                            
+                switch(instrument){
+                    case 1: playSound(t, s_01, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 2: playSound(t, s_02, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 3: playSound(t, s_03, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 4: playSound(t, s_04, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 5: playSound(t, s_05, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 6: playSound(t, s_06, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 7: playSound(t, s_07, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 8: playSound(t, s_08, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 9: playSound(t, s_09, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 10: playSound(t, s_10, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 11: playSound(t, s_11, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 12: playSound(t, s_12, volume, speed, sampleRepeat[instrument-1]);  break;
+                    case 13: playSound(t, s_13, volume, speed, sampleRepeat[instrument-1]);  break;
+                }
             }
+                                
+            snd[t].volume = volume;
+                    
         }
-                            
-        snd[t].volume = volume;
-                
+     
+        // patterns are 64 lines long, or until special code 20.
+        if(currentLine++==63 || special == 20){
+            currentLine=0;
+            if(++pattern>=sizeof(my_pattern))pattern=0;
+        }
+
+    } // playMusic
+}
+
+
+int beatCounter;
+void update_buffer(){
+
+ int quart = soundbufindex / 512;
+ int sndOffset[]={1024,1536,0,512};
+
+    if(oldQuart != quart){
+        oldQuart = quart;
+        for(int t=0; t<=SBUFSIZE/4;){
+            uint8_t sample = mixSound(t);
+            soundbuf[t+sndOffset[quart]] = sample;
+            t++;
+        }
+//        if(beatCounter++==3){
+//            beatCounter=0;
+//            update_tune();            
+//        }
     }
- 
-    if(currentLine++==63){
-        currentLine=0;
-        pattern++;
+    
+}
+
+// print text
+void print(uint16_t x, uint16_t y, const char* text){
+    for(uint8_t t = 0; t < strlen(text); t++){
+        uint8_t character = text[t];
+        d.drawBitmap(x,y,tinyfont[character]);
+        x += 4;
     }
 }
 
@@ -218,58 +211,72 @@
 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;
+    mygame.setFrameRate(255);    
 
     // Init audio stream.
     pokPlayStream(); // activate stream
     mygame.sound.ampEnable(true);
     mygame.sound.playMusicStream();
-    
-    
-    uint32_t nextBufferIndexToFill = 0;
+
+    sounder.attach(&update_tune, 0.08); // speed of song
+
+
+    d.load565Palette(&tinyfont_pal[0]);
 
     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();            
-        }        
-
+        update_buffer();
+        
         if (mygame.update())
         {
-            // update buttons
-            myPad = updateButtons(myPad);
-            UpdatePad(myPad);
-                        
             d.color = 1;
-            d.printf("Tick %d", mytick);
-            d.printf("Line %d", currentLine);
+            //d.printf("Pattern %d\n", pattern);
+            //d.printf("Line %d\n", currentLine);
+
+        char pat = my_pattern[pattern];
+    
+        char tempText[20];
+
+        int s1=currentLine-5;
+        if(s1<0)s1=0;
+        int s2 = currentLine+5;
+        if(s2>63)s2=63;
+
+        sprintf(tempText,"T[%2d] P[%2d] L[%2d]",pattern,pat,currentLine);
+        print(0,0,tempText);
+
+        int s;
+        for(s=s1; s<s2; s++){
+
+            for(int t=0; t<4; t++){
+                int note =       tune[pat][s][t][0];
+                int octave =     tune[pat][s][t][1]; // no longer used
+                int volume =     tune[pat][s][t][2];// max volume from xm/mod was 64
+                int instrument = tune[pat][s][t][3];
+                int special =    tune[pat][s][t][4];
+
+                if(volume >=128){
+                    volume -=128;
+                }
+            
+                int x1 = t*27;
+                int y1 = ((8-currentLine)+s)*6;
+
+                if(s == currentLine || s == currentLine+1){
+                    d.setColor(5);
+                    d.drawLine(0, y1-1, 219, y1-1); 
+                }
+                
+                print(x1,y1,noteNames[note]);
+                sprintf(tempText,"%d",octave);
+                print(x1 + 8,y1,tempText);
+                sprintf(tempText,"%d",volume);
+                print(x1 + 12,y1,tempText);
+                sprintf(tempText,"%2d|",instrument);
+                print(x1 + 16,y1,tempText);
+                
+            }
+        }
 
         }
     }