| @@ -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 | |||