| @@ -12,7 +12,7 @@ namespace rack { | |||||
| namespace core { | namespace core { | ||||
| template <int NUM_AUDIO_OUTPUTS, int NUM_AUDIO_INPUTS> | |||||
| template <int NUM_AUDIO_INPUTS, int NUM_AUDIO_OUTPUTS> | |||||
| struct AudioInterfacePort : audio::Port { | struct AudioInterfacePort : audio::Port { | ||||
| // std::mutex engineMutex; | // std::mutex engineMutex; | ||||
| // std::condition_variable engineCv; | // 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 { | struct AudioInterface : Module { | ||||
| enum ParamIds { | enum ParamIds { | ||||
| NUM_PARAMS | NUM_PARAMS | ||||
| @@ -124,7 +124,7 @@ struct AudioInterface : Module { | |||||
| NUM_LIGHTS | NUM_LIGHTS | ||||
| }; | }; | ||||
| AudioInterfacePort<NUM_AUDIO_OUTPUTS, NUM_AUDIO_INPUTS> port; | |||||
| AudioInterfacePort<NUM_AUDIO_INPUTS, NUM_AUDIO_OUTPUTS> port; | |||||
| // int lastSampleRate = 0; | // int lastSampleRate = 0; | ||||
| // int lastNumOutputs = -1; | // int lastNumOutputs = -1; | ||||
| // int lastNumInputs = -1; | // int lastNumInputs = -1; | ||||
| @@ -138,7 +138,11 @@ struct AudioInterface : Module { | |||||
| AudioInterface() { | AudioInterface() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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; | port.module = this; | ||||
| onSampleRateChange(); | 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 { | struct AudioInterfaceWidget : ModuleWidget { | ||||
| typedef AudioInterface<NUM_AUDIO_OUTPUTS, NUM_AUDIO_INPUTS> TAudioInterface; | |||||
| typedef AudioInterface<NUM_AUDIO_INPUTS, NUM_AUDIO_OUTPUTS> TAudioInterface; | |||||
| AudioInterfaceWidget(TAudioInterface* module) { | AudioInterfaceWidget(TAudioInterface* module) { | ||||
| setModule(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"))); | setPanel(APP->window->loadSvg(asset::system("res/Core/AudioInterface.svg"))); | ||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
| @@ -337,7 +341,7 @@ struct AudioInterfaceWidget : ModuleWidget { | |||||
| audioWidget->setAudioPort(module ? &module->port : NULL); | audioWidget->setAudioPort(module ? &module->port : NULL); | ||||
| addChild(audioWidget); | 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"))); | setPanel(APP->window->loadSvg(asset::system("res/Core/AudioInterface16.svg"))); | ||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | ||||
| @@ -7,14 +7,14 @@ namespace core { | |||||
| struct BlankModule : Module { | struct BlankModule : Module { | ||||
| int width = 4; | |||||
| int width = 10; | |||||
| /** Legacy for <=v1 patches */ | /** Legacy for <=v1 patches */ | ||||
| void fromJson(json_t* rootJ) override { | void fromJson(json_t* rootJ) override { | ||||
| Module::fromJson(rootJ); | Module::fromJson(rootJ); | ||||
| json_t* widthJ = json_object_get(rootJ, "width"); | json_t* widthJ = json_object_get(rootJ, "width"); | ||||
| if (widthJ) | if (widthJ) | ||||
| width = json_number_value(widthJ) / RACK_GRID_WIDTH; | |||||
| width = std::round(json_number_value(widthJ) / RACK_GRID_WIDTH); | |||||
| } | } | ||||
| json_t* dataToJson() override { | json_t* dataToJson() override { | ||||
| @@ -58,6 +58,7 @@ struct ModuleResizeHandle : OpaqueWidget { | |||||
| bool right = false; | bool right = false; | ||||
| Vec dragPos; | Vec dragPos; | ||||
| Rect originalBox; | Rect originalBox; | ||||
| BlankModule* module; | |||||
| ModuleResizeHandle() { | ModuleResizeHandle() { | ||||
| box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); | 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)) { | if (!APP->scene->rack->requestModulePos(mw, newBox.pos)) { | ||||
| mw->box = oldBox; | mw->box = oldBox; | ||||
| } | } | ||||
| module->width = std::round(mw->box.size.x / RACK_GRID_WIDTH); | |||||
| } | } | ||||
| void draw(const DrawArgs& args) override { | void draw(const DrawArgs& args) override { | ||||
| @@ -122,7 +124,7 @@ struct BlankWidget : ModuleWidget { | |||||
| Widget* rightHandle; | Widget* rightHandle; | ||||
| BlankPanel* blankPanel; | BlankPanel* blankPanel; | ||||
| BlankWidget(Module* module) { | |||||
| BlankWidget(BlankModule* module) { | |||||
| setModule(module); | setModule(module); | ||||
| box.size = Vec(RACK_GRID_WIDTH * 10, RACK_GRID_HEIGHT); | box.size = Vec(RACK_GRID_WIDTH * 10, RACK_GRID_HEIGHT); | ||||
| @@ -130,10 +132,13 @@ struct BlankWidget : ModuleWidget { | |||||
| addChild(blankPanel); | addChild(blankPanel); | ||||
| ModuleResizeHandle* leftHandle = new ModuleResizeHandle; | ModuleResizeHandle* leftHandle = new ModuleResizeHandle; | ||||
| leftHandle->module = module; | |||||
| addChild(leftHandle); | |||||
| ModuleResizeHandle* rightHandle = new ModuleResizeHandle; | ModuleResizeHandle* rightHandle = new ModuleResizeHandle; | ||||
| rightHandle->right = true; | rightHandle->right = true; | ||||
| this->rightHandle = rightHandle; | this->rightHandle = rightHandle; | ||||
| addChild(leftHandle); | |||||
| rightHandle->module = module; | |||||
| addChild(rightHandle); | addChild(rightHandle); | ||||
| addChild(createWidget<ScrewSilver>(Vec(15, 0))); | addChild(createWidget<ScrewSilver>(Vec(15, 0))); | ||||
| @@ -145,7 +150,10 @@ struct BlankWidget : ModuleWidget { | |||||
| } | } | ||||
| void step() override { | 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; | blankPanel->box.size = box.size; | ||||
| topRightScrew->box.pos.x = box.size.x - 30; | 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 | } // namespace core | ||||
| @@ -54,6 +54,8 @@ struct CV_CC : Module { | |||||
| CV_CC() { | CV_CC() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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(); | onReset(); | ||||
| } | } | ||||
| @@ -81,6 +81,8 @@ struct CV_Gate : Module { | |||||
| CV_Gate() { | CV_Gate() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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(); | onReset(); | ||||
| } | } | ||||
| @@ -48,6 +48,18 @@ struct CV_MIDI : Module { | |||||
| CV_MIDI() { | CV_MIDI() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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(); | onReset(); | ||||
| } | } | ||||
| @@ -28,6 +28,8 @@ struct MIDI_CC : Module { | |||||
| MIDI_CC() { | MIDI_CC() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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++) { | for (int i = 0; i < 16; i++) { | ||||
| valueFilters[i].setTau(1 / 30.f); | valueFilters[i].setTau(1 / 30.f); | ||||
| } | } | ||||
| @@ -31,6 +31,8 @@ struct MIDI_Gate : Module { | |||||
| MIDI_Gate() { | MIDI_Gate() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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(); | onReset(); | ||||
| } | } | ||||
| @@ -7,6 +7,7 @@ namespace core { | |||||
| struct NotesModule : Module { | struct NotesModule : Module { | ||||
| std::string text; | std::string text; | ||||
| bool dirty = false; | |||||
| /** Legacy for <=v1 patches */ | /** Legacy for <=v1 patches */ | ||||
| void fromJson(json_t* rootJ) override { | void fromJson(json_t* rootJ) override { | ||||
| @@ -14,11 +15,12 @@ struct NotesModule : Module { | |||||
| json_t* textJ = json_object_get(rootJ, "text"); | json_t* textJ = json_object_get(rootJ, "text"); | ||||
| if (textJ) | if (textJ) | ||||
| text = json_string_value(textJ); | text = json_string_value(textJ); | ||||
| dirty = true; | |||||
| } | } | ||||
| json_t* dataToJson() override { | json_t* dataToJson() override { | ||||
| json_t* rootJ = json_object(); | 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; | return rootJ; | ||||
| } | } | ||||
| @@ -26,15 +28,32 @@ struct NotesModule : Module { | |||||
| json_t* textJ = json_object_get(rootJ, "text"); | json_t* textJ = json_object_get(rootJ, "text"); | ||||
| if (textJ) | if (textJ) | ||||
| text = json_string_value(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 { | 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); | setModule(module); | ||||
| setPanel(APP->window->loadSvg(asset::system("res/Core/Notes.svg"))); | 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(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))); | 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->box.size = mm2px(Vec(74.480, 102.753)); | ||||
| textField->multiline = true; | textField->multiline = true; | ||||
| textField->module = dynamic_cast<NotesModule*>(module); | |||||
| addChild(textField); | addChild(textField); | ||||
| } | } | ||||
| }; | }; | ||||
| Model* modelNotes = createModel<Module, NotesWidget>("Notes"); | |||||
| Model* modelNotes = createModel<NotesModule, NotesWidget>("Notes"); | |||||
| } // namespace core | } // namespace core | ||||