Nucleo Sequencer of my Base Machine

Dependencies:   Amp AverageAnalogIn Envelope FilterController Sequence BaseMachineComon mbed-rtos mbed

Fork of SpiSequenceSender_Test by Ryo Od

main.cpp

Committer:
ryood
Date:
2016-09-09
Revision:
37:d4e50159baee
Parent:
36:50ad7e0a9a95
Child:
38:820cb3a7102b

File content as of revision 37:d4e50159baee:

/*
 * main.cpp
 * SpiSequencerSender_test
 *
 * 2016.08.20 mbed Rev 121 / mbed-rtos Rev 117で動作確認
 *
 */

#include "mbed.h"
#include "rtos.h"
#include "st7565LCD.h"
#include "PinDetect.h"
#include "RotaryEncoder.h"
#include "AverageAnalogIn.h"

#define UART_TRACE  (0)
#include "SpiSequenceSender.h"
#include "EnvelopeGenerator.h"
#include "SpiAmpController.h"
#include "SpiFilterController.h"
#include "ST7565_SequencerDisplay.h"

#define TITLE_STR1  ("BaseMachine Sequencer")
#define TITLE_STR2  ("20160909")

#define SEQUENCE_N  (16)
#define SPI_RATE    (16000000)  // Actual frequency about 5MHz

const int samplingPeriod = 1;   // ms
const int bpm = 120;
const int envelopeLength = (60 * 1000 / (bpm * 4)) / samplingPeriod;
const int waveShape = SpiSequenceSender::WAVESHAPE_SQUARE;
const int baseNoteNumber = 36;
const int bpmMax = 240;
const int bpmMin = 60;
const int UImodeMax = 2;

// Initial Sequence
const int noteOn[SEQUENCE_N] = { 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 };
const int pitch[SEQUENCE_N]  = {36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 };
const int tie[SEQUENCE_N]    = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const int accent[SEQUENCE_N] = { 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 };

// Devices
//
//SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel=NC)
SPI spiMaster(PA_7, PA_6, PA_5);

//ST7565(PinName mosi, PinName sclk, PinName cs, PinName rst, PinName a0);
ST7565 gLCD(PB_15, PB_13, PB_12, PB_2, PB_1);

AverageAnalogIn AinPulseWidth(PC_2);
AverageAnalogIn AinCutOff(PB_0);
AverageAnalogIn AinResonance(PC_1);
AverageAnalogIn AinEnvMod(PC_3);
AverageAnalogIn AinLevel(PC_0);
AverageAnalogIn AinDuration(PA_4);
AverageAnalogIn AinDecay(PA_1);
AverageAnalogIn AinSustain(PA_0);

RotaryEncoder RotEncStep(PB_9, PB_8, 0, SEQUENCE_N - 1, 0);
RotaryEncoder RotEncPitch(PB_5, PB_4, 0, Sequence::getMaxPitch() - 1, 0);
RotaryEncoder RotEncBpm(PC_12, PC_10, bpmMin, bpmMax, 120);

PinDetect PinWaveShape(PD_2, PullUp);
PinDetect PinUIMode(PC_11, PullUp);
PinDetect PinOctaveUp(PB_3, PullUp);
PinDetect PinOctaveDown(PA_10, PullUp);
PinDetect PinNoteOnOff(PC_5, PullUp);
PinDetect PinTie(PC_6, PullUp);
PinDetect PinAccent(PC_8, PullUp);
PinDetect PinRunStop(PC_9, PullUp);

PwmOut LCDBackLight(PA_11);

// Grobal Variables
//
Sequence sequences[SEQUENCE_N];
SpiSequenceSender sequenceSender(&spiMaster, D9, sequences, SEQUENCE_N, samplingPeriod, bpm);

Envelope envelope(4095, envelopeLength, envelopeLength*3/4, envelopeLength/2, 2047);
EnvelopeGenerator envelopeGenerator;
SpiAmpController ampController(&spiMaster, D8, D7);

SpiFilterController filterController(&spiMaster, D10);

ST7565_SequencerDisplay sequencerDisplay(&gLCD, sequences, SEQUENCE_N);

volatile int currentStep = 0;
volatile int playingStep = 0;
volatile bool isRunning = false;
volatile bool isDirty = true;
volatile uint8_t pinFlag = 0x00;
volatile int UImode = 0;

enum PinBit {
    bWaveShape  = 0x01,
    bUIMode       = 0x02,
    bOctaveUp   = 0x04,
    bOctaveDown = 0x08,
    bNoteOnOff  = 0x10,
    bTie        = 0x20,
    bAccent     = 0x40,
    bRunStop    = 0x80
};

// とりあえずの変数(後でClassのメンバ変数に格納)
volatile uint8_t envMod = 127;

//------------------------------------------------------------------------
// Callback functions
//------------------------------------------------------------------------
void updateTicks(int ticks)
{
    if (ticks == 0) {
        envelopeGenerator.init(envelope);
        // LCDにStepを表示するフラグを立てる
        //sequencerDisplay.update(SequencerDisplay::run, sequenceSender.getStep());
        playingStep = sequenceSender.getStep();
        isDirty = true;
    }

    if (sequences[sequenceSender.getStep()].isNoteOn()) {
        uint16_t level = envelopeGenerator.getModLevel();
        if (!sequences[sequenceSender.getStep()].isAccent()) {
            level = level * 1 / 2;
        }
        ampController.outDca(level);
    } else {
        ampController.outDca(0);
    }
    envelopeGenerator.update();
    
    filterController.outDcf();
}

//------------------------------------------------------------------------
// PinDetect ISR
//------------------------------------------------------------------------
void swWaveShapePressed()
{
    pinFlag |= bWaveShape;
}

void swUIModePressed()
{
    pinFlag |= bUIMode;
}

void swOctaveUpPressed()
{
    pinFlag |= bOctaveUp;
}

void swOctaveDownPressed()
{
    pinFlag |= bOctaveDown;
}

void swNoteOnOffPressed()
{
    pinFlag |= bNoteOnOff;
}

void swTiePressed()
{
    pinFlag |= bTie;
}

void swAccentPressed()
{
    pinFlag |= bAccent;
}

void swRunStopPressed()
{
    pinFlag |= bRunStop;
}

//------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------
void pollingPots()
{
    sequenceSender.setPulseWidth(AinPulseWidth.read_u16() >> 8);

    filterController.setCutoff(AinCutOff.read_u16() >> 8);
    filterController.setResonance(AinResonance.read_u16() >> 8);
    
    // テスト用にバックライトの調整に使用
    LCDBackLight = AinEnvMod.read();
    
    envelope.setLevel(AinLevel.read_u16() >> 4);
    envelope.setDuration(AinDuration.read() * envelopeLength);
    envelope.setDecay(AinDecay.read() * envelopeLength);
    envelope.setSustain(AinSustain.read() * 4095);
}

void pollingRotEncs()
{
    int _bpm = RotEncBpm.getVal();
    if (_bpm != sequenceSender.getBpm()) {
        sequenceSender.setBpm(_bpm);
        sequencerDisplay.setBpm(_bpm);
        isDirty = true;
    }
    
    int _step = RotEncStep.getVal();
    if (_step != currentStep) {
        currentStep = _step;
        // syncronize sequence value & Rotary Encoder's value
        RotEncPitch.setVal(sequences[currentStep].getPitch());
        isDirty = true;
    }
    
    int _pitch = RotEncPitch.getVal();
    if (_pitch != sequences[currentStep].getPitch()) {
        sequences[currentStep].setPitch(_pitch);
        isDirty = true;
    }
}

void pollingPins()
{
    if (pinFlag & bWaveShape) {
        #if (UART_TRACE)
        printf("PinWaveShape Pushed\r\n");
        #endif
        uint8_t waveShape = sequenceSender.getWaveShape();
        waveShape++;
        if (waveShape == SpiSequenceSender::WAVESHAPE_N) {
            waveShape = 0;
        }
        sequenceSender.setWaveShape(waveShape);
        sequencerDisplay.setWaveShape(waveShape);
        pinFlag &= ~bWaveShape;
        isDirty = true;
    }
    
    if (pinFlag & bUIMode) {
        #if (UART_TRACE)
        printf("PinUIMode Pushed\r\n");
        #endif
        UImode++;
        if (UImode > UImodeMax) {
            UImode = 0;
        }
        pinFlag &= ~bUIMode;
        isDirty = true;
    }
    
    if (pinFlag & bOctaveUp) {
        #if (UART_TRACE)
        printf("PinOctaveUp Pushed\r\n");
        #endif
        //sequences[currentStep].setOctave(sequences[currentStep].getOctave() + 1);
        sequencerDisplay.setOctave(sequencerDisplay.getOctave() + 1);
        pinFlag &= ~bOctaveUp;
        isDirty = true;
    }

    if (pinFlag & bOctaveDown) {
        #if (UART_TRACE)
        printf("PinOctaveDown Pushed\r\n");
        #endif
        //sequences[currentStep].setOctave(sequences[currentStep].getOctave() - 1);
        sequencerDisplay.setOctave(sequencerDisplay.getOctave() - 1);
        pinFlag &= ~bOctaveDown;
        isDirty = true;
    }
    
    if (pinFlag & bNoteOnOff) {
        #if (UART_TRACE)
        printf("PinNoteOnOff Pushed\r\n");
        #endif
        sequences[currentStep].setNoteOn(!sequences[currentStep].isNoteOn());
        pinFlag &= ~bNoteOnOff;
        isDirty = true;
    }
    
    if (pinFlag & bTie) {
        #if (UART_TRACE)
        printf("PinTie Pushed\r\n");
        #endif
        sequences[currentStep].setTie(!sequences[currentStep].isTie());
        pinFlag &= ~bTie;
        isDirty = true;
    }
    
    if (pinFlag & bAccent) {
        #if (UART_TRACE)
        printf("PinAccent Pushed\r\n");
        #endif
        sequences[currentStep].setAccent(!sequences[currentStep].isAccent());
        pinFlag &= ~bAccent;
        isDirty = true;
    }
    
    if (pinFlag & bRunStop) {
        #if (UART_TRACE)
        printf("PinRunStop Pushed\r\n");
        #endif
        if (isRunning) {
            ampController.outDca(0);
            sequenceSender.stop();
            isRunning = false;
        } else {
            sequenceSender.run(currentStep);
            isRunning = true;
        }
        pinFlag &= ~bRunStop;
        isDirty = true;
    }
}

void dumpToLCD00()
{
    char buff[64];
    int col = 0;
    
    gLCD.clear();

    sprintf(buff, "Run:%d BPM:%03d", isRunning, sequenceSender.getBpm());
    gLCD.drawstring(0, col++, buff);

    sprintf(buff, "Stp:%02d Nto:%d Pch:%02d",
        currentStep, sequences[currentStep].isNoteOn(), sequences[currentStep].getPitch());
    gLCD.drawstring(0, col++, buff);
    
    sprintf(buff, "Oct:%-2d Tie:%d Acc:%d", 
        sequencerDisplay.getOctave(), sequences[currentStep].isTie(),sequences[currentStep].isAccent());
    gLCD.drawstring(0, col++, buff);

    sprintf(buff, "Wsp:%d Mod:%d", sequenceSender.getWaveShape(), UImode);
    gLCD.drawstring(0, col++, buff);
    
    sprintf(buff, "PW :%4d   CO :%4d", sequenceSender.getPulseWidth(), filterController.getCutoff());
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "RSO:%4d   ENV:%4d", filterController.getResonance(), envMod);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "LVL:%4d   DUR:%4d", envelope.getLevel(), envelope.getDuration());
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "DCY:%4d   SUS:%4d", envelope.getDecay(), envelope.getSustain());
    gLCD.drawstring(0, col++, buff);
    
    gLCD.display();
}

void dumpToLCD01()
{
    char buff[64];
    int col = 0;
    
    gLCD.clear();

    sprintf(buff, "Cutoff     %5d", AinCutOff.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "Duration   %5d", AinDuration.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "Decay      %5d", AinDecay.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "Sustain    %5d", AinSustain.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    
    
    sprintf(buff, "Resonance  %5d", AinResonance.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "Level      %5d", AinLevel.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "PulseWidth %5d", AinPulseWidth.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    sprintf(buff, "EnvMod     %5d", AinEnvMod.read_u16() >> 8);
    gLCD.drawstring(0, col++, buff);
    
    gLCD.display();
}

//------------------------------------------------------------------------
// Main routine
//------------------------------------------------------------------------
int main()
{
    #if (UART_TRACE)
    printf("*** BaseMachine Sequencer ***\r\n");
    #endif
    
    //--------------------------------------------------------------------
    // Setup Devices
    //
    spiMaster.format(8, 0);
    spiMaster.frequency(SPI_RATE);
    
    // Mute output
    ampController.outDca(0);
    
    LCDBackLight.period_ms(10); 
    LCDBackLight = 0.6f;
    gLCD.set_spi_frequency(SPI_RATE);
    gLCD.begin(0x12);
    gLCD.clear();
    gLCD.drawstring(0, 0, TITLE_STR1);
    gLCD.drawstring(0, 1, TITLE_STR2);
    gLCD.display();
    Thread::wait(1000);
    
    RotEncStep.setInterval(100);
    RotEncPitch.setInterval(100);
    RotEncBpm.setInterval(100);
    
    PinWaveShape.attach_asserted(&swWaveShapePressed);
    PinWaveShape.setAssertValue(0);
    PinWaveShape.setSampleFrequency();  
    
    PinUIMode.attach_asserted(&swUIModePressed);
    PinUIMode.setAssertValue(0);
    PinUIMode.setSampleFrequency();
    
    PinOctaveUp.attach_asserted(&swOctaveUpPressed);
    PinOctaveUp.setAssertValue(0);
    PinOctaveUp.setSampleFrequency();  

    PinOctaveDown.attach_asserted(&swOctaveDownPressed);
    PinOctaveDown.setAssertValue(0);
    PinOctaveDown.setSampleFrequency();
    
    PinNoteOnOff.attach_asserted(&swNoteOnOffPressed);
    PinNoteOnOff.setAssertValue(0);
    PinNoteOnOff.setSampleFrequency();  
    
    PinTie.attach_asserted(&swTiePressed);
    PinTie.setAssertValue(0);
    PinTie.setSampleFrequency();  
    
    PinAccent.attach_asserted(&swAccentPressed);
    PinAccent.setAssertValue(0);
    PinAccent.setSampleFrequency();    
    
    PinRunStop.attach_asserted(&swRunStopPressed);
    PinRunStop.setAssertValue(0);
    PinRunStop.setSampleFrequency(); 
    
    //--------------------------------------------------------------------
    // Initialize objects
    //
    Sequence::setBaseNoteNumber(baseNoteNumber);
    
    for (int i = 0; i < SEQUENCE_N; i++) {
        Sequence& seq = sequenceSender.getSequences()[i];
        seq.setPitch(pitch[i]);
        seq.setNoteOn(noteOn[i]);
        seq.setTie(tie[i]);
        seq.setAccent(accent[i]);
    }
    RotEncPitch.setVal(sequences[0].getPitch());
    
    envelopeGenerator.init(envelope);

    sequenceSender.attachUpdate(&updateTicks);
    sequenceSender.setWaveShape(waveShape);
    
    //--------------------------------------------------------------------
    // Main loop
    //
    for (;;) {
        pollingPots();
        pollingRotEncs();
        pollingPins();
        if (!isRunning) {
            if (isDirty) {
                switch (UImode) {
                case 0:
                    sequencerDisplay.update(SequencerDisplay::stop, currentStep, playingStep);
                    break;
                case 1:
                    dumpToLCD00();
                    break;
                }
                isDirty = false;
            }
            if (UImode == 2) {
                dumpToLCD01();
            }
        } else {
            if (isDirty) {
                sequencerDisplay.update(SequencerDisplay::run, currentStep, playingStep);
                /*
                static int cnt = 0;
                char buffer[32];
                sprintf(buffer, "%d", cnt);
                cnt++;
                gLCD.clear();
                gLCD.drawstring(0, 0, buffer);
                gLCD.display();
                */
                //gLCD.fillrect((currentStep-1) * 7, 1, 7, 1, 0);
                //gLCD.clear();
                //gLCD.fillrect(currentStep * 7, 1, 7, 3, 1);
                //gLCD.display();
                
                isDirty = false;
            }
        }
    }
}