Browse Source

Modify ports to support Component Library

tags/v0.3.0
Andrew Belt 7 years ago
parent
commit
4c891085fe
12 changed files with 170 additions and 123 deletions
  1. +3
    -0
      .gitmodules
  2. +1
    -0
      ext/nanosvg
  3. +4
    -4
      include/rack.hpp
  4. +37
    -6
      include/rackwidgets.hpp
  5. +38
    -29
      src/core/AudioInterface.cpp
  6. +10
    -7
      src/core/MidiInterface.cpp
  7. +0
    -2
      src/core/core.hpp
  8. +0
    -7
      src/widgets/InputPort.cpp
  9. +2
    -6
      src/widgets/ModulePanel.cpp
  10. +0
    -7
      src/widgets/OutputPort.cpp
  11. +0
    -16
      src/widgets/Port.cpp
  12. +75
    -39
      src/widgets/WireWidget.cpp

+ 3
- 0
.gitmodules View File

@@ -1,3 +1,6 @@
[submodule "ext/nanovg"] [submodule "ext/nanovg"]
path = ext/nanovg path = ext/nanovg
url = https://github.com/memononen/nanovg.git url = https://github.com/memononen/nanovg.git
[submodule "ext/nanosvg"]
path = ext/nanosvg
url = https://github.com/memononen/nanosvg.git

+ 1
- 0
ext/nanosvg

@@ -0,0 +1 @@
Subproject commit dc12d90586a8ab99da0c575aafff999666aa5d55

+ 4
- 4
include/rack.hpp View File

@@ -166,18 +166,18 @@ ParamWidget *createParam(Vec pos, Module *module, int paramId, float minValue, f
return param; return param;
} }


inline
template <class TInputPort>
InputPort *createInput(Vec pos, Module *module, int inputId) { InputPort *createInput(Vec pos, Module *module, int inputId) {
InputPort *port = new InputPort();
InputPort *port = new TInputPort();
port->box.pos = pos; port->box.pos = pos;
port->module = module; port->module = module;
port->inputId = inputId; port->inputId = inputId;
return port; return port;
} }


inline
template <class TOutputPort>
OutputPort *createOutput(Vec pos, Module *module, int outputId) { OutputPort *createOutput(Vec pos, Module *module, int outputId) {
OutputPort *port = new OutputPort();
OutputPort *port = new TOutputPort();
port->box.pos = pos; port->box.pos = pos;
port->module = module; port->module = module;
port->outputId = outputId; port->outputId = outputId;


+ 37
- 6
include/rackwidgets.hpp View File

@@ -94,7 +94,6 @@ struct RackWidget : OpaqueWidget {


struct ModulePanel : TransparentWidget { struct ModulePanel : TransparentWidget {
NVGcolor backgroundColor; NVGcolor backgroundColor;
NVGcolor highlightColor;
std::string imageFilename; std::string imageFilename;
void draw(NVGcontext *vg); void draw(NVGcontext *vg);
}; };
@@ -167,7 +166,7 @@ struct MomentarySwitch : virtual Switch {
// ports // ports
//////////////////// ////////////////////


struct Port : OpaqueWidget, SpriteWidget {
struct Port : OpaqueWidget {
Module *module = NULL; Module *module = NULL;
WireWidget *connectedWire = NULL; WireWidget *connectedWire = NULL;


@@ -175,8 +174,6 @@ struct Port : OpaqueWidget, SpriteWidget {
~Port(); ~Port();
void disconnect(); void disconnect();


int type;
void drawGlow(NVGcontext *vg);
void onMouseDown(int button); void onMouseDown(int button);
void onDragEnd(); void onDragEnd();
}; };
@@ -184,7 +181,6 @@ struct Port : OpaqueWidget, SpriteWidget {
struct InputPort : Port { struct InputPort : Port {
int inputId; int inputId;


void draw(NVGcontext *vg);
void onDragStart(); void onDragStart();
void onDragDrop(Widget *origin); void onDragDrop(Widget *origin);
}; };
@@ -192,7 +188,6 @@ struct InputPort : Port {
struct OutputPort : Port { struct OutputPort : Port {
int outputId; int outputId;


void draw(NVGcontext *vg);
void onDragStart(); void onDragStart();
void onDragDrop(Widget *origin); void onDragDrop(Widget *origin);
}; };
@@ -220,5 +215,41 @@ struct Scene : OpaqueWidget {
void step(); void step();
}; };


////////////////////
// component library
////////////////////

struct PJ301M : SpriteWidget {
PJ301M() {
box.size = Vec(24, 24);
spriteOffset = Vec(-10, -10);
spriteSize = Vec(48, 48);
spriteFilename = "res/ComponentLibrary/PJ301M.png";
}
};
struct InputPortPJ301M : InputPort, PJ301M {};
struct OutputPortPJ301M: OutputPort, PJ301M {};

struct PJ3410 : SpriteWidget {
PJ3410() {
box.size = Vec(31, 31);
spriteOffset = Vec(-9, -9);
spriteSize = Vec(54, 54);
spriteFilename = "res/ComponentLibrary/PJ3410.png";
}
};
struct InputPortPJ3410 : InputPort, PJ3410 {};
struct OutputPortPJ3410: OutputPort, PJ3410 {};

struct CL1362 : SpriteWidget {
CL1362() {
box.size = Vec(33, 29);
spriteOffset = Vec(-10, -10);
spriteSize = Vec(57, 54);
spriteFilename = "res/ComponentLibrary/CL1362.png";
}
};
struct InputPortCL1362 : InputPort, CL1362 {};
struct OutputPortCL1362 : OutputPort, CL1362 {};


} // namespace rack } // namespace rack

+ 38
- 29
src/core/AudioInterface.cpp View File

@@ -45,10 +45,11 @@ struct AudioInterface : Module {
SampleRateConverter<2> inputSrc; SampleRateConverter<2> inputSrc;
SampleRateConverter<2> outputSrc; SampleRateConverter<2> outputSrc;


// in device's sample rate
DoubleRingBuffer<Frame<2>, (1<<15)> inputBuffer;
// in rack's sample rate // in rack's sample rate
DoubleRingBuffer<Frame<2>, 32> inputBuffer;
DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer; DoubleRingBuffer<Frame<2>, (1<<15)> outputBuffer;
// in device's sample rate
DoubleRingBuffer<Frame<2>, (1<<15)> inputSrcBuffer;


AudioInterface(); AudioInterface();
~AudioInterface(); ~AudioInterface();
@@ -89,29 +90,35 @@ void AudioInterface::step() {


// Get input and pass it through the sample rate converter // Get input and pass it through the sample rate converter
if (numOutputs > 0) { if (numOutputs > 0) {
Frame<2> f;
f.samples[0] = getf(inputs[AUDIO1_INPUT]) / 5.0;
f.samples[1] = getf(inputs[AUDIO2_INPUT]) / 5.0;

inputSrc.setRatio(sampleRate / gRack->sampleRate);
int inLen = 1;
int outLen = inputBuffer.capacity();
inputSrc.process((const float*) &f, &inLen, (float*) inputBuffer.endData(), &outLen);
inputBuffer.endIncr(outLen);
if (!inputBuffer.full()) {
Frame<2> f;
f.samples[0] = getf(inputs[AUDIO1_INPUT]) / 5.0;
f.samples[1] = getf(inputs[AUDIO2_INPUT]) / 5.0;
inputBuffer.push(f);
}

// Once full, sample rate convert the input
if (inputBuffer.full()) {
inputSrc.setRatio(sampleRate / gRack->sampleRate);
int inLen = inputBuffer.size();
int outLen = inputSrcBuffer.capacity();
inputSrc.process((const float*) inputBuffer.startData(), &inLen, (float*) inputSrcBuffer.endData(), &outLen);
inputBuffer.startIncr(inLen);
inputSrcBuffer.endIncr(outLen);
}
} }


// Read/write stream if we have enough input
bool streamReady = (numOutputs > 0) ? (inputBuffer.size() >= blockSize) : (outputBuffer.empty());
// Read/write stream if we have enough input, OR the output buffer is empty if we have no input
bool streamReady = (numOutputs > 0) ? (inputSrcBuffer.size() >= blockSize) : (outputBuffer.empty());
if (streamReady) { if (streamReady) {
// printf("%p\t%d\t%d\n", this, inputSrcBuffer.size(), outputBuffer.size());
PaError err; PaError err;


// Read output from input stream // Read output from input stream
// (for some reason, if you write the output stream before you read the input stream, PortAudio can segfault on Windows.) // (for some reason, if you write the output stream before you read the input stream, PortAudio can segfault on Windows.)
if (numInputs > 0) { if (numInputs > 0) {
Frame<2> *buf = new Frame<2>[blockSize]; Frame<2> *buf = new Frame<2>[blockSize];
printf("read %d\n", blockSize);
err = Pa_ReadStream(stream, (float*) buf, blockSize); err = Pa_ReadStream(stream, (float*) buf, blockSize);
printf("read done\n");
if (err) { if (err) {
// Ignore buffer underflows // Ignore buffer underflows
if (err != paInputOverflowed) { if (err != paInputOverflowed) {
@@ -131,11 +138,9 @@ void AudioInterface::step() {


// Write input to output stream // Write input to output stream
if (numOutputs > 0) { if (numOutputs > 0) {
assert(inputBuffer.size() >= blockSize);
printf("write %d\n", blockSize);
err = Pa_WriteStream(stream, (const float*) inputBuffer.startData(), blockSize);
printf("write done\n");
inputBuffer.startIncr(blockSize);
assert(inputSrcBuffer.size() >= blockSize);
err = Pa_WriteStream(stream, (const float*) inputSrcBuffer.startData(), blockSize);
inputSrcBuffer.startIncr(blockSize);
if (err) { if (err) {
// Ignore buffer underflows // Ignore buffer underflows
if (err != paOutputUnderflowed) { if (err != paOutputUnderflowed) {
@@ -241,6 +246,7 @@ void AudioInterface::closeDevice() {
// Clear buffers // Clear buffers
inputBuffer.clear(); inputBuffer.clear();
outputBuffer.clear(); outputBuffer.clear();
inputSrcBuffer.clear();
inputSrc.reset(); inputSrc.reset();
outputSrc.reset(); outputSrc.reset();
} }
@@ -355,6 +361,14 @@ struct BlockSizeChoice : ChoiceButton {
AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface()) { AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface()) {
box.size = Vec(15*8, 380); box.size = Vec(15*8, 380);


{
ModulePanel *panel = new ModulePanel();
panel->box.size = box.size;
panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90);
// panel->imageFilename = "";
addChild(panel);
}

float margin = 5; float margin = 5;
float yPos = margin; float yPos = margin;


@@ -420,8 +434,8 @@ AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface()
} }


yPos += 5; yPos += 5;
addInput(createInput(Vec(25, yPos), module, AudioInterface::AUDIO1_INPUT));
addInput(createInput(Vec(75, yPos), module, AudioInterface::AUDIO2_INPUT));
addInput(createInput<InputPortPJ3410>(Vec(20, yPos), module, AudioInterface::AUDIO1_INPUT));
addInput(createInput<InputPortPJ3410>(Vec(70, yPos), module, AudioInterface::AUDIO2_INPUT));
yPos += 35 + margin; yPos += 35 + margin;


{ {
@@ -433,12 +447,7 @@ AudioInterfaceWidget::AudioInterfaceWidget() : ModuleWidget(new AudioInterface()
} }


yPos += 5; yPos += 5;
addOutput(createOutput(Vec(25, yPos), module, AudioInterface::AUDIO1_OUTPUT));
addOutput(createOutput(Vec(75, yPos), module, AudioInterface::AUDIO2_OUTPUT));
addOutput(createOutput<OutputPortPJ3410>(Vec(20, yPos), module, AudioInterface::AUDIO1_OUTPUT));
addOutput(createOutput<OutputPortPJ3410>(Vec(70, yPos), module, AudioInterface::AUDIO2_OUTPUT));
yPos += 35 + margin; yPos += 35 + margin;
} }

void AudioInterfaceWidget::draw(NVGcontext *vg) {
bndBackground(vg, box.pos.x, box.pos.y, box.size.x, box.size.y);
ModuleWidget::draw(vg);
}

+ 10
- 7
src/core/MidiInterface.cpp View File

@@ -224,6 +224,14 @@ struct MidiChoice : ChoiceButton {
MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) { MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) {
box.size = Vec(15*8, 380); box.size = Vec(15*8, 380);


{
ModulePanel *panel = new ModulePanel();
panel->box.size = box.size;
panel->backgroundColor = nvgRGBf(0.90, 0.90, 0.90);
// panel->imageFilename = "";
addChild(panel);
}

float margin = 5; float margin = 5;
float yPos = margin; float yPos = margin;


@@ -246,8 +254,8 @@ MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) {
} }


yPos += 5; yPos += 5;
addOutput(createOutput(Vec(25, yPos), module, MidiInterface::PITCH_OUTPUT));
addOutput(createOutput(Vec(75, yPos), module, MidiInterface::GATE_OUTPUT));
addOutput(createOutput<OutputPortPJ3410>(Vec(20, yPos), module, MidiInterface::PITCH_OUTPUT));
addOutput(createOutput<OutputPortPJ3410>(Vec(70, yPos), module, MidiInterface::GATE_OUTPUT));
yPos += 25 + margin; yPos += 25 + margin;


{ {
@@ -264,8 +272,3 @@ MidiInterfaceWidget::MidiInterfaceWidget() : ModuleWidget(new MidiInterface()) {
yPos += pitchLabel->box.size.y + margin; yPos += pitchLabel->box.size.y + margin;
} }
} }

void MidiInterfaceWidget::draw(NVGcontext *vg) {
bndBackground(vg, box.pos.x, box.pos.y, box.size.x, box.size.y);
ModuleWidget::draw(vg);
}

+ 0
- 2
src/core/core.hpp View File

@@ -14,10 +14,8 @@ void midiInit();


struct AudioInterfaceWidget : ModuleWidget { struct AudioInterfaceWidget : ModuleWidget {
AudioInterfaceWidget(); AudioInterfaceWidget();
void draw(NVGcontext *vg);
}; };


struct MidiInterfaceWidget : ModuleWidget { struct MidiInterfaceWidget : ModuleWidget {
MidiInterfaceWidget(); MidiInterfaceWidget();
void draw(NVGcontext *vg);
}; };

+ 0
- 7
src/widgets/InputPort.cpp View File

@@ -3,13 +3,6 @@


namespace rack { namespace rack {


void InputPort::draw(NVGcontext *vg) {
SpriteWidget::draw(vg);
if (gRackWidget->activeWire && gRackWidget->activeWire->inputPort) {
Port::drawGlow(vg);
}
}

void InputPort::onDragStart() { void InputPort::onDragStart() {
if (connectedWire) { if (connectedWire) {
// Disconnect wire from this port, but set it as the active wire // Disconnect wire from this port, but set it as the active wire


+ 2
- 6
src/widgets/ModulePanel.cpp View File

@@ -8,12 +8,8 @@ void ModulePanel::draw(NVGcontext *vg) {
nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y);
NVGpaint paint; NVGpaint paint;


// Background gradient
Vec c = box.pos;
float length = box.size.norm();
paint = nvgRadialGradient(vg, c.x, c.y, 0.0, length, highlightColor, backgroundColor);
nvgFillPaint(vg, paint);
// nvgFillColor(vg, backgroundColor);
// Background color
nvgFillColor(vg, backgroundColor);
nvgFill(vg); nvgFill(vg);


// Background image // Background image


+ 0
- 7
src/widgets/OutputPort.cpp View File

@@ -3,13 +3,6 @@


namespace rack { namespace rack {


void OutputPort::draw(NVGcontext *vg) {
SpriteWidget::draw(vg);
if (gRackWidget->activeWire && gRackWidget->activeWire->outputPort) {
Port::drawGlow(vg);
}
}

void OutputPort::onDragStart() { void OutputPort::onDragStart() {
if (connectedWire) { if (connectedWire) {
// Disconnect wire from this port, but set it as the active wire // Disconnect wire from this port, but set it as the active wire


+ 0
- 16
src/widgets/Port.cpp View File

@@ -5,11 +5,6 @@ namespace rack {


Port::Port() { Port::Port() {
box.size = Vec(20, 20); box.size = Vec(20, 20);
spriteOffset = Vec(-18, -18);
spriteSize = Vec(56, 56);
spriteFilename = "res/port.png";

index = randomu32() % 5;
} }


Port::~Port() { Port::~Port() {
@@ -24,17 +19,6 @@ void Port::disconnect() {
} }
} }


void Port::drawGlow(NVGcontext *vg) {
Vec c = box.getCenter();
NVGcolor icol = nvgRGBAf(1, 1, 1, 0.5);
NVGcolor ocol = nvgRGBAf(1, 1, 1, 0);
NVGpaint paint = nvgRadialGradient(vg, c.x, c.y, 0, 20, icol, ocol);
nvgFillPaint(vg, paint);
nvgBeginPath(vg);
nvgRect(vg, box.pos.x - 10, box.pos.y - 10, box.size.x + 20, box.size.y + 20);
nvgFill(vg);
}

void Port::onMouseDown(int button) { void Port::onMouseDown(int button) {
if (button == 1) { if (button == 1) {
disconnect(); disconnect();


+ 75
- 39
src/widgets/WireWidget.cpp View File

@@ -3,37 +3,79 @@


namespace rack { namespace rack {


void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, float tension, NVGcolor color) {
float dist = pos1.minus(pos2).norm();
Vec slump;
slump.y = (1.0 - tension) * (150.0 + 1.0*dist);
Vec pos3 = pos1.plus(pos2).div(2).plus(slump);
void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, float tension, NVGcolor color, float opacity) {
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08);
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);


// Wire
if (opacity > 0.0) {
nvgSave(vg);
nvgGlobalAlpha(vg, opacity);

float dist = pos1.minus(pos2).norm();
Vec slump;
slump.y = (1.0 - tension) * (150.0 + 1.0*dist);
Vec pos3 = pos1.plus(pos2).div(2).plus(slump);

nvgLineJoin(vg, NVG_ROUND);

// Shadow
Vec pos4 = pos3.plus(slump.mult(0.08));
nvgBeginPath(vg);
nvgMoveTo(vg, pos1.x, pos1.y);
nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y);
nvgStrokeColor(vg, colorShadow);
nvgStrokeWidth(vg, 5);
nvgStroke(vg);

// Wire outline
nvgBeginPath(vg);
nvgMoveTo(vg, pos1.x, pos1.y);
nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y);
nvgStrokeColor(vg, colorOutline);
nvgStrokeWidth(vg, 6);
nvgStroke(vg);

// Wire solid
nvgStrokeColor(vg, color);
nvgStrokeWidth(vg, 4);
nvgStroke(vg);

nvgRestore(vg);
}

// First plug
nvgBeginPath(vg);
nvgCircle(vg, pos1.x, pos1.y, 21/2.0);
nvgFillColor(vg, colorOutline);
nvgFill(vg);


nvgLineJoin(vg, NVG_ROUND);
nvgBeginPath(vg);
nvgCircle(vg, pos1.x, pos1.y, 19/2.0);
nvgFillColor(vg, color);
nvgFill(vg);


// Shadow
Vec pos4 = pos3.plus(slump.mult(0.08));
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08);
nvgBeginPath(vg); nvgBeginPath(vg);
nvgMoveTo(vg, pos1.x, pos1.y);
nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y);
nvgStrokeColor(vg, colorShadow);
nvgStrokeWidth(vg, 5);
nvgStroke(vg);

// Wire outline
NVGcolor colorOutline = nvgRGBf(0, 0, 0);
nvgCircle(vg, pos1.x, pos1.y, 11/2.0);
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
nvgFill(vg);

// Second plug
nvgBeginPath(vg);
nvgCircle(vg, pos2.x, pos2.y, 21/2.0);
nvgFillColor(vg, colorOutline);
nvgFill(vg);

nvgBeginPath(vg); nvgBeginPath(vg);
nvgMoveTo(vg, pos1.x, pos1.y);
nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y);
nvgStrokeColor(vg, colorOutline);
nvgStrokeWidth(vg, 4);
nvgStroke(vg);

// Wire solid
nvgStrokeColor(vg, color);
nvgStrokeWidth(vg, 2);
nvgStroke(vg);
nvgCircle(vg, pos2.x, pos2.y, 19/2.0);
nvgFillColor(vg, color);
nvgFill(vg);

nvgBeginPath(vg);
nvgCircle(vg, pos2.x, pos2.y, 11/2.0);
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
nvgFill(vg);
} }




@@ -87,35 +129,29 @@ void WireWidget::updateWire() {
void WireWidget::draw(NVGcontext *vg) { void WireWidget::draw(NVGcontext *vg) {
Vec outputPos, inputPos; Vec outputPos, inputPos;
Vec absolutePos = getAbsolutePos(); Vec absolutePos = getAbsolutePos();
float wireOpacity = gScene->toolbar->wireOpacitySlider->value / 100.0;
float opacity = gScene->toolbar->wireOpacitySlider->value / 100.0;


// Compute location of pos1 and pos2
if (outputPort) { if (outputPort) {
outputPos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); outputPos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter();
} }
else { else {
outputPos = gMousePos; outputPos = gMousePos;
wireOpacity = 1.0;
opacity = 1.0;
} }
if (inputPort) { if (inputPort) {
inputPos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); inputPos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter();
} }
else { else {
inputPos = gMousePos; inputPos = gMousePos;
wireOpacity = 1.0;
opacity = 1.0;
} }


outputPos = outputPos.minus(absolutePos); outputPos = outputPos.minus(absolutePos);
inputPos = inputPos.minus(absolutePos); inputPos = inputPos.minus(absolutePos);


bndNodePort(vg, outputPos.x, outputPos.y, BND_DEFAULT, color);
bndNodePort(vg, inputPos.x, inputPos.y, BND_DEFAULT, color);
nvgSave(vg);
if (wireOpacity > 0.0) {
nvgGlobalAlpha(vg, wireOpacity);
float tension = gScene->toolbar->wireTensionSlider->value;
drawWire(vg, outputPos, inputPos, tension, color);
}
nvgRestore(vg);
float tension = gScene->toolbar->wireTensionSlider->value;
drawWire(vg, outputPos, inputPos, tension, color, opacity);
} }






Loading…
Cancel
Save