attempt at tracker style music

Dependencies:   PokittoLib

main.cpp

Committer:
spinal
Date:
2018-11-17
Revision:
13:8ce494870ba6
Parent:
12:37d999e445ad
Child:
14:97a5deea7c94
Child:
15:209481812170

File content as of revision 13:8ce494870ba6:

#include "Pokitto.h"
#include "HWSound.h"
#include "snd.h"
#include "tune.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;
    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#


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){
/*
    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];

    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;
            }
        }
     }    


//    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++;
        }
    }

}

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
                        
            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

    // 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);
                        
            d.color = 1;
            d.printf("Tick %d", mytick);
            d.printf("Line %d", currentLine);

        }
    }
}