@@ -12,7 +12,7 @@ namespace rack { | |||
namespace core { | |||
template <int NUM_AUDIO_OUTPUTS, int NUM_AUDIO_INPUTS> | |||
template <int NUM_AUDIO_INPUTS, int NUM_AUDIO_OUTPUTS> | |||
struct AudioInterfacePort : audio::Port { | |||
// std::mutex engineMutex; | |||
// std::condition_variable engineCv; | |||
@@ -105,7 +105,7 @@ struct AudioInterfacePort : audio::Port { | |||
}; | |||
template <int NUM_AUDIO_OUTPUTS, int NUM_AUDIO_INPUTS> | |||
template <int NUM_AUDIO_INPUTS, int NUM_AUDIO_OUTPUTS> | |||
struct AudioInterface : Module { | |||
enum ParamIds { | |||
NUM_PARAMS | |||
@@ -124,7 +124,7 @@ struct AudioInterface : Module { | |||
NUM_LIGHTS | |||
}; | |||
AudioInterfacePort<NUM_AUDIO_OUTPUTS, NUM_AUDIO_INPUTS> port; | |||
AudioInterfacePort<NUM_AUDIO_INPUTS, NUM_AUDIO_OUTPUTS> port; | |||
// int lastSampleRate = 0; | |||
// int lastNumOutputs = -1; | |||
// int lastNumInputs = -1; | |||
@@ -138,7 +138,11 @@ struct AudioInterface : Module { | |||
AudioInterface() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
port.maxChannels = std::max(NUM_AUDIO_OUTPUTS, NUM_AUDIO_INPUTS); | |||
for (int i = 0; i < NUM_AUDIO_INPUTS; i++) | |||
configInput(AUDIO_INPUTS + i, string::f("To device %d", i + 1)); | |||
for (int i = 0; i < NUM_AUDIO_OUTPUTS; i++) | |||
configOutput(AUDIO_OUTPUTS + i, string::f("From device %d", i + 1)); | |||
port.maxChannels = std::max(NUM_AUDIO_INPUTS, NUM_AUDIO_OUTPUTS); | |||
port.module = this; | |||
onSampleRateChange(); | |||
} | |||
@@ -290,14 +294,14 @@ struct PrimaryModuleItem : MenuItem { | |||
}; | |||
template <int NUM_AUDIO_OUTPUTS, int NUM_AUDIO_INPUTS> | |||
template <int NUM_AUDIO_INPUTS, int NUM_AUDIO_OUTPUTS> | |||
struct AudioInterfaceWidget : ModuleWidget { | |||
typedef AudioInterface<NUM_AUDIO_OUTPUTS, NUM_AUDIO_INPUTS> TAudioInterface; | |||
typedef AudioInterface<NUM_AUDIO_INPUTS, NUM_AUDIO_OUTPUTS> TAudioInterface; | |||
AudioInterfaceWidget(TAudioInterface* module) { | |||
setModule(module); | |||
if (NUM_AUDIO_OUTPUTS == 8 && NUM_AUDIO_INPUTS == 8) { | |||
if (NUM_AUDIO_INPUTS == 8 && NUM_AUDIO_OUTPUTS == 8) { | |||
setPanel(APP->window->loadSvg(asset::system("res/Core/AudioInterface.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
@@ -337,7 +341,7 @@ struct AudioInterfaceWidget : ModuleWidget { | |||
audioWidget->setAudioPort(module ? &module->port : NULL); | |||
addChild(audioWidget); | |||
} | |||
else if (NUM_AUDIO_OUTPUTS == 16 && NUM_AUDIO_INPUTS == 16) { | |||
else if (NUM_AUDIO_INPUTS == 16 && NUM_AUDIO_OUTPUTS == 16) { | |||
setPanel(APP->window->loadSvg(asset::system("res/Core/AudioInterface16.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
@@ -7,14 +7,14 @@ namespace core { | |||
struct BlankModule : Module { | |||
int width = 4; | |||
int width = 10; | |||
/** Legacy for <=v1 patches */ | |||
void fromJson(json_t* rootJ) override { | |||
Module::fromJson(rootJ); | |||
json_t* widthJ = json_object_get(rootJ, "width"); | |||
if (widthJ) | |||
width = json_number_value(widthJ) / RACK_GRID_WIDTH; | |||
width = std::round(json_number_value(widthJ) / RACK_GRID_WIDTH); | |||
} | |||
json_t* dataToJson() override { | |||
@@ -58,6 +58,7 @@ struct ModuleResizeHandle : OpaqueWidget { | |||
bool right = false; | |||
Vec dragPos; | |||
Rect originalBox; | |||
BlankModule* module; | |||
ModuleResizeHandle() { | |||
box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); | |||
@@ -100,6 +101,7 @@ struct ModuleResizeHandle : OpaqueWidget { | |||
if (!APP->scene->rack->requestModulePos(mw, newBox.pos)) { | |||
mw->box = oldBox; | |||
} | |||
module->width = std::round(mw->box.size.x / RACK_GRID_WIDTH); | |||
} | |||
void draw(const DrawArgs& args) override { | |||
@@ -122,7 +124,7 @@ struct BlankWidget : ModuleWidget { | |||
Widget* rightHandle; | |||
BlankPanel* blankPanel; | |||
BlankWidget(Module* module) { | |||
BlankWidget(BlankModule* module) { | |||
setModule(module); | |||
box.size = Vec(RACK_GRID_WIDTH * 10, RACK_GRID_HEIGHT); | |||
@@ -130,10 +132,13 @@ struct BlankWidget : ModuleWidget { | |||
addChild(blankPanel); | |||
ModuleResizeHandle* leftHandle = new ModuleResizeHandle; | |||
leftHandle->module = module; | |||
addChild(leftHandle); | |||
ModuleResizeHandle* rightHandle = new ModuleResizeHandle; | |||
rightHandle->right = true; | |||
this->rightHandle = rightHandle; | |||
addChild(leftHandle); | |||
rightHandle->module = module; | |||
addChild(rightHandle); | |||
addChild(createWidget<ScrewSilver>(Vec(15, 0))); | |||
@@ -145,7 +150,10 @@ struct BlankWidget : ModuleWidget { | |||
} | |||
void step() override { | |||
// TODO Update from module | |||
BlankModule* module = dynamic_cast<BlankModule*>(this->module); | |||
if (module) { | |||
box.size.x = module->width * RACK_GRID_WIDTH; | |||
} | |||
blankPanel->box.size = box.size; | |||
topRightScrew->box.pos.x = box.size.x - 30; | |||
@@ -162,7 +170,7 @@ struct BlankWidget : ModuleWidget { | |||
}; | |||
Model* modelBlank = createModel<Module, BlankWidget>("Blank"); | |||
Model* modelBlank = createModel<BlankModule, BlankWidget>("Blank"); | |||
} // namespace core | |||
@@ -54,6 +54,8 @@ struct CV_CC : Module { | |||
CV_CC() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
for (int i = 0; i < 16; i++) | |||
configInput(CC_INPUTS + i, string::f("Cell %d", i + 1)); | |||
onReset(); | |||
} | |||
@@ -81,6 +81,8 @@ struct CV_Gate : Module { | |||
CV_Gate() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
for (int i = 0; i < 16; i++) | |||
configInput(GATE_INPUTS + i, string::f("Cell %d", i + 1)); | |||
onReset(); | |||
} | |||
@@ -48,6 +48,18 @@ struct CV_MIDI : Module { | |||
CV_MIDI() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
configInput(PITCH_INPUT, "V/oct"); | |||
configInput(GATE_INPUT, "Gate"); | |||
configInput(VEL_INPUT, "Velocity"); | |||
configInput(AFT_INPUT, "Aftertouch"); | |||
configInput(PW_INPUT, "Pitch wheel"); | |||
configInput(MW_INPUT, "Mod wheel"); | |||
configInput(CLK_INPUT, "Clock"); | |||
configInput(VOL_INPUT, "Volume"); | |||
configInput(PAN_INPUT, "Pan"); | |||
configInput(START_INPUT, "Start"); | |||
configInput(STOP_INPUT, "Stop"); | |||
configInput(CONTINUE_INPUT, "Continue"); | |||
onReset(); | |||
} | |||
@@ -28,6 +28,8 @@ struct MIDI_CC : Module { | |||
MIDI_CC() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
for (int i = 0; i < 16; i++) | |||
configOutput(CC_OUTPUT + i, string::f("Cell %d", i + 1)); | |||
for (int i = 0; i < 16; i++) { | |||
valueFilters[i].setTau(1 / 30.f); | |||
} | |||
@@ -31,6 +31,8 @@ struct MIDI_Gate : Module { | |||
MIDI_Gate() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
for (int i = 0; i < 16; i++) | |||
configOutput(TRIG_OUTPUT + i, string::f("Cell %d", i + 1)); | |||
onReset(); | |||
} | |||
@@ -7,6 +7,7 @@ namespace core { | |||
struct NotesModule : Module { | |||
std::string text; | |||
bool dirty = false; | |||
/** Legacy for <=v1 patches */ | |||
void fromJson(json_t* rootJ) override { | |||
@@ -14,11 +15,12 @@ struct NotesModule : Module { | |||
json_t* textJ = json_object_get(rootJ, "text"); | |||
if (textJ) | |||
text = json_string_value(textJ); | |||
dirty = true; | |||
} | |||
json_t* dataToJson() override { | |||
json_t* rootJ = json_object(); | |||
json_object_set_new(rootJ, "text", json_string(text.c_str())); | |||
json_object_set_new(rootJ, "text", json_stringn(text.c_str(), text.size())); | |||
return rootJ; | |||
} | |||
@@ -26,15 +28,32 @@ struct NotesModule : Module { | |||
json_t* textJ = json_object_get(rootJ, "text"); | |||
if (textJ) | |||
text = json_string_value(textJ); | |||
dirty = true; | |||
} | |||
}; | |||
struct NotesTextField : LedDisplayTextField { | |||
NotesModule* module; | |||
void step() override { | |||
TextField::step(); | |||
if (module && module->dirty) { | |||
setText(module->text); | |||
module->dirty = false; | |||
} | |||
} | |||
void onChange(const event::Change& e) override { | |||
if (module) | |||
module->text = text; | |||
} | |||
}; | |||
struct NotesWidget : ModuleWidget { | |||
// TODO Subclass this or something and keep `module->text` in sync with the text field's string. | |||
TextField* textField; | |||
NotesTextField* textField; | |||
NotesWidget(Module* module) { | |||
NotesWidget(NotesModule* module) { | |||
setModule(module); | |||
setPanel(APP->window->loadSvg(asset::system("res/Core/Notes.svg"))); | |||
@@ -43,15 +62,16 @@ struct NotesWidget : ModuleWidget { | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||
textField = createWidget<LedDisplayTextField>(mm2px(Vec(3.39962, 14.8373))); | |||
textField = createWidget<NotesTextField>(mm2px(Vec(3.39962, 14.8373))); | |||
textField->box.size = mm2px(Vec(74.480, 102.753)); | |||
textField->multiline = true; | |||
textField->module = dynamic_cast<NotesModule*>(module); | |||
addChild(textField); | |||
} | |||
}; | |||
Model* modelNotes = createModel<Module, NotesWidget>("Notes"); | |||
Model* modelNotes = createModel<NotesModule, NotesWidget>("Notes"); | |||
} // namespace core | |||