attempt at tracker style music

Dependencies:   PokittoLib

Revision:
13:8ce494870ba6
Parent:
12:37d999e445ad
Child:
14:97a5deea7c94
Child:
15:209481812170
--- a/main.cpp	Sat Oct 20 15:16:16 2018 +0000
+++ b/main.cpp	Sat Nov 17 16:33:51 2018 +0000
@@ -1,140 +1,275 @@
 #include "Pokitto.h"
+#include "HWSound.h"
+#include "snd.h"
+#include "tune.h"
 
 Pokitto::Core mygame;
 Pokitto::Display d;
 
-mbed::DigitalOut jh_rumble(EXT0);
-mbed::DigitalIn jh_b1(EXT15);
-mbed::DigitalIn jh_b2(EXT14);
-mbed::AnalogIn jh_x(EXT1);
-mbed::AnalogIn jh_y(EXT2);
+//------------------------[ 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
+}
 
-#define ANALOG 256
-#define DECAY .85
-#define SEGSIZE 7
-#define number_of_segments 10
-#define MOVEANGLE .25
+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;
+}
+
 
-//Sprite structure
-typedef struct
-{
-    int x,y,oldx,oldy;  //location 
-    int xSpeed, ySpeed; //speed
-    char frame; // body gfx
-}Sprite;
-Sprite marbles[number_of_segments];
+typedef struct{
+    bool playSample;
+    int soundPoint;
+    const uint8_t *currentSound;
+    int currentSoundSize;
+    int volume;
+    int speed;
+    int repeat;
+} sampletype;
+
+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#
 
 
-bool move_tail(void){
-    int pos_x,pos_y;
-    int bodySize = SEGSIZE*512;
-    bool collision = false;
-    for(int t=1; t<number_of_segments; t++){
-//    float rotation = atan2((float)marbles[t].y-marbles[t-1].y,(float)marbles[t].x-marbles[t-1].x);
+void emptyBuffer(){
+    for(int t=0; t<SBUFSIZE;){
+        soundbuf[++t]=0;
+    }
+
+    for(int t=0; t<4; t++){
+        snd[t].playSample=0;
+    }
+
+}
+
+uint8_t playSound(int channel, const unsigned char *sound, uint16_t soundSize, int volume = 255, int speed=255, int repeat=0){
 /*
-    // rotate the head graphic
-    if(t==1)
-    {
-        int rot = rotation*(180 / 3.14159);
-        rot+=90;
-        if(rot<0)rot+=360;
-        if(rot>360)rot-=360;
-        rot/=10;
-        rot+=3;
-//        PA_SetSpriteAnimEx(1,0,16,16,1,rot);
+    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;
 
-    float x1 = marbles[t].x;
-    float y1 = marbles[t].y;
-    float x2 = marbles[t-1].x;
-    float y2 = marbles[t-1].y;
-    float rotation = atan2(y1-y2,x1-x2);
+    return channel;
+}
+
+uint8_t mixSound(int samplePos)
+{
+    int temp = 0;
+    int ss[4];
 
-    for(int s=0; s<number_of_segments; s++){
-        if(s<t-1 || s>t+1){
-            double square_difference_x = (x1 - marbles[s].x) * (x1 - marbles[s].x);
-            double square_difference_y = (y1 - marbles[s].y) * (y1 - marbles[s].y);
-            double value = sqrt(square_difference_x + square_difference_y);
-            
-            if(value < bodySize+1){
-                pos_x = x2 + bodySize * cos(rotation+MOVEANGLE);
-                pos_y = y2 + bodySize * sin(rotation+MOVEANGLE);
+    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){
+                snd[s].soundPoint=0;
+            }else{
+                snd[s].playSample=0;
+                snd[s].soundPoint=0;
+            }
+        }
+     }    
+
 
-                double square_difference_x = (pos_x - marbles[s].x) * (pos_x - marbles[s].x);
-                double square_difference_y = (pos_y - marbles[s].y) * (pos_y - marbles[s].y);
-                double value2 = sqrt(square_difference_x + square_difference_y);
-                
-                if(value < value2)rotation+=MOVEANGLE;
-                if(value > value2)rotation-=MOVEANGLE;
-                collision=true;
-            }
-        }    
+//    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;
     }
 
-    pos_x = marbles[t-1].x + bodySize * cos(rotation);
-    pos_y = marbles[t-1].y + bodySize * sin(rotation);
-    marbles[t].x = pos_x;
-    marbles[t].y = pos_y;
+}
 
 
-    } // for t...
-    return collision;
+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++;
+        }
+    }
+
+}
+
+void update_tune(){
 
-}// end function
-
+    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
+                        
+            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;
+            }
+        }
+                            
+        snd[t].volume = volume;
+                
+    }
+ 
+    if(currentLine++==63){
+        currentLine=0;
+        pattern++;
+    }
+}
 
 
 int main ()
 {
     mygame.begin();
+    mygame.setFrameRate(255);
+//    emptyBuffer(); // clear the sound buffer
 
-    int JCX = ((jh_x.read()*ANALOG));
-    int JCY = ((jh_y.read()*ANALOG));
+    // 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();
+    
+    
+    uint32_t nextBufferIndexToFill = 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();            
+        }        
+
         if (mygame.update())
         {
+            // update buttons
+            myPad = updateButtons(myPad);
+            UpdatePad(myPad);
                         
-            int xd = ((jh_x.read()*ANALOG)-JCX)*4;
-            int yd = ((jh_y.read()*ANALOG)-JCY)*4;
-            
-            // motion gravity etc.
-            marbles[0].xSpeed += -xd;
-            marbles[0].ySpeed += yd;
-            
-            // add some dampening to speed
-            marbles[0].xSpeed *= DECAY;
-            marbles[0].ySpeed *= DECAY;
-            
-            marbles[0].x += marbles[0].xSpeed;
-            marbles[0].y += marbles[0].ySpeed;
-            
-            
-            jh_rumble.write(mygame.buttons.aBtn());
             d.color = 1;
-            d.printf("Joy X: %d\n",xd);
-            d.printf("Joy Y: %d\n",yd);
-            d.printf("B1: %d\n",jh_b1.read());
-            d.printf("B2: %d\n",jh_b2.read());
-            d.printf("A to Rumble!\n");
-
-
-            // loop until the snake no longer collides with itself.
-            while(move_tail()){}
-
-            for(int t=0; t<number_of_segments; t++){
-                d.color = 0;
-                if(t==0) d.color = 1;
-                d.fillCircle(marbles[t].x>>8,marbles[t].y>>8,SEGSIZE);
-                d.color = 2;
-                d.drawCircle(marbles[t].x>>8,marbles[t].y>>8,SEGSIZE);
-            }
-
-
-
+            d.printf("Tick %d", mytick);
+            d.printf("Line %d", currentLine);
 
         }
     }