Show FM/AM routing
BIN
sprites/icons/WireArrowLeft.png
Normal file
|
After Width: | Height: | Size: 498 B |
BIN
sprites/icons/WireArrowRight.png
Normal file
|
After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 515 B |
|
Before Width: | Height: | Size: 531 B After Width: | Height: | Size: 530 B |
@ -123,7 +123,15 @@ PlotFill = #ccfdcc25
|
||||
PlotLine = #ccfdcc
|
||||
PlotText = #333333
|
||||
|
||||
WaveOff = #33663340
|
||||
WaveActive = #339933
|
||||
SoundCardWaveOff = #33663340
|
||||
SoundCardWaveActive = #339933
|
||||
|
||||
WireOff = #929292
|
||||
SoundCardWireOff = #929292
|
||||
SoundCardWire0 = #237f23
|
||||
SoundCardWire1 = #237f77
|
||||
SoundCardWire2 = #23567f
|
||||
SoundCardWire3 = #69237f
|
||||
SoundCardWire4 = #7f2331
|
||||
SoundCardWire5 = #7f5123
|
||||
SoundCardWire6 = #7f7723
|
||||
SoundCardWire7 = #000000
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
@ -1,7 +1,7 @@
|
||||
BackgroundPattern 0 0 304 304
|
||||
BarSegment 29 355 16 4
|
||||
ComputerMotherboard 305 0 79 70
|
||||
Empty 12 405 1 1
|
||||
Empty 12 414 1 1
|
||||
EmptySlot 458 147 18 18
|
||||
Knob 385 0 50 50
|
||||
KnobCenter 436 0 50 50
|
||||
@ -43,6 +43,8 @@ icons/WaveSawtooth 86 305 24 10
|
||||
icons/WaveSine 111 305 24 10
|
||||
icons/WaveSquare 136 305 24 10
|
||||
icons/WaveTriangle 161 305 24 10
|
||||
icons/WireArrowLeft 2 394 4 8
|
||||
icons/WireArrowRight 7 394 4 8
|
||||
items/APU0 373 122 16 96
|
||||
items/APU1 390 122 16 96
|
||||
items/APU2 407 122 16 96
|
||||
@ -101,17 +103,17 @@ items/Server3 424 105 16 16
|
||||
items/SoundCard 356 122 16 128
|
||||
items/WirelessNetworkCard0 441 105 16 16
|
||||
items/WirelessNetworkCard1 458 105 16 16
|
||||
light-panel/BookmarkLeft 391 219 20 14
|
||||
light-panel/BookmarkRight 17 305 18 14
|
||||
light-panel/BorderB 8 394 4 4
|
||||
light-panel/BorderL 98 394 4 2
|
||||
light-panel/BorderR 13 394 4 4
|
||||
light-panel/BorderT 18 394 4 4
|
||||
light-panel/CornerBL 23 394 4 4
|
||||
light-panel/CornerBR 28 394 4 4
|
||||
light-panel/CornerTL 33 394 4 4
|
||||
light-panel/CornerTR 38 394 4 4
|
||||
light-panel/Fill 6 405 2 2
|
||||
light-panel/BookmarkLeft 17 305 18 14
|
||||
light-panel/BookmarkRight 391 219 20 14
|
||||
light-panel/BorderB 8 403 4 4
|
||||
light-panel/BorderL 98 403 4 2
|
||||
light-panel/BorderR 13 403 4 4
|
||||
light-panel/BorderT 18 403 4 4
|
||||
light-panel/CornerBL 23 403 4 4
|
||||
light-panel/CornerBR 28 403 4 4
|
||||
light-panel/CornerTL 33 403 4 4
|
||||
light-panel/CornerTR 38 403 4 4
|
||||
light-panel/Fill 6 414 2 2
|
||||
light-panel/Vent 0 355 2 38
|
||||
nodes/Cable 3 366 8 8
|
||||
nodes/Computer 475 105 16 16
|
||||
@ -127,26 +129,26 @@ nodes/NoteBlock 453 51 16 16
|
||||
nodes/Relay 470 51 16 16
|
||||
nodes/Screen 487 51 16 16
|
||||
nodes/ScreenOnOverlay 0 305 16 16
|
||||
panel/BorderB 43 394 4 4
|
||||
panel/BorderL 103 394 4 2
|
||||
panel/BorderR 48 394 4 4
|
||||
panel/BorderT 53 394 4 4
|
||||
panel/CornerBL 58 394 4 4
|
||||
panel/CornerBR 63 394 4 4
|
||||
panel/CornerTL 68 394 4 4
|
||||
panel/CornerTR 73 394 4 4
|
||||
panel/Fill 9 405 2 2
|
||||
panel/BorderB 43 403 4 4
|
||||
panel/BorderL 103 403 4 2
|
||||
panel/BorderR 48 403 4 4
|
||||
panel/BorderT 53 403 4 4
|
||||
panel/CornerBL 58 403 4 4
|
||||
panel/CornerBR 63 403 4 4
|
||||
panel/CornerTL 68 403 4 4
|
||||
panel/CornerTR 73 403 4 4
|
||||
panel/Fill 9 414 2 2
|
||||
particles/Note 21 355 7 10
|
||||
screen/BorderB 5 394 2 8
|
||||
screen/BorderT 2 394 2 10
|
||||
screen/BorderB 5 403 2 8
|
||||
screen/BorderT 2 403 2 10
|
||||
screen/CornerBL 12 366 8 8
|
||||
screen/CornerBR 21 366 8 8
|
||||
screen/CornerTL 3 355 8 10
|
||||
screen/CornerTR 12 355 8 10
|
||||
window/BorderDark 2 405 1 4
|
||||
window/BorderLight 4 405 1 4
|
||||
window/BorderDark 2 414 1 4
|
||||
window/BorderLight 4 414 1 4
|
||||
window/CloseButton 30 366 7 6
|
||||
window/CornerBL 78 394 4 4
|
||||
window/CornerBR 83 394 4 4
|
||||
window/CornerTL 88 394 4 4
|
||||
window/CornerTR 93 394 4 4
|
||||
window/CornerBL 78 403 4 4
|
||||
window/CornerBR 83 403 4 4
|
||||
window/CornerTL 88 403 4 4
|
||||
window/CornerTR 93 403 4 4
|
||||
|
||||
@ -2,7 +2,7 @@ package ocelot.desktop.ui.widget.card
|
||||
|
||||
import ocelot.desktop.ColorScheme
|
||||
import ocelot.desktop.color.Color
|
||||
import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D}
|
||||
import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D, Vector2D}
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.layout.{Layout, LinearLayout}
|
||||
import ocelot.desktop.ui.widget.card.SoundCardWindow._
|
||||
@ -31,6 +31,12 @@ class SoundCardWindow(card: SoundCard) extends BasicWindow {
|
||||
new Channel(proc, osc)
|
||||
}
|
||||
|
||||
private val patchbays: Array[Patchbay] = (0 until numChannels / 2)
|
||||
.map(i => new Patchbay(2 * i, 2 * i + 1, isFirst = i == 0, isLast = i == numChannels / 2 - 1))
|
||||
.toArray
|
||||
|
||||
private val existingConnectors = new mutable.ArrayBuffer[Connector]()
|
||||
|
||||
private var eventSub: Option[EventBus.Subscription] = None
|
||||
|
||||
children :+= new PaddingBox(new Widget {
|
||||
@ -44,20 +50,13 @@ class SoundCardWindow(card: SoundCard) extends BasicWindow {
|
||||
|
||||
children :+= new PaddingBox(masterOscilloscope, Padding2D(left = 4, right = 4))
|
||||
|
||||
for (i <- process.channels.indices by 2) {
|
||||
for (i <- 0 until numChannels / 2) {
|
||||
children :+= new Widget {
|
||||
children :+= channelWidgets(i)
|
||||
children :+= new Patchbay(i, i + 1, isFirst = i == 0, isLast = i == numChannels - 2)
|
||||
children :+= channelWidgets(i + 1)
|
||||
children :+= channelWidgets(2 * i)
|
||||
children :+= patchbays(i)
|
||||
children :+= channelWidgets(2 * i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
if (numChannels % 2 == 1) {
|
||||
val i = numChannels - 1
|
||||
children :+= channelWidgets(i)
|
||||
children :+= new Patchbay(i, -1, isFirst = false, isLast = true)
|
||||
children :+= new Widget
|
||||
}
|
||||
}, Padding2D.equal(8))
|
||||
|
||||
private def numChannels: Int = process.channels.length
|
||||
@ -84,9 +83,118 @@ class SoundCardWindow(card: SoundCard) extends BasicWindow {
|
||||
beginDraw(g)
|
||||
DrawUtils.windowWithShadow(g, position.x, position.y, size.width, size.height, 1f, 0.5f)
|
||||
drawChildren(g)
|
||||
drawConnectors(g)
|
||||
endDraw(g)
|
||||
}
|
||||
|
||||
private def drawConnectors(g: Graphics): Unit = {
|
||||
val initColor = ColorScheme("Label")
|
||||
for (i <- 0 until numChannels) {
|
||||
setColCh(i, initColor)
|
||||
setColAm(i, initColor)
|
||||
setColFm(i, initColor)
|
||||
}
|
||||
|
||||
existingConnectors.clear()
|
||||
|
||||
var colorIdx = 0
|
||||
var color = ColorScheme("SoundCardWire0")
|
||||
val px = patchbays(0).posLeftCh.x
|
||||
|
||||
for (i <- 0 until numChannels) {
|
||||
var hadAny = false
|
||||
|
||||
for (j <- 0 until numChannels) {
|
||||
if (i != j) {
|
||||
val dstCh = process.channels(j)
|
||||
if (dstCh.amplitudeMod.exists(_.modulatorIndex == i)) {
|
||||
setColAm(j, color)
|
||||
drawConnector(g, px, posCh(i), posAm(j), colorIdx)
|
||||
hadAny = true
|
||||
}
|
||||
|
||||
if (dstCh.frequencyMod.exists(_.modulatorIndex == i)) {
|
||||
setColFm(j, color)
|
||||
drawConnector(g, px, posCh(i), posFm(j), colorIdx)
|
||||
hadAny = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hadAny) {
|
||||
setColCh(i, color)
|
||||
colorIdx += 1
|
||||
color = ColorScheme(s"SoundCardWire${colorIdx % 8}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def drawConnector(g: Graphics, px: Float, a: Vector2D, b: Vector2D, colorIdx: Int): Unit = {
|
||||
var from = a.y
|
||||
var to = b.y
|
||||
if (from > to) {
|
||||
from = b.y
|
||||
to = a.y
|
||||
}
|
||||
|
||||
var column = 0
|
||||
val existing = existingConnectors.find(con => con.colorIdx == colorIdx)
|
||||
if (existing.isDefined) {
|
||||
column = existing.get.column
|
||||
} else {
|
||||
var done = false
|
||||
while (column >= 0 && column < 6 && !done) {
|
||||
val conflict = existingConnectors.exists(con => {
|
||||
con.column == column && con.from <= to && con.to >= from
|
||||
})
|
||||
if (conflict) {
|
||||
column += 1
|
||||
} else {
|
||||
done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val mx = px + column * 4 + 9
|
||||
val col = ColorScheme(s"SoundCardWire${colorIdx % 8}")
|
||||
|
||||
g.line(a, Vector2D(mx, a.y), 2, col)
|
||||
g.line(Vector2D(mx, from - 1), Vector2D(mx, to + 1), 2, col)
|
||||
g.line(b, Vector2D(mx, b.y), 2, col)
|
||||
|
||||
if (b.x > px) {
|
||||
g.sprite("icons/WireArrowRight", b.x - 4, b.y - 4, col)
|
||||
} else {
|
||||
g.sprite("icons/WireArrowLeft", b.x, b.y - 4, col)
|
||||
}
|
||||
|
||||
existingConnectors += Connector(column, colorIdx, from, to)
|
||||
}
|
||||
|
||||
private def posCh(i: Int): Vector2D = {
|
||||
if (i % 2 == 0) patchbays(i / 2).posLeftCh else patchbays(i / 2).posRightCh
|
||||
}
|
||||
|
||||
private def posAm(i: Int): Vector2D = {
|
||||
if (i % 2 == 0) patchbays(i / 2).posLeftAm else patchbays(i / 2).posRightAm
|
||||
}
|
||||
|
||||
private def posFm(i: Int): Vector2D = {
|
||||
if (i % 2 == 0) patchbays(i / 2).posLeftFm else patchbays(i / 2).posRightFm
|
||||
}
|
||||
|
||||
private def setColCh(i: Int, col: Color): Unit = {
|
||||
if (i % 2 == 0) patchbays(i / 2).colLeftCh = col else patchbays(i / 2).colRightCh = col
|
||||
}
|
||||
|
||||
private def setColAm(i: Int, col: Color): Unit = {
|
||||
if (i % 2 == 0) patchbays(i / 2).colLeftAm = col else patchbays(i / 2).colRightAm = col
|
||||
}
|
||||
|
||||
private def setColFm(i: Int, col: Color): Unit = {
|
||||
if (i % 2 == 0) patchbays(i / 2).colLeftFm = col else patchbays(i / 2).colRightFm = col
|
||||
}
|
||||
|
||||
override def update(): Unit = {
|
||||
super.update()
|
||||
|
||||
@ -183,7 +291,7 @@ object SoundCardWindow {
|
||||
case ADSREnvelope.Phase.Release => releaseStart + elapsedMs
|
||||
}
|
||||
|
||||
var col = ColorScheme("WaveActive").withAlpha(0.6f)
|
||||
var col = ColorScheme("SoundCardWaveActive").withAlpha(0.6f)
|
||||
for (sx <- 0 until bounds.w.toInt) {
|
||||
val t = (sx / bounds.w) * envDuration
|
||||
if (t >= elapsedTime) col = col.withAlpha(0.2f)
|
||||
@ -202,7 +310,7 @@ object SoundCardWindow {
|
||||
val ay = bounds.y + bounds.h
|
||||
val by = bounds.y
|
||||
val cy = bounds.y + (1 - env.sustain) * bounds.h
|
||||
col = ColorScheme("WaveActive")
|
||||
col = ColorScheme("SoundCardWaveActive")
|
||||
|
||||
var ax = bounds.x
|
||||
var bx = bounds.x + env.attack * unit
|
||||
@ -233,7 +341,7 @@ object SoundCardWindow {
|
||||
override def draw(g: Graphics): Unit = {
|
||||
for (((icon, clazz), i) <- waves.zipWithIndex) {
|
||||
val active = clazz.isInstance(channel.generator)
|
||||
val color = if (active) ColorScheme("WaveActive") else ColorScheme("WaveOff")
|
||||
val color = if (active) ColorScheme("SoundCardWaveActive") else ColorScheme("SoundCardWaveOff")
|
||||
g.sprite(icon, position.x + 24 * i + 2, position.y + 4, color)
|
||||
}
|
||||
|
||||
@ -276,9 +384,28 @@ object SoundCardWindow {
|
||||
}
|
||||
|
||||
private class Patchbay(leftIdx: Int, rightIdx: Int, isFirst: Boolean, isLast: Boolean) extends Widget {
|
||||
override def minimumSize: Size2D = Size2D(68, 100)
|
||||
var colLeftCh: Color = ColorScheme("Label")
|
||||
var colLeftAm: Color = ColorScheme("Label")
|
||||
var colLeftFm: Color = ColorScheme("Label")
|
||||
var colRightCh: Color = ColorScheme("Label")
|
||||
var colRightAm: Color = ColorScheme("Label")
|
||||
var colRightFm: Color = ColorScheme("Label")
|
||||
|
||||
override def maximumSize: Size2D = Size2D(68, Float.PositiveInfinity)
|
||||
override def minimumSize: Size2D = Size2D(74, 100)
|
||||
|
||||
override def maximumSize: Size2D = Size2D(74, Float.PositiveInfinity)
|
||||
|
||||
def posLeftCh: Vector2D = Vector2D(position.x + 18, position.y + 22)
|
||||
|
||||
def posLeftAm: Vector2D = Vector2D(position.x + 18, position.y + 38)
|
||||
|
||||
def posLeftFm: Vector2D = Vector2D(position.x + 18, position.y + 54)
|
||||
|
||||
def posRightCh: Vector2D = Vector2D(position.x + width - 20, position.y + 22)
|
||||
|
||||
def posRightAm: Vector2D = Vector2D(position.x + width - 20, position.y + 38)
|
||||
|
||||
def posRightFm: Vector2D = Vector2D(position.x + width - 20, position.y + 54)
|
||||
|
||||
override def draw(g: Graphics): Unit = {
|
||||
val x = position.x
|
||||
@ -309,33 +436,40 @@ object SoundCardWindow {
|
||||
}
|
||||
|
||||
for (i <- 0 until 6) {
|
||||
g.rect(x + 23 + i * 4, y - 2, 2, h + 4, ColorScheme("WireOff"))
|
||||
g.rect(x + 26 + i * 4, y - 2, 2, h + 4, ColorScheme("SoundCardWireOff"))
|
||||
}
|
||||
|
||||
y -= sy
|
||||
h += sh
|
||||
|
||||
g.sprite("light-panel/BookmarkLeft", x, y + 16, 20, 14)
|
||||
g.sprite("light-panel/BookmarkLeft", x, y + 32, 20, 14)
|
||||
g.sprite("light-panel/BookmarkLeft", x, y + 48, 20, 14)
|
||||
g.sprite("light-panel/BookmarkLeft", x, y + 16, 18, 14)
|
||||
g.sprite("light-panel/BookmarkLeft", x, y + 32, 18, 14)
|
||||
g.sprite("light-panel/BookmarkLeft", x, y + 48, 18, 14)
|
||||
|
||||
g.sprite("light-panel/BookmarkRight", x + w - 20, y + 16, 20, 14)
|
||||
g.sprite("light-panel/BookmarkRight", x + w - 20, y + 32, 20, 14)
|
||||
g.sprite("light-panel/BookmarkRight", x + w - 20, y + 48, 20, 14)
|
||||
|
||||
g.setSmallFont()
|
||||
g.foreground = ColorScheme("Label")
|
||||
g.background = Color.Transparent
|
||||
|
||||
g.foreground = colLeftCh
|
||||
g.text(x, y + 18, s"C${leftIdx + 1}")
|
||||
g.foreground = colLeftAm
|
||||
g.text(x, y + 34, "AM")
|
||||
g.foreground = colLeftFm
|
||||
g.text(x, y + 50, "FM")
|
||||
|
||||
g.foreground = colRightCh
|
||||
g.text(x + w - 18, y + 18, s"C${rightIdx + 1}")
|
||||
g.foreground = colRightAm
|
||||
g.text(x + w - 18, y + 34, "AM")
|
||||
g.foreground = colRightFm
|
||||
g.text(x + w - 18, y + 50, "FM")
|
||||
|
||||
g.setNormalFont()
|
||||
}
|
||||
}
|
||||
|
||||
private case class Connector(column: Int, colorIdx: Int, from: Float, to: Float)
|
||||
}
|
||||