Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: AverageAnalogIn PinDetect RotaryEncoder Sequence SequencerDisplay mbed-rtos mbed st7567LCD BaseMachineComon
Fork of BaseMachine_Sequencer by
main.cpp
- Committer:
- ryood
- Date:
- 2016-10-16
- Revision:
- 51:7bbf15d6d7ec
- Parent:
- 50:0a06df15c784
- Child:
- 52:72332a596bc5
File content as of revision 51:7bbf15d6d7ec:
/*
* main.cpp
* SpiSequencerSender_test
*
* 2016.10.02 UI Controllerに分割
* 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 (1)
#include "Sequence.h"
#include "ST7565_SequencerDisplay.h"
#define TITLE_STR1 ("BaseMachine UI Controller")
#define TITLE_STR2 ("20161011")
#define SEQUENCE_N (16)
#define SPI1_RATE (3000000)
#define SPI2_RATE (1000000)
#define POT_RESOLUTION (7) // bit
#define AIN_AVERAGE (32) // AnalogInを移動平均する要素数
#define POLLING_POTS_WAIT (5) // POT読み取りThreadのWait値(ミリ秒)
enum SequencerCmd {
CMD_RCV_PLAYING_STEP = 0x01,
CMD_RUN = 0x11,
CMD_BPM = 0x12,
CMD_ACCENT_LEVEL = 0x13,
CMD_WAVE_SHAPE = 0x21,
CMD_PULSE_WIDTH = 0x22,
CMD_CUTOFF = 0x31,
CMD_RESONANCE = 0x32,
CMD_LEVEL = 0x41,
CMD_DURATION = 0x42,
CMD_DECAY = 0x43,
CMD_SUSTAIN = 0x44,
CMD_NOTE = 0x51,
CMD_PITCH = 0x52,
};
const int baseNoteNumber = 36;
const int bpmMax = 240;
const int bpmMin = 60;
const int octaveMax = 2;
const int octaveMin = -2;
const int waveShapeMax = 1;
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);
DigitalOut SpiMasterCs(PB_6);
InterruptIn stepChangeInterrupt(PC_7);
//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, AIN_AVERAGE);
AverageAnalogIn AinCutOff(PB_0, AIN_AVERAGE);
AverageAnalogIn AinResonance(PC_1, AIN_AVERAGE);
AverageAnalogIn AinLevel(PC_0, AIN_AVERAGE);
AverageAnalogIn AinDuration(PA_4, AIN_AVERAGE);
AverageAnalogIn AinDecay(PA_1, AIN_AVERAGE);
AverageAnalogIn AinSustain(PA_0, AIN_AVERAGE);
AverageAnalogIn AinAccentLevel(PC_3, AIN_AVERAGE);
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(PA_12, PullUp);
// Grobal Variables
//
Sequence sequences[SEQUENCE_N];
ST7565_SequencerDisplay sequencerDisplay(&gLCD, sequences, SEQUENCE_N);
struct OscillatorParam {
uint8_t waveShape;
uint8_t pulseWidth;
} oscillatorParam;
struct FilterParam {
uint8_t cutoff;
uint8_t resonance;
} filterParam;
struct EnvelopeParam {
uint8_t level;
uint8_t length;
uint8_t duration;
uint8_t decay;
uint8_t sustain;
} envelopeParam;
uint8_t bpm = 120;
uint8_t accentLevel = 127;
int currentStep = 0;
int playingStep = 0;
bool isRunning = false;
bool isDirty = true;
int UImode = 0;
volatile bool isStepChanged = false;
volatile uint8_t pinFlag = 0x00;
enum PinBit {
bWaveShape = 0x01,
bUIMode = 0x02,
bOctaveUp = 0x04,
bOctaveDown = 0x08,
bNoteOnOff = 0x10,
bTie = 0x20,
bAccent = 0x40,
bRunStop = 0x80
};
//------------------------------------------------------------------------
// InterruptIn ISR
//------------------------------------------------------------------------
void updateStep()
{
isStepChanged = true;
}
//------------------------------------------------------------------------
// 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
//------------------------------------------------------------------------
uint8_t getNoteData(uint8_t step)
{
uint8_t noteData = 0;
noteData |= (step << 4);
noteData |= (sequences[step].isAccent() ? 4 : 0);
noteData |= (sequences[step].isTie() ? 2 : 0);
noteData |= (sequences[step].isNoteOn() ? 1 : 0);
return noteData;
}
uint16_t SpiSendParams(uint8_t cmd, uint8_t data)
{
uint16_t sendVal = ((uint16_t)cmd << 8) | data;
SpiMasterCs = 0;
uint16_t recievedVal = SpiMaster.write(sendVal);
SpiMasterCs = 1;
//Thread::wait(1);
return recievedVal;
}
uint16_t SpiSendAllParams()
{
SpiSendParams(CMD_BPM, bpm);
SpiSendParams(CMD_ACCENT_LEVEL, accentLevel);
SpiSendParams(CMD_WAVE_SHAPE , oscillatorParam.waveShape);
SpiSendParams(CMD_PULSE_WIDTH, oscillatorParam.pulseWidth);
SpiSendParams(CMD_CUTOFF, filterParam.cutoff);
SpiSendParams(CMD_RESONANCE, filterParam.resonance);
SpiSendParams(CMD_LEVEL, envelopeParam.level);
SpiSendParams(CMD_DURATION, envelopeParam.duration);
SpiSendParams(CMD_DECAY, envelopeParam.decay);
SpiSendParams(CMD_SUSTAIN, envelopeParam.sustain);
for (int i = 0; i < SEQUENCE_N; i++) {
SpiSendParams(CMD_NOTE, getNoteData(i));
SpiSendParams(CMD_PITCH, sequences[i].getPitch());
}
uint16_t retVal = SpiSendParams(CMD_RCV_PLAYING_STEP, 0xaa); // Send dummy data
return retVal;
}
void pollingRotEncs()
{
int _bpm = RotEncBpm.getVal();
if (_bpm != bpm) {
bpm = _bpm;
sequencerDisplay.setBpm(_bpm);
SpiSendParams(CMD_BPM, _bpm);
isDirty = true;
}
int _step = RotEncStep.getVal();
if (_step != currentStep) {
currentStep = _step;
// syncronize sequence value & Rotary Encoder's value
RotEncPitch.setVal(sequences[currentStep].getPitch());
SpiSendParams(CMD_NOTE, getNoteData(_step));
SpiSendParams(CMD_PITCH, sequences[_step].getPitch());
isDirty = true;
}
int _pitch = RotEncPitch.getVal();
if (_pitch != sequences[currentStep].getPitch()) {
sequences[currentStep].setPitch(_pitch);
SpiSendParams(CMD_NOTE, getNoteData(currentStep));
SpiSendParams(CMD_PITCH, _pitch);
isDirty = true;
}
}
void pollingPins()
{
if (pinFlag & bWaveShape) {
#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);
pinFlag &= ~bWaveShape;
SpiSendParams(CMD_WAVE_SHAPE, _waveShape);
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
if (sequencerDisplay.getOctave() < octaveMax) {
sequencerDisplay.setOctave(sequencerDisplay.getOctave() + 1);
isDirty = true;
}
pinFlag &= ~bOctaveUp;
}
if (pinFlag & bOctaveDown) {
#if (UART_TRACE)
printf("PinOctaveDown Pushed\r\n");
#endif
if (sequencerDisplay.getOctave () > octaveMin) {
sequencerDisplay.setOctave(sequencerDisplay.getOctave() - 1);
isDirty = true;
}
pinFlag &= ~bOctaveDown;
}
if (pinFlag & bNoteOnOff) {
#if (UART_TRACE)
printf("PinNoteOnOff Pushed\r\n");
#endif
sequences[currentStep].setNoteOn(!sequences[currentStep].isNoteOn());
pinFlag &= ~bNoteOnOff;
SpiSendParams(CMD_NOTE, getNoteData(currentStep));
isDirty = true;
}
if (pinFlag & bTie) {
#if (UART_TRACE)
printf("PinTie Pushed\r\n");
#endif
sequences[currentStep].setTie(!sequences[currentStep].isTie());
pinFlag &= ~bTie;
SpiSendParams(CMD_NOTE, getNoteData(currentStep));
isDirty = true;
}
if (pinFlag & bAccent) {
#if (UART_TRACE)
printf("PinAccent Pushed\r\n");
#endif
sequences[currentStep].setAccent(!sequences[currentStep].isAccent());
pinFlag &= ~bAccent;
SpiSendParams(CMD_NOTE, getNoteData(currentStep));
isDirty = true;
}
if (pinFlag & bRunStop) {
#if (UART_TRACE)
printf("PinRunStop Pushed\r\n");
#endif
if (isRunning) {
isRunning = false;
} else {
isRunning = true;
}
pinFlag &= ~bRunStop;
SpiSendParams(CMD_RUN, isRunning);
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",
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 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()
{
static int errCutoff = 0;
static int errDuration = 0;
static int errDecay = 0;
static int errSustain = 0;
static int errResonace = 0;
static int errLevel = 0;
static int errPulseWidth = 0;
static int errAccentLevel = 0;
uint8_t v;
char buff[64];
v = AinCutOff.read_u16() >> (16 - POT_RESOLUTION);
if (v != filterParam.cutoff) {
errCutoff++;
filterParam.cutoff = v;
}
v = AinDuration.read_u16() >> (16 - POT_RESOLUTION);
if (v != envelopeParam.duration) {
errDuration++;
envelopeParam.duration = v;
}
v = AinDecay.read_u16() >> (16 - POT_RESOLUTION);
if (v != envelopeParam.decay) {
errDecay++;
envelopeParam.decay = v;
}
v = AinSustain.read_u16() >> (16 - POT_RESOLUTION);
if (v != envelopeParam.sustain) {
errSustain++;
envelopeParam.sustain = v;
}
v = AinResonance.read_u16() >> (16 - POT_RESOLUTION);
if (v != filterParam.resonance) {
errResonace++;
filterParam.resonance = v;
}
v = AinLevel.read_u16() >> (16 - POT_RESOLUTION);
if (v != envelopeParam.level) {
errLevel++;
envelopeParam.level = v;
}
v = AinPulseWidth.read_u16() >> (16 - POT_RESOLUTION);
if (v != oscillatorParam.pulseWidth) {
errPulseWidth++;
oscillatorParam.pulseWidth = v;
}
v = AinAccentLevel.read_u16() >> (16 - POT_RESOLUTION);
if (v != accentLevel) {
errAccentLevel++;
accentLevel = v;
}
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, errResonace);
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();
Thread::wait(10);
}
//------------------------------------------------------------------------
// Threads
//------------------------------------------------------------------------
void pollingPots(void const *args)
{
for (;;)
{
uint8_t pulseWidth = AinPulseWidth.read_u16() >> (16 - POT_RESOLUTION);
if (pulseWidth != oscillatorParam.pulseWidth) {
oscillatorParam.pulseWidth = pulseWidth;
SpiSendParams(CMD_PULSE_WIDTH, pulseWidth);
isDirty = true;
}
uint8_t cutoff = AinCutOff.read_u16() >> (16 - POT_RESOLUTION);
if (cutoff != filterParam.cutoff) {
filterParam.cutoff = cutoff;
SpiSendParams(CMD_CUTOFF, cutoff);
isDirty = true;
}
uint8_t resonance = AinResonance.read_u16() >> (16 - POT_RESOLUTION);
if (resonance != filterParam.resonance) {
filterParam.resonance = resonance;
SpiSendParams(CMD_RESONANCE, resonance);
isDirty = true;
}
uint8_t level = AinLevel.read_u16() >> (16 - POT_RESOLUTION);
if (level != envelopeParam.level) {
envelopeParam.level = level;
SpiSendParams(CMD_LEVEL, level);
isDirty = true;
}
uint8_t duration = AinDuration.read_u16() >> (16 - POT_RESOLUTION);
if (duration != envelopeParam.duration) {
envelopeParam.duration = duration;
SpiSendParams(CMD_DURATION, duration);
isDirty = true;
}
uint8_t decay = AinDecay.read_u16() >> (16 - POT_RESOLUTION);
if (decay != envelopeParam.decay) {
envelopeParam.decay = decay;
SpiSendParams(CMD_DECAY, decay);
isDirty = true;
}
uint8_t sustain = AinSustain.read_u16() >> (16 - POT_RESOLUTION);
if (sustain != envelopeParam.sustain) {
envelopeParam.sustain = sustain;
SpiSendParams(CMD_SUSTAIN, sustain);
isDirty = true;
}
uint8_t _accentLevel = AinAccentLevel.read_u16() >> (16 - POT_RESOLUTION);
if (_accentLevel != accentLevel) {
accentLevel = _accentLevel;
SpiSendParams(CMD_ACCENT_LEVEL, accentLevel);
isDirty = true;
}
Thread::wait(POLLING_POTS_WAIT);
}
}
//------------------------------------------------------------------------
// Main routine
//------------------------------------------------------------------------
int main()
{
#if (UART_TRACE)
printf("*** BaseMachine UI Controller ***\r\n");
#endif
//--------------------------------------------------------------------
// Setup Devices
//
gLCD.set_spi_frequency(SPI2_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 SPI Master
//
SpiMasterCs = 1;
SpiMaster.format(16, 0);
SpiMaster.frequency(SPI1_RATE);
stepChangeInterrupt.fall(&updateStep);
//--------------------------------------------------------------------
// 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());
//--------------------------------------------------------------------
// Initialize threads
//
Thread thPollingPots(pollingPots);
//--------------------------------------------------------------------
// Synchronize with Slave
//
Thread::wait(100);
SpiSendAllParams();
//--------------------------------------------------------------------
// Main loop
//
for (;;) {
// Polling Devices
/*
if (UImode != 2) {
pollingPots();
}
*/
pollingRotEncs();
pollingPins();
// Recieve playing step from SPI slave
if (isStepChanged) {
uint16_t recievedVal = SpiSendParams(CMD_RCV_PLAYING_STEP, 0x55); // Send dummy data
playingStep = (uint8_t)(recievedVal & 0xff);
isStepChanged = false;
isDirty = true;
}
// Display
/*
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);
isDirty = false;
}
/*
}
*/
}
}
