Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added images/cat/cat-front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-knob.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-slider-grey.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-slider-red.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-slider-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-switch-down.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-switch-middle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cat/cat-switch-up.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
145 changes: 145 additions & 0 deletions js/behringer-cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { FrontPanel } from "./front-panel"

//
// Some constants for locations of knobs and connectors, etc.
//
const CANVAS_WIDTH = 2000;
const CANVAS_HEIGHT = 710;
const CABLE_WIDTH = 6;
const CELL_RADIUS = 12;
const CONNECTORS = [
//inputs
//row 1
{idx: 0, col: 0, row: 0, x: 1466, y: 86, name: "VCO1 CV", input: true},
{idx: 1, col: 1, row: 0, x: 1539, y: 86, name: "GATE", input: true},
//row 2
{idx: 2, col: 0, row: 1, x: 1466, y: 160, name: "VCO2 CV", input: true},
{idx: 3, col: 1, row: 1, x: 1539, y: 160, name: "VCO2 Fc", input: true},
{idx: 4, col: 2, row: 1, x: 1609, y: 160, name: "VCF Q", input: true},
{idx: 5, col: 3, row: 1, x: 1681, y: 160, name: "EXT AUDIO", input: true},
{idx: 6, col: 4, row: 1, x: 1752, y: 160, name: "VCA CV", input: true},

//outputs
//row 1
{idx: 7, col: 2, row: 0, x: 1609, y: 86, name: "KB CV", input: false},
{idx: 8, col: 3, row: 0, x: 1681, y: 86, name: "GATE", input: false},
{idx: 9, col: 4, row: 0, x: 1752, y: 86, name: "ADSR", input: false},
{idx: 10, col: 5, row: 0, x: 1824, y: 86, name: "AR", input: false},
//row 2
{idx: 11, col: 5, row: 1, x: 1824, y: 160, name: "PHONES", input: false},
{idx: 12, col: 6, row: 1, x: 1895, y: 160, name: "MAIN OUT", input: false}

]
const KNOBS = [
{idx: 0, x: 523, y: 127, type: "large", name: "VCO1 FREQUENCY FINE"},
{idx: 1, x: 646, y: 127, type: "large", name: "VCO1 FREQUENCY COARSE"},
{idx: 2, x: 523, y: 379, type: "large", name: "VCO1 OSC MOD DEPTH1"},
{idx: 3, x: 646, y: 379, type: "large", name: "VCO1 OSC MOD DEPTH2"},
{idx: 4, x: 768, y: 379, type: "large", name: "VCO1 PULSE WIDTH"},
{idx: 5, x: 939, y: 127, type: "large", name: "VCO2 FINE"},
{idx: 6, x: 939, y: 379, type: "large", name: "VCO2 OSC MOD DEPTH1"},
{idx: 7, x: 1062, y: 379, type: "large", name: "VCO2 OSC MOD DEPTH2"},
{idx: 8, x: 1355, y: 127, type: "large", name: "KEYBOARD CONTROL"},
{idx: 9, x: 1231, y: 379, type: "large", name: "VCF MOD DEPTH1"},
{idx: 10, x: 1354, y: 379, type: "large", name: "VCF MOD DEPTH1"},
{idx: 11, x: 1885, y: 379, type: "large", name: "VCA"}
]
const KNOB_TYPES = {
large: {radius: 38, limit: 303}
}
const TOGGLES = [
{idx: 0, x: 171, y: 521, type: "threeway", name: "OCTAVE SHIFT"},
{idx: 1, x: 755, y: 102, type: "threeway", name: "KEYBOARD CONTROL"},
{idx: 2, x: 511, y: 229, type: "threeway", name: "VCO1 WAVEFORM1"},
{idx: 3, x: 633, y: 229, type: "threeway", name: "VCO1 WAVEFORM2"},
{idx: 4, x: 757, y: 229, type: "threeway", name: "VCO1 WAVEFORM3"},
{idx: 5, x: 1049, y: 102, type: "threeway", name: "VCO SYNC"},
{idx: 6, x: 926, y: 229, type: "threeway", name: "VCO2 WAVEFORM1"},
{idx: 7, x: 1049, y: 229, type: "threeway", name: "VCO2 WAVEFORM2"},
{idx: 8, x: 1219, y: 102, type: "twoway", name: "VCO1 AUDIO"},
{idx: 9, x: 1219, y: 229, type: "threeway", name: "VCF MODSOURCE1"},
{idx: 10, x: 1342, y: 229, type: "threeway", name: "VCF MODSOURCE2"},
{idx: 11, x: 1656, y: 430, type: "threeway", name: "ADSR REPEAT"},
{idx: 12, x: 1656, y: 556, type: "twoway", name: "SAMPLE HOLD"},
{idx: 13, x: 1874, y: 231, type: "threeway", name: "VCA OUTPUT"}
]
const TOGGLE_TYPES = {
twoway: {values: ["up", "down"]},
threeway: {values: ["up", "middle", "down"]}
}
const SLIDERS = [
{idx: 0, x: 101, y: 605, type: "red", name: "PITCH BEND"},
{idx: 1, x: 265, y: 605, type: "red", name: "GLIDE"},
{idx: 2, x: 346, y: 605, type: "red", name: "LFO FREQ"},
{idx: 3, x: 523, y: 605, type: "white", name: "VCO1 SUB"},
{idx: 4, x: 605, y: 605, type: "white", name: "VCO1 SAW"},
{idx: 5, x: 687, y: 605, type: "white", name: "VCO1 TRI"},
{idx: 6, x: 769, y: 605, type: "white", name: "VCO1 PULSE"},
{idx: 7, x: 919, y: 605, type: "white", name: "VCO2 SUB"},
{idx: 8, x: 1000, y: 605, type: "white", name: "VCO2 SQUARE"},
{idx: 9, x: 1081, y: 605, type: "white", name: "VCO2 SAW"},
{idx: 10, x: 1252, y: 605, type: "red", name: "VCF FC"},
{idx: 11, x: 1334, y: 605, type: "red", name: "VCF Q"},
{idx: 12, x: 1504, y: 359, type: "grey", name: "ADSR A"},
{idx: 13, x: 1586, y: 359, type: "grey", name: "ADSR D"},
{idx: 14, x: 1668, y: 359, type: "grey", name: "ADSR S"},
{idx: 15, x: 1749, y: 359, type: "grey", name: "ADSR R"},
{idx: 16, x: 1504, y: 605, type: "grey", name: "AR A"},
{idx: 17, x: 1586, y: 605, type: "grey", name: "AR R"},
{idx: 18, x: 1749, y: 605, type: "grey", name: "LFO DELAY"},
{idx: 19, x: 1885, y: 605, type: "white", name: "NOISE"}
]
const SLIDER_TYPES = {
red: {radius: 18, limit: 110},
white: {radius: 18, limit: 110},
grey: {radius: 18, limit: 110}
}
const TOGGLE_WIDTH = 35
const TOGGLE_HEIGHT = 50

export class BehringerCat extends FrontPanel {
constructor() {
super({
deviceName: "behringer-cat",
canvasWidth: CANVAS_WIDTH,
canvasHeight: CANVAS_HEIGHT,
connectors: CONNECTORS,
connectorOptions: {
cellRadius: CELL_RADIUS,
cableWidth: CABLE_WIDTH
},
knobs: KNOBS,
knobTypes: KNOB_TYPES,
sliders: SLIDERS,
sliderTypes: SLIDER_TYPES,
toggles: TOGGLES,
toggleOptions: {
types: TOGGLE_TYPES,
width: TOGGLE_WIDTH,
height: TOGGLE_HEIGHT
},
initialValues: {
knobValues: Array(15).fill(0),
sliderValues: [55].concat(Array(19).fill(0)),
toggleValues: [1].concat(Array(14).fill(0))
},
images: {
panel: "/images/cat/cat-front.png",
knobs: {
large: "/images/cat/cat-knob.png"
},
toggles: {
down: "/images/cat/cat-switch-down.png",
middle: "/images/cat/cat-switch-middle.png",
up: "/images/cat/cat-switch-up.png"
},
sliders: {
grey: "/images/cat/cat-slider-grey.png",
red: "/images/cat/cat-slider-red.png",
white: "/images/cat/cat-slider-white.png"
}
}
})
}

}
52 changes: 48 additions & 4 deletions js/front-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class FrontPanel {
constructor(options) {
const {deviceName, canvasWidth, canvasHeight, buttons, knobs, connectors, toggles,
lights, initialValues, buttonOptions, connectorOptions, knobTypes, toggleOptions,
lightOptions, images} = options
lightOptions, images, sliders, sliderTypes} = options

// The canvas, input elements and images
this.canvas = document.querySelector(`canvas[data-device='${deviceName}']`);
Expand All @@ -32,8 +32,10 @@ class FrontPanel {
this.buttons = buttons || []
this.toggles = toggles || []
this.lights = lights || []
this.sliders = sliders || []

this.knobTypes = knobTypes
this.sliderTypes = sliderTypes
this.buttonOptions = buttonOptions
this.connectorOptions = connectorOptions
this.toggleOptions = toggleOptions
Expand Down Expand Up @@ -70,6 +72,11 @@ class FrontPanel {
this.turnNewValue;
this.turnPreviousY;

// Slider sliding
this.sliding = false;
this.slideSliderIdx;
this.slidePreviousY;

// Current patch data
// this.connections = [
// {from: 0, to: 36, color: CABLE_COLORS[9]},
Expand All @@ -79,6 +86,7 @@ class FrontPanel {
this.knobValues = initialValues.knobValues || []
this.buttonValues = initialValues.buttonValues || []
this.toggleValues = initialValues.toggleValues || []
this.sliderValues = initialValues.sliderValues || []
this.lightValues = initialValues.lightValues || {}


Expand Down Expand Up @@ -111,6 +119,7 @@ class FrontPanel {
this.buttons.forEach(button => this.drawButton(button))
this.toggles.forEach(toggle => this.drawToggle(toggle))
this.connections.forEach(connection => this.drawConnection(connection))
this.sliders.forEach(slider => this.drawSlider(slider))
this.drawLights()

if (this.dragging) {
Expand All @@ -119,7 +128,7 @@ class FrontPanel {
this.drawCable(from, to, this.dragColor);
}

if (this.dragging || this.turning) {
if (this.dragging || this.turning || this.sliding) {
this.requestRedraw()
}
}
Expand Down Expand Up @@ -181,6 +190,17 @@ class FrontPanel {
this.ctx.restore()
}

drawSlider(slider) {
const value = this.sliderValues[slider.idx]
const sliderImage = this.images.sliders[slider.type]
if (!sliderImage) { return }

this.ctx.save();
this.ctx.translate(slider.x, slider.y - value);
this.ctx.drawImage(sliderImage, -sliderImage.width / 2, -sliderImage.height / 2);
this.ctx.restore()
}

// To be overridden in subclass
drawLights() {}

Expand Down Expand Up @@ -337,11 +357,21 @@ class FrontPanel {
}
})

this.sliders.forEach(slider => {
const sliderType = this.sliderTypes[slider.type];
if (this.isIntersect(pos, {x: slider.x, y: slider.y - this.sliderValues[slider.idx]}, sliderType.radius)) {
this.sliding = true;
this.slideSliderIdx = slider.idx;
this.slidePreviousY = pos.y;
this.requestRedraw()
}
})

// e.preventDefault()
}, false);

this.canvas.addEventListener("mousemove", (e) => {
if (!this.dragging && !this.turning) return;
if (!this.dragging && !this.turning && !this.sliding) return;
// const pos = {x: e.pageX, y: e.pageY};
const pos = this.getMousePos(this.canvas, e)
// console.log("mousemove", pos, e)
Expand All @@ -367,11 +397,20 @@ class FrontPanel {
this.turnPreviousY = pos.y
// console.log(this.knobValues[this.turnKnobIdx])
}

if (this.sliding) {
const slider = this.sliders[this.slideSliderIdx]
const sliderType= this.sliderTypes[slider.type]
this.sliderValues[this.slideSliderIdx] += this.slidePreviousY - pos.y
this.sliderValues[this.slideSliderIdx] = Math.max(this.sliderValues[this.slideSliderIdx], 0)
this.sliderValues[this.slideSliderIdx] = Math.min(this.sliderValues[this.slideSliderIdx], sliderType.limit)
this.slidePreviousY = pos.y
}
// e.preventDefault()
}, false)

this.canvas.addEventListener("mouseup", (e) => {
if (!this.dragging && !this.turning) return;
if (!this.dragging && !this.turning && !this.sliding) return;
const pos = {x: this.dragToX, y: this.dragToY}
if (this.dragging) {
this.connectors.forEach(circle => {
Expand Down Expand Up @@ -399,11 +438,16 @@ class FrontPanel {
this.updatePatchCableOutput()
this.turning = false;
}
if (this.sliding) {
this.updatePatchCableOutput()
this.sliding = false;
}
}, false)

this.canvas.addEventListener("mouseleave", (e) => {
this.dragging = false;
this.turning = false;
this.sliding = false;
}, false)

// Touch event handlers
Expand Down
2 changes: 2 additions & 0 deletions js/front-panels.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MoogDfam } from "./moog-dfam"
import { MoogMother32 } from "./moog-mother-32"
import { BehringerModelD } from "./behringer-model-d"
import { MakeNoise0Coast } from "./make-noise-0-coast"
import { BehringerCat } from "./behringer-cat"
import { BehringerCrave } from "./behringer-crave"
import { EricaPicoIII } from "./erica-pico-iii"

Expand All @@ -14,6 +15,7 @@ export default {
"moog-mother-32": MoogMother32,
"behringer-model-d": BehringerModelD,
"make-noise-0-coast": MakeNoise0Coast,
"behringer-cat": BehringerCat,
"behringer-crave": BehringerCrave,
"erica-pico-iii": EricaPicoIII
}