Integrated version
Diff: BaseMachineUIController.h
- Revision:
- 0:5bc618f6d862
- Child:
- 1:ecae97c65943
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BaseMachineUIController.h Sun Nov 06 22:13:43 2016 +0000 @@ -0,0 +1,525 @@ +/* + * BaseMachineUIController.h + * + * 2016.11.06 created + * + */ + +#ifndef _UICONTROLLER_H_ +#define _UICONTROLLER_H_ + +#include "mbed.h" +#include "rtos.h" + +#include "BaseMachineCommon.h" + +#include "st7565LCD.h" +#include "PinDetect.h" +#include "RotaryEncoder.h" +#include "AverageAnalogIn.h" + +#include "Sequence.h" +#include "ST7565_SequencerDisplay.h" + +#define GLCD_SPI_RATE (1000000) +#define POT_RESOLUTION (7) // bit +#define AIN_AVERAGE (16) // AnalogInを移動平均する要素数 + +const int bpmMax = 240; +const int bpmMin = 60; +const int octaveMax = 2; +const int octaveMin = -2; +const int waveShapeMax = 1; +const int UImodeMax = 2; + +struct OscillatorParam { + uint8_t waveShape; + uint8_t pulseWidth; + + OscillatorParam() : waveShape(0), pulseWidth(0) {} +}; + +struct FilterParam { + uint8_t cutoff; + uint8_t resonance; + + FilterParam() : cutoff(0), resonance(0) {} +}; + +struct EnvelopeParam { + uint8_t level; + uint8_t length; + uint8_t duration; + uint8_t decay; + uint8_t sustain; + + EnvelopeParam() : level(0), length(0), duration(0), decay(0), sustain(0) {} +}; + +class BaseMachineUIController +{ +public: + BaseMachineUIController() : + bpm(120), + accentLevel(127), + editingStep(0), + playingStep(0), + isRunning(false), + isDirty(true), + UImode(0), + isStepChanged(false), + errCutoff(0), + errDuration(0), + errDecay(0), + errSustain(0), + errResonance(0), + errLevel(0), + errPulseWidth(0), + errAccentLevel(0) { + } + + ~BaseMachineUIController() {} + + void init() { + //-------------------------------------------------------------------- + // Create Dvices + // + //ST7565(PinName mosi, PinName sclk, PinName cs, PinName rst, PinName a0); + gLCD = new ST7565(PB_15, PB_13, PB_12, PB_2, PB_1); + sequencerDisplay = new ST7565_SequencerDisplay(gLCD, sequences, SEQUENCE_N); + + AinPulseWidth = new AverageAnalogIn(PC_2, AIN_AVERAGE); + AinCutOff = new AverageAnalogIn(PB_0, AIN_AVERAGE); + AinResonance = new AverageAnalogIn(PC_1, AIN_AVERAGE); + AinLevel = new AverageAnalogIn(PC_0, AIN_AVERAGE); + AinDuration = new AverageAnalogIn(PA_4, AIN_AVERAGE); + AinDecay = new AverageAnalogIn(PA_1, AIN_AVERAGE); + AinSustain = new AverageAnalogIn(PA_0, AIN_AVERAGE); + AinAccentLevel= new AverageAnalogIn(PC_3, AIN_AVERAGE); + + RotEncStep = new RotaryEncoder(PA_11, PA_12, 0, SEQUENCE_N - 1, 0); + RotEncPitch = new RotaryEncoder(PB_5, PB_4, 0, Sequence::getMaxPitch() - 1, 0); + RotEncBpm = new RotaryEncoder(PC_12, PC_10, bpmMin, bpmMax, 120); + + PinWaveShape = new PinDetect(PD_2, PullUp); + PinUIMode = new PinDetect(PC_11, PullUp); + PinOctaveUp = new PinDetect(PB_3, PullUp); + PinOctaveDown = new PinDetect(PA_10, PullUp); + PinNoteOnOff = new PinDetect(PC_5, PullUp); + PinTie = new PinDetect(PC_6, PullUp); + PinAccent = new PinDetect(PC_8, PullUp); + PinRunStop = new PinDetect(PC_9, PullUp); + + //-------------------------------------------------------------------- + // Setup Devices + // + gLCD->set_spi_frequency(GLCD_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(this, &BaseMachineUIController::swWaveShapePressed); + PinWaveShape->setAssertValue(0); + PinWaveShape->setSampleFrequency(); + + PinUIMode->attach_asserted(this, &BaseMachineUIController::swUIModePressed); + PinUIMode->setAssertValue(0); + PinUIMode->setSampleFrequency(); + + PinOctaveUp->attach_asserted(this, &BaseMachineUIController::swOctaveUpPressed); + PinOctaveUp->setAssertValue(0); + PinOctaveUp->setSampleFrequency(); + + PinOctaveDown->attach_asserted(this, &BaseMachineUIController::swOctaveDownPressed); + PinOctaveDown->setAssertValue(0); + PinOctaveDown->setSampleFrequency(); + + PinNoteOnOff->attach_asserted(this, &BaseMachineUIController::swNoteOnOffPressed); + PinNoteOnOff->setAssertValue(0); + PinNoteOnOff->setSampleFrequency(); + + PinTie->attach_asserted(this, &BaseMachineUIController::swTiePressed); + PinTie->setAssertValue(0); + PinTie->setSampleFrequency(); + + PinAccent->attach_asserted(this, &BaseMachineUIController::swAccentPressed); + PinAccent->setAssertValue(0); + PinAccent->setSampleFrequency(); + + PinRunStop->attach_asserted(this, &BaseMachineUIController::swRunStopPressed); + PinRunStop->setAssertValue(0); + PinRunStop->setSampleFrequency(); + + //-------------------------------------------------------------------- + // Initialize objects + // + Sequence::setBaseNoteNumber(baseNoteNumber); + + for (int i = 0; i < SEQUENCE_N; i++) { + Sequence& seq = sequences[i]; + seq.setPitch(pitch[i]); + seq.setNoteOn(noteOn[i]); + seq.setTie(tie[i]); + seq.setAccent(accent[i]); + } + RotEncPitch->setVal(sequences[0].getPitch()); + } + + void destract() { + //-------------------------------------------------------------------- + // Destract Devices + // + delete gLCD; + + delete AinPulseWidth; + delete AinCutOff; + delete AinResonance; + delete AinLevel; + delete AinDuration; + delete AinDecay; + delete AinSustain; + delete AinAccentLevel; + + delete RotEncStep; + delete RotEncPitch; + delete RotEncBpm; + + delete PinWaveShape; + delete PinUIMode; + delete PinOctaveUp; + delete PinOctaveDown; + delete PinNoteOnOff; + delete PinTie; + delete PinAccent; + delete PinRunStop; + } + + void getOscillatorParam(OscillatorParam* pParam) { + memcpy(pParam, &oscillatorParam, sizeof(oscillatorParam)); + } + void getFilterParam(FilterParam* pParam) { + memcpy(pParam, &filterParam, sizeof(filterParam)); + } + void getEnvelopeParam(EnvelopeParam* pParam) { + memcpy(pParam, &envelopeParam, sizeof(envelopeParam)); + } + uint8_t getBpm() { return bpm; } + uint8_t getAccentLevel() { return accentLevel; } + + bool getIsRunning() { return isRunning; } + + void setPlayingStep(int step) + { + playingStep = step; + isDirty = true; + } + + void update() { + pollingRotEncs(); + pollingPots(); + + switch (UImode) { + case 0: + if (isDirty) { + sequencerDisplay->update(SequencerDisplay::stop, editingStep, playingStep); + } + break; + case 1: + if (isDirty) { + dumpToLCD00(); + } + break; + case 2: + dumpToLCD01(); + break; + } + isDirty = false; + } + +private: + ST7565* gLCD; + + AverageAnalogIn* AinPulseWidth; + AverageAnalogIn* AinCutOff; + AverageAnalogIn* AinResonance; + AverageAnalogIn* AinLevel; + AverageAnalogIn* AinDuration; + AverageAnalogIn* AinDecay; + AverageAnalogIn* AinSustain; + AverageAnalogIn* AinAccentLevel; + + RotaryEncoder* RotEncStep; + RotaryEncoder* RotEncPitch; + RotaryEncoder* RotEncBpm; + + PinDetect* PinWaveShape; + PinDetect* PinUIMode; + PinDetect* PinOctaveUp; + PinDetect* PinOctaveDown; + PinDetect* PinNoteOnOff; + PinDetect* PinTie; + PinDetect* PinAccent; + PinDetect* PinRunStop; + + ST7565_SequencerDisplay* sequencerDisplay; + + Sequence sequences[SEQUENCE_N]; + + OscillatorParam oscillatorParam; + FilterParam filterParam; + EnvelopeParam envelopeParam; + + uint8_t bpm; + uint8_t accentLevel; + + int editingStep; + int playingStep; + bool isRunning; + bool isDirty; + int UImode; + + bool isStepChanged; + + int errCutoff; + int errDuration; + int errDecay; + int errSustain; + int errResonance; + int errLevel; + int errPulseWidth; + int errAccentLevel; + + //------------------------------------------------------------------------ + // PinDetect callback functions + //------------------------------------------------------------------------ + void swWaveShapePressed() { +#if (UART_TRACE) + printf("PinWaveShape Pushed\r\n"); +#endif + uint8_t _waveShape = oscillatorParam.waveShape; + _waveShape++; + if (_waveShape > waveShapeMax) { + _waveShape = 0; + } + oscillatorParam.waveShape = _waveShape; + sequencerDisplay->setWaveShape(_waveShape); + isDirty = true; + } + + void swUIModePressed() { +#if (UART_TRACE) + printf("PinUIMode Pushed\r\n"); +#endif + UImode++; + if (UImode > UImodeMax) { + UImode = 0; + } + isDirty = true; + } + + void swOctaveUpPressed() { +#if (UART_TRACE) + printf("PinOctaveUp Pushed\r\n"); +#endif + if (sequencerDisplay->getOctave() < octaveMax) { + sequencerDisplay->setOctave(sequencerDisplay->getOctave() + 1); + isDirty = true; + } + } + + void swOctaveDownPressed() { +#if (UART_TRACE) + printf("PinOctaveDown Pushed\r\n"); +#endif + if (sequencerDisplay->getOctave () > octaveMin) { + sequencerDisplay->setOctave(sequencerDisplay->getOctave() - 1); + isDirty = true; + } + } + + void swNoteOnOffPressed() { +#if (UART_TRACE) + printf("PinNoteOnOff Pushed\r\n"); +#endif + sequences[editingStep].setNoteOn(!sequences[editingStep].isNoteOn()); + isDirty = true; + } + + void swTiePressed() { +#if (UART_TRACE) + printf("PinTie Pushed\r\n"); +#endif + sequences[editingStep].setTie(!sequences[editingStep].isTie()); + isDirty = true; + } + + void swAccentPressed() { +#if (UART_TRACE) + printf("PinAccent Pushed\r\n"); +#endif + sequences[editingStep].setAccent(!sequences[editingStep].isAccent()); + isDirty = true; + } + + void swRunStopPressed() { +#if (UART_TRACE) + printf("PinRunStop Pushed\r\n"); +#endif + if (isRunning) { + isRunning = false; + } else { + isRunning = true; + } + isDirty = true; + } + + //------------------------------------------------------------------------ + // Functions + //------------------------------------------------------------------------ + void pollingRotEncs() { + int _bpm = RotEncBpm->getVal(); + if (_bpm != bpm) { + bpm = _bpm; + sequencerDisplay->setBpm(_bpm); + isDirty = true; + } + + int _step = RotEncStep->getVal(); + if (_step != editingStep) { + editingStep = _step; + // syncronize sequence value & Rotary Encoder's value + RotEncPitch->setVal(sequences[editingStep].getPitch()); + isDirty = true; + } + + int _pitch = RotEncPitch->getVal(); + if (_pitch != sequences[editingStep].getPitch()) { + sequences[editingStep].setPitch(_pitch); + isDirty = true; + } + } + + void pollingPots() { + uint8_t pulseWidth = AinPulseWidth->read_u16() >> (16 - POT_RESOLUTION); + if (pulseWidth != oscillatorParam.pulseWidth) { + oscillatorParam.pulseWidth = pulseWidth; + errPulseWidth++; + isDirty = true; + } + + uint8_t cutoff = AinCutOff->read_u16() >> (16 - POT_RESOLUTION); + if (cutoff != filterParam.cutoff) { + filterParam.cutoff = cutoff; + errCutoff++; + isDirty = true; + } + + uint8_t resonance = AinResonance->read_u16() >> (16 - POT_RESOLUTION); + if (resonance != filterParam.resonance) { + filterParam.resonance = resonance; + errResonance++; + isDirty = true; + } + + uint8_t level = AinLevel->read_u16() >> (16 - POT_RESOLUTION); + if (level != envelopeParam.level) { + errLevel++; + envelopeParam.level = level; + isDirty = true; + } + + uint8_t duration = AinDuration->read_u16() >> (16 - POT_RESOLUTION); + if (duration != envelopeParam.duration) { + errDuration++; + envelopeParam.duration = duration; + isDirty = true; + } + + uint8_t decay = AinDecay->read_u16() >> (16 - POT_RESOLUTION); + if (decay != envelopeParam.decay) { + errDecay++; + envelopeParam.decay = decay; + isDirty = true; + } + + uint8_t sustain = AinSustain->read_u16() >> (16 - POT_RESOLUTION); + if (sustain != envelopeParam.sustain) { + errSustain++; + envelopeParam.sustain = sustain; + isDirty = true; + } + + uint8_t _accentLevel = AinAccentLevel->read_u16() >> (16 - POT_RESOLUTION); + if (_accentLevel != accentLevel) { + errAccentLevel++; + accentLevel = _accentLevel; + isDirty = true; + } + } + + void dumpToLCD00() { + char buff[64]; + int col = 0; + + gLCD->clear(); + + sprintf(buff, "Run:%d BPM:%03d", isRunning, bpm); + gLCD->drawstring(0, col++, buff); + + sprintf(buff, "Stp:%02d Nto:%d Pch:%02d", + editingStep, sequences[editingStep].isNoteOn(), sequences[editingStep].getPitch()); + gLCD->drawstring(0, col++, buff); + + sprintf(buff, "Oct:%-2d Tie:%d Acc:%d", + sequencerDisplay->getOctave(), sequences[editingStep].isTie(),sequences[editingStep].isAccent()); + gLCD->drawstring(0, col++, buff); + + sprintf(buff, "Wsp:%d Mod:%d pStp:%d", oscillatorParam.waveShape, UImode, playingStep); + gLCD->drawstring(0, col++, buff); + + sprintf(buff, "PW :%4d CO :%4d", oscillatorParam.pulseWidth, filterParam.cutoff); + gLCD->drawstring(0, col++, buff); + sprintf(buff, "RSO:%4d ACL:%4d", filterParam.resonance, accentLevel); + gLCD->drawstring(0, col++, buff); + sprintf(buff, "LVL:%4d DUR:%4d", envelopeParam.level, envelopeParam.duration); + gLCD->drawstring(0, col++, buff); + sprintf(buff, "DCY:%4d SUS:%4d", envelopeParam.decay, envelopeParam.sustain); + gLCD->drawstring(0, col++, buff); + + gLCD->display(); + } + + void dumpToLCD01() { + char buff[64]; + + gLCD->clear(); + + sprintf(buff, "Cutoff %3d %5d", filterParam.cutoff, errCutoff); + gLCD->drawstring(0, 0, buff); + sprintf(buff, "Duration %3d %5d", envelopeParam.duration, errDuration); + gLCD->drawstring(0, 1, buff); + sprintf(buff, "Decay %3d %5d", envelopeParam.decay, errDecay); + gLCD->drawstring(0, 2, buff); + sprintf(buff, "Sustain %3d %5d", envelopeParam.sustain, errSustain); + gLCD->drawstring(0, 3, buff); + sprintf(buff, "Resonance %3d %5d", filterParam.resonance, errResonance); + gLCD->drawstring(0, 4, buff); + sprintf(buff, "Level %3d %5d", envelopeParam.level, errLevel); + gLCD->drawstring(0, 5, buff); + sprintf(buff, "PulseWidth %3d %5d", oscillatorParam.pulseWidth, errPulseWidth); + gLCD->drawstring(0, 6, buff); + sprintf(buff, "AccentLvl %3d %5d", accentLevel, errAccentLevel); + gLCD->drawstring(0, 7, buff); + + gLCD->display(); + } +}; + +#endif //_UICONTROLLER_H_