@@ -37,10 +37,10 @@ struct OpenItem : MenuItem { | |||||
struct FileChoice : ChoiceButton { | struct FileChoice : ChoiceButton { | ||||
void onAction() { | void onAction() { | ||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
{ | { | ||||
MenuItem *newItem = new NewItem(); | MenuItem *newItem = new NewItem(); | ||||
newItem->text = "New"; | newItem->text = "New"; | ||||
@@ -58,8 +58,6 @@ struct FileChoice : ChoiceButton { | |||||
saveAsItem->text = "Save As"; | saveAsItem->text = "Save As"; | ||||
menu->pushChild(saveAsItem); | menu->pushChild(saveAsItem); | ||||
} | } | ||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
} | } | ||||
}; | }; | ||||
@@ -73,8 +71,7 @@ struct SampleRateItem : MenuItem { | |||||
struct SampleRateChoice : ChoiceButton { | struct SampleRateChoice : ChoiceButton { | ||||
void onAction() { | void onAction() { | ||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
@@ -86,9 +83,6 @@ struct SampleRateChoice : ChoiceButton { | |||||
item->sampleRate = sampleRates[i]; | item->sampleRate = sampleRates[i]; | ||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
} | } | ||||
void step() { | void step() { | ||||
text = stringf("%.0f Hz", gSampleRate); | text = stringf("%.0f Hz", gSampleRate); | ||||
@@ -116,7 +110,6 @@ Toolbar::Toolbar() { | |||||
SampleRateChoice *srChoice = new SampleRateChoice(); | SampleRateChoice *srChoice = new SampleRateChoice(); | ||||
srChoice->box.pos = Vec(xPos, margin); | srChoice->box.pos = Vec(xPos, margin); | ||||
srChoice->box.size.x = 100; | srChoice->box.size.x = 100; | ||||
srChoice->text = ""; | |||||
addChild(srChoice); | addChild(srChoice); | ||||
xPos += srChoice->box.size.x; | xPos += srChoice->box.size.x; | ||||
} | } | ||||
@@ -300,9 +300,9 @@ struct AudioItem : MenuItem { | |||||
struct AudioChoice : ChoiceButton { | struct AudioChoice : ChoiceButton { | ||||
AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
void onAction() { | void onAction() { | ||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | |||||
int deviceCount = audioInterface->getDeviceCount(); | int deviceCount = audioInterface->getDeviceCount(); | ||||
{ | { | ||||
@@ -319,8 +319,6 @@ struct AudioChoice : ChoiceButton { | |||||
audioItem->text = audioInterface->getDeviceName(deviceId); | audioItem->text = audioInterface->getDeviceName(deviceId); | ||||
menu->pushChild(audioItem); | menu->pushChild(audioItem); | ||||
} | } | ||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
} | } | ||||
void step() { | void step() { | ||||
std::string name = audioInterface->getDeviceName(audioInterface->deviceId); | std::string name = audioInterface->getDeviceName(audioInterface->deviceId); | ||||
@@ -340,9 +338,9 @@ struct SampleRateItem : MenuItem { | |||||
struct SampleRateChoice : ChoiceButton { | struct SampleRateChoice : ChoiceButton { | ||||
AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
void onAction() { | void onAction() { | ||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | |||||
const float sampleRates[6] = {44100, 48000, 88200, 96000, 176400, 192000}; | const float sampleRates[6] = {44100, 48000, 88200, 96000, 176400, 192000}; | ||||
int sampleRatesLen = sizeof(sampleRates) / sizeof(sampleRates[0]); | int sampleRatesLen = sizeof(sampleRates) / sizeof(sampleRates[0]); | ||||
@@ -353,9 +351,6 @@ struct SampleRateChoice : ChoiceButton { | |||||
item->text = stringf("%.0f Hz", sampleRates[i]); | item->text = stringf("%.0f Hz", sampleRates[i]); | ||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
} | } | ||||
void step() { | void step() { | ||||
this->text = stringf("%.0f Hz", audioInterface->sampleRate); | this->text = stringf("%.0f Hz", audioInterface->sampleRate); | ||||
@@ -374,9 +369,9 @@ struct BlockSizeItem : MenuItem { | |||||
struct BlockSizeChoice : ChoiceButton { | struct BlockSizeChoice : ChoiceButton { | ||||
AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
void onAction() { | void onAction() { | ||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | |||||
const int blockSizes[] = {64, 128, 256, 512, 1024, 2048, 4096}; | const int blockSizes[] = {64, 128, 256, 512, 1024, 2048, 4096}; | ||||
int blockSizesLen = sizeof(blockSizes) / sizeof(blockSizes[0]); | int blockSizesLen = sizeof(blockSizes) / sizeof(blockSizes[0]); | ||||
@@ -387,9 +382,6 @@ struct BlockSizeChoice : ChoiceButton { | |||||
item->text = stringf("%d", blockSizes[i]); | item->text = stringf("%d", blockSizes[i]); | ||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
} | } | ||||
void step() { | void step() { | ||||
this->text = stringf("%d", audioInterface->blockSize); | this->text = stringf("%d", audioInterface->blockSize); | ||||
@@ -423,7 +415,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||||
AudioChoice *choice = new AudioChoice(); | AudioChoice *choice = new AudioChoice(); | ||||
choice->audioInterface = dynamic_cast<AudioInterface*>(module); | choice->audioInterface = dynamic_cast<AudioInterface*>(module); | ||||
choice->box.pos = Vec(margin, yPos); | choice->box.pos = Vec(margin, yPos); | ||||
choice->box.size.x = box.size.x - 10; | |||||
choice->box.size.x = box.size.x - 2*margin; | |||||
addChild(choice); | addChild(choice); | ||||
yPos += choice->box.size.y + margin; | yPos += choice->box.size.y + margin; | ||||
} | } | ||||
@@ -438,7 +430,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||||
SampleRateChoice *choice = new SampleRateChoice(); | SampleRateChoice *choice = new SampleRateChoice(); | ||||
choice->audioInterface = dynamic_cast<AudioInterface*>(module); | choice->audioInterface = dynamic_cast<AudioInterface*>(module); | ||||
choice->box.pos = Vec(margin, yPos); | choice->box.pos = Vec(margin, yPos); | ||||
choice->box.size.x = box.size.x - 10; | |||||
choice->box.size.x = box.size.x - 2*margin; | |||||
addChild(choice); | addChild(choice); | ||||
yPos += choice->box.size.y + margin; | yPos += choice->box.size.y + margin; | ||||
} | } | ||||
@@ -453,7 +445,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||||
BlockSizeChoice *choice = new BlockSizeChoice(); | BlockSizeChoice *choice = new BlockSizeChoice(); | ||||
choice->audioInterface = dynamic_cast<AudioInterface*>(module); | choice->audioInterface = dynamic_cast<AudioInterface*>(module); | ||||
choice->box.pos = Vec(margin, yPos); | choice->box.pos = Vec(margin, yPos); | ||||
choice->box.size.x = box.size.x - 10; | |||||
choice->box.size.x = box.size.x - 2*margin; | |||||
addChild(choice); | addChild(choice); | ||||
yPos += choice->box.size.y + margin; | yPos += choice->box.size.y + margin; | ||||
} | } | ||||
@@ -30,15 +30,23 @@ struct MidiInterface : Module { | |||||
NUM_INPUTS | NUM_INPUTS | ||||
}; | }; | ||||
enum OutputIds { | enum OutputIds { | ||||
GATE_OUTPUT, | |||||
PITCH_OUTPUT, | PITCH_OUTPUT, | ||||
GATE_OUTPUT, | |||||
MOD_OUTPUT, | |||||
PITCHWHEEL_OUTPUT, | |||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
int portId = -1; | |||||
PortMidiStream *stream = NULL; | PortMidiStream *stream = NULL; | ||||
std::list<int> notes; | std::list<int> notes; | ||||
/** Filter MIDI channel | |||||
-1 means all MIDI channels | |||||
*/ | |||||
int channel = -1; | |||||
bool pedal = false; | bool pedal = false; | ||||
int note = 60; // C4, most modules should use 261.626 Hz | int note = 60; // C4, most modules should use 261.626 Hz | ||||
int mod = 0; | |||||
int pitchWheel = 64; | int pitchWheel = 64; | ||||
bool retrigger = false; | bool retrigger = false; | ||||
bool retriggered = false; | bool retriggered = false; | ||||
@@ -62,6 +70,8 @@ MidiInterface::MidiInterface() { | |||||
inputs.resize(NUM_INPUTS); | inputs.resize(NUM_INPUTS); | ||||
outputs.resize(NUM_OUTPUTS); | outputs.resize(NUM_OUTPUTS); | ||||
midiInit(); | midiInit(); | ||||
printf("<<<%d>>>\n", getPortCount()); | |||||
} | } | ||||
MidiInterface::~MidiInterface() { | MidiInterface::~MidiInterface() { | ||||
@@ -77,6 +87,9 @@ void MidiInterface::step() { | |||||
} | } | ||||
} | } | ||||
if (outputs[PITCH_OUTPUT]) { | |||||
*outputs[PITCH_OUTPUT] = ((note - 64)) / 12.0; | |||||
} | |||||
if (outputs[GATE_OUTPUT]) { | if (outputs[GATE_OUTPUT]) { | ||||
bool gate = pedal || !notes.empty(); | bool gate = pedal || !notes.empty(); | ||||
if (retrigger && retriggered) { | if (retrigger && retriggered) { | ||||
@@ -85,8 +98,11 @@ void MidiInterface::step() { | |||||
} | } | ||||
*outputs[GATE_OUTPUT] = gate ? 5.0 : 0.0; | *outputs[GATE_OUTPUT] = gate ? 5.0 : 0.0; | ||||
} | } | ||||
if (outputs[PITCH_OUTPUT]) { | |||||
*outputs[PITCH_OUTPUT] = ((note - 64) + 2.0*(pitchWheel - 64) / 64.0) / 12.0; | |||||
if (outputs[MOD_OUTPUT]) { | |||||
*outputs[MOD_OUTPUT] = mod; | |||||
} | |||||
if (outputs[PITCHWHEEL_OUTPUT]) { | |||||
*outputs[PITCHWHEEL_OUTPUT] = (pitchWheel - 64) / 64.0 / 12.0; | |||||
} | } | ||||
} | } | ||||
@@ -121,6 +137,7 @@ void MidiInterface::openPort(int portId) { | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
this->portId = portId; | |||||
} | } | ||||
void MidiInterface::pressNote(int note) { | void MidiInterface::pressNote(int note) { | ||||
@@ -202,9 +219,9 @@ struct MidiItem : MenuItem { | |||||
struct MidiChoice : ChoiceButton { | struct MidiChoice : ChoiceButton { | ||||
MidiInterface *midiInterface; | MidiInterface *midiInterface; | ||||
void onAction() { | void onAction() { | ||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | |||||
int portCount = midiInterface->getPortCount(); | int portCount = midiInterface->getPortCount(); | ||||
{ | { | ||||
@@ -221,8 +238,45 @@ struct MidiChoice : ChoiceButton { | |||||
midiItem->text = midiInterface->getPortName(portId); | midiItem->text = midiInterface->getPortName(portId); | ||||
menu->pushChild(midiItem); | menu->pushChild(midiItem); | ||||
} | } | ||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
} | |||||
void step() { | |||||
std::string name = midiInterface->getPortName(midiInterface->portId); | |||||
text = name.empty() ? "(no device)" : ellipsize(name, 14); | |||||
} | |||||
}; | |||||
struct ChannelItem : MenuItem { | |||||
MidiInterface *midiInterface; | |||||
int channel; | |||||
void onAction() { | |||||
midiInterface->channel = channel; | |||||
} | |||||
}; | |||||
struct ChannelChoice : ChoiceButton { | |||||
MidiInterface *midiInterface; | |||||
void onAction() { | |||||
Menu *menu = gScene->createMenu(); | |||||
menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); | |||||
menu->box.size.x = box.size.x; | |||||
{ | |||||
ChannelItem *channelItem = new ChannelItem(); | |||||
channelItem->midiInterface = midiInterface; | |||||
channelItem->channel = -1; | |||||
channelItem->text = "All"; | |||||
menu->pushChild(channelItem); | |||||
} | |||||
for (int channel = 0; channel < 16; channel++) { | |||||
ChannelItem *channelItem = new ChannelItem(); | |||||
channelItem->midiInterface = midiInterface; | |||||
channelItem->channel = channel; | |||||
channelItem->text = stringf("%d", channel + 1); | |||||
menu->pushChild(channelItem); | |||||
} | |||||
} | |||||
void step() { | |||||
text = (midiInterface->channel >= 0) ? stringf("%d", midiInterface->channel + 1) : "All"; | |||||
} | } | ||||
}; | }; | ||||
@@ -239,42 +293,52 @@ MidiInterfaceWidget::MidiInterfaceWidget() { | |||||
} | } | ||||
float margin = 5; | float margin = 5; | ||||
float labelHeight = 15; | |||||
float yPos = margin; | float yPos = margin; | ||||
{ | { | ||||
Label *label = new Label(); | Label *label = new Label(); | ||||
label->box.pos = Vec(margin, yPos); | label->box.pos = Vec(margin, yPos); | ||||
label->text = "MIDI Interface"; | |||||
label->text = "MIDI device"; | |||||
addChild(label); | addChild(label); | ||||
yPos += label->box.size.y + margin; | |||||
} | |||||
yPos += labelHeight + margin; | |||||
{ | |||||
MidiChoice *midiChoice = new MidiChoice(); | MidiChoice *midiChoice = new MidiChoice(); | ||||
midiChoice->midiInterface = dynamic_cast<MidiInterface*>(module); | midiChoice->midiInterface = dynamic_cast<MidiInterface*>(module); | ||||
midiChoice->text = "MIDI device"; | |||||
midiChoice->box.pos = Vec(margin, yPos); | midiChoice->box.pos = Vec(margin, yPos); | ||||
midiChoice->box.size.x = box.size.x - 10; | midiChoice->box.size.x = box.size.x - 10; | ||||
addChild(midiChoice); | addChild(midiChoice); | ||||
yPos += midiChoice->box.size.y + margin; | yPos += midiChoice->box.size.y + margin; | ||||
} | } | ||||
{ | |||||
Label *label = new Label(); | |||||
label->box.pos = Vec(margin, yPos); | |||||
label->text = "MIDI channel"; | |||||
addChild(label); | |||||
yPos += labelHeight + margin; | |||||
ChannelChoice *channelChoice = new ChannelChoice(); | |||||
channelChoice->midiInterface = dynamic_cast<MidiInterface*>(module); | |||||
channelChoice->box.pos = Vec(margin, yPos); | |||||
channelChoice->box.size.x = box.size.x - 10; | |||||
addChild(channelChoice); | |||||
yPos += channelChoice->box.size.y + margin; | |||||
} | |||||
yPos += 5; | yPos += 5; | ||||
addOutput(createOutput<PJ3410Port>(Vec(20, yPos), module, MidiInterface::PITCH_OUTPUT)); | addOutput(createOutput<PJ3410Port>(Vec(20, yPos), module, MidiInterface::PITCH_OUTPUT)); | ||||
addOutput(createOutput<PJ3410Port>(Vec(70, yPos), module, MidiInterface::GATE_OUTPUT)); | |||||
yPos += 25 + margin; | |||||
yPos += 37 + margin; | |||||
{ | |||||
Label *pitchLabel = new Label(); | |||||
pitchLabel->box.pos = Vec(25-12, yPos); | |||||
pitchLabel->text = "Pitch"; | |||||
addChild(pitchLabel); | |||||
yPos += 5; | |||||
addOutput(createOutput<PJ3410Port>(Vec(20, yPos), module, MidiInterface::GATE_OUTPUT)); | |||||
yPos += 37 + margin; | |||||
Label *gateLabel = new Label(); | |||||
gateLabel->box.pos = Vec(75-12, yPos); | |||||
gateLabel->text = "Gate"; | |||||
addChild(gateLabel); | |||||
yPos += 5; | |||||
addOutput(createOutput<PJ3410Port>(Vec(20, yPos), module, MidiInterface::MOD_OUTPUT)); | |||||
yPos += 37 + margin; | |||||
yPos += pitchLabel->box.size.y + margin; | |||||
} | |||||
yPos += 5; | |||||
addOutput(createOutput<PJ3410Port>(Vec(20, yPos), module, MidiInterface::PITCHWHEEL_OUTPUT)); | |||||
yPos += 37 + margin; | |||||
} | } |