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