diff --git a/data/bitmaps/xg/font.tsv b/data/bitmaps/xg/font.tsv index 89f25785..becfff82 100644 --- a/data/bitmaps/xg/font.tsv +++ b/data/bitmaps/xg/font.tsv @@ -329,15 +329,9 @@ CdPt Bitmap 03cd 1c0242920c 03ce 0c1244920c 0401 3eaa2aaa22 -0451 1caa2aaa18 -0490 7e404040c0 -0491 3e202020e0 0404 7c92928244 -0454 1c2a2a2214 0406 0082fe8200 -0456 0022be0200 0407 00a23ea200 -0457 00a23e8200 0410 7e9090907e 0411 fe9292928c 0412 fe9292926c @@ -402,6 +396,18 @@ CdPt Bitmap 044d 14222a2a1c 044e 3e081c221c 044f 122a2c283e +0451 1caa2aaa18 +0454 1c2a2a2214 +0456 0022be0200 +0457 00a23e8200 +0462 40fe52520c +0463 20fe2a2a04 +0472 7c9292927c +0473 3c5252523c +0474 f00c027c80 +0475 3804021c20 +0490 7e404040c0 +0491 3e202020e0 05d0 2618080c32 05d1 2222221e02 05d2 2224180600 diff --git a/src/disp/disp_psr.mjs b/src/disp/disp_psr.mjs index 8a6729b8..5adabe01 100644 --- a/src/disp/disp_psr.mjs +++ b/src/disp/disp_psr.mjs @@ -20,8 +20,11 @@ let PsrDisplay = class extends RootDisplay { #bmst = 0; #bmex = 0; #ch = 0; + #lastRefreshTime = 0; + #letterShift = 0; + #letterCoolDown = 0; xgFont = new MxFont40("./data/bitmaps/xg/font.tsv"); - trueFont = new MxFont40("./data/bitmaps/korg/font.tsv"); + trueFont = new MxFont40("./data/bitmaps/korg/font.tsv", "./data/bitmaps/xg/font.tsv"); sysBm = new MxBm256("./data/bitmaps/xg/system.tsv"); voxBm = new MxBm256("./data/bitmaps/xg/voices.tsv"); aniBm = new MxBm256("./data/bitmaps/xg/animation.tsv"); @@ -91,6 +94,10 @@ let PsrDisplay = class extends RootDisplay { B: new Uint8Array([0, 1, 1, 1, 1, 1, 0, 0]), C: new Uint8Array([0, 0, 1, 1, 1, 0, 0, 1]), D: new Uint8Array([0, 1, 0, 1, 1, 1, 1, 0]), + E: new Uint8Array([0, 1, 1, 1, 1, 0, 0, 1]), + F: new Uint8Array([0, 1, 1, 1, 0, 0, 0, 1]), + G: new Uint8Array([0, 0, 1, 1, 1, 1, 0, 1]), + H: new Uint8Array([0, 1, 1, 1, 0, 1, 1, 0]), "-": new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0]) }; Array.from(str).forEach((e, i) => { @@ -107,22 +114,38 @@ let PsrDisplay = class extends RootDisplay { let timeNow = Date.now(); ctx.setTransform(1, 0, skew, 1, 0, 0); // Determine the used font - let targetFont = trueMode ? upThis.trueFont : upThis.xgFont; - let rollX = 0; + let usedFont = trueMode ? upThis.trueFont : upThis.xgFont; + let longString = false; + let originalLength = str.length; if (str.length > 8) { - rollX = Math.floor(timeNow / 125) % (2 + str.length); - // rollX = 0; - str = `${str} ${str.slice(0, 8)}` - str = str.slice(rollX, rollX + 8); - }; - str = str.padEnd(8, " "); - targetFont.getStr(str).forEach((e, i) => { + longString = true; + str = `${str} ${str.slice(0, 8)}`; + str = str.slice(upThis.#letterShift, upThis.#letterShift + 8); + } else { + str = str.padEnd(8, " "); + } + usedFont.getStr(str).forEach((e, i) => { e.render((e, x, y) => { ctx.fillStyle = e ? activePixel : inactivePixel; ctx.fillRect(offsetX + (x + 6 * i) * scaleX, offsetY + y * scaleY, scaleX - 1, scaleY - 1); }); }); ctx.resetTransform(); + if (longString && Math.floor(timeNow / 60) != upThis.#lastRefreshTime) { + if (upThis.#letterCoolDown > 0) { + upThis.#letterCoolDown--; + } else if (upThis.#letterShift > originalLength + 1) { + upThis.#letterShift = 0; + upThis.#letterCoolDown = 8; + } else { + upThis.#letterShift++; + upThis.#letterCoolDown = 1; + } + } else if (!longString) { + upThis.#letterShift = 0; + upThis.#letterCoolDown = 0; + } + upThis.#lastRefreshTime = Math.floor(timeNow / 60); } render(time, ctx, backlightColor = "#b7bfaf64", mixerView, tempoView, id = 0, trueMode = false) { let sum = super.render(time); @@ -242,10 +265,10 @@ let PsrDisplay = class extends RootDisplay { this.#nsdb[(Math.floor(i / 12) - 4) * 7 + noteHeadPos[i % 12]] = pixel; if (isBlackKey[i % 12]) { if (isBlackKey[i % 12] == 1) { - this.#nadb[(Math.floor(i / 12) - 4) * 2 + nadbIndex[i % 12]] = 1; + this.#nadb[(Math.floor(i / 12) - 4) * 2 + nadbIndex[i % 12]] = pixel; } else { - this.#nadb[(Math.floor(i / 12) - 4) * 3 + nadbIndex[i % 12] + 6] = 1; + this.#nadb[(Math.floor(i / 12) - 4) * 3 + nadbIndex[i % 12] + 6] = pixel; } } } @@ -263,10 +286,10 @@ let PsrDisplay = class extends RootDisplay { } if (isBlackKey[i % 12]) { if (isBlackKey[i % 12] == 1) { - this.#nadb[nadbIndex[i % 12]] = 1; + this.#nadb[nadbIndex[i % 12]] = Math.max(this.#nadb[nadbIndex[i % 12]], pixel); } else { - this.#nadb[nadbIndex[i % 12] + 6] = 1; + this.#nadb[nadbIndex[i % 12] + 6] = Math.max(this.#nadb[nadbIndex[i % 12] + 6], pixel); } } } @@ -284,10 +307,10 @@ let PsrDisplay = class extends RootDisplay { } if (isBlackKey[i % 12]) { if (isBlackKey[i % 12] == 1) { - this.#nadb[4 + nadbIndex[i % 12]] = 1; + this.#nadb[4 + nadbIndex[i % 12]] = Math.max(this.#nadb[4 + nadbIndex[i % 12]], pixel); } else { - this.#nadb[12 + nadbIndex[i % 12]] = 1; + this.#nadb[12 + nadbIndex[i % 12]] = Math.max(this.#nadb[12 + nadbIndex[i % 12]], pixel); } } } @@ -303,7 +326,8 @@ let PsrDisplay = class extends RootDisplay { ctx.fillStyle = topOctaveFlag2 ? activePixel : inactivePixel; ctx.fillText("15va+", 874, 40); // Temporary channel number display - this.#render7seg(`${"ABCDEFGH"[this.#ch >> 4]}${((this.#ch & 15) + 1).toString().padStart(2, "0")}`, ctx, 32, 315, 0.24, 0.24); + // this.#render7seg(`${"ABCDEFGH"[this.#ch >> 4]}${((this.#ch & 15) + 1).toString().padStart(2, "0")}`, ctx, 32, 315, 0.24, 0.24); + this.#render7seg(`${"ABCDEFGH"[this.#ch >> 4]}${((this.#ch & 15) + 1).toString().padStart(2, "0")}`, ctx, 25, 260, 0.1, 0.1); // Measure / tempo view ctx.font = '23px "Arial Web"'; ctx.fillStyle = tempoView ? inactivePixel : activePixel; @@ -360,7 +384,10 @@ let PsrDisplay = class extends RootDisplay { let sequence = this.demoInfo.class || "boot"; let stepTime = this.demoInfo.fps || 2; let stepSize = this.demoInfo.size || 4; - let stepId = `${sequence}_${Math.floor(time * stepTime % stepSize)}`; + let stepOffset = this.demoInfo.offset || 0; + let stepFrame = Math.floor((time * stepTime + stepOffset) % stepSize); + let stepId = `${sequence}_${stepFrame}`; + //console.debug(stepId); useBm = this.aniBm?.getBm(stepId) || this.sysBm?.getBm(stepId) || this.sysBm?.getBm("no_abm"); if (!useBm) { useBm = this.#bmdb.slice(); @@ -403,11 +430,32 @@ let PsrDisplay = class extends RootDisplay { ctx.fillStyle = e ? activePixel : inactivePixel; ctx.fillRect(224 + x * 6, 261 + y * 3, 5, 2); }); + // Chord display ctx.fillStyle = inactivePixel; ctx.font = '18px "Arial Web"'; ctx.fillText("ACMP", 430, 275); ctx.fillText("ON", 430, 295); ctx.fill(new Path2D("M482 296 L482 312 L462 304 Z")); + this.#render7seg(" ", ctx, 32, 300, 0.25, 0.25); + ctx.font = 'bold 53px "Arial Web"'; + ctx.fillText("m", 82, 375); + ctx.fillText("M", 130, 375); + ctx.font = '40px "Arial Web"'; + ctx.fillText("7", 175, 375); + ctx.font = '30px "Arial Web"'; + // ctx.fillText("♯", 82, 328); + // ctx.fillText("♭", 105, 328); + ctx.fillText("♯", 88, 328); + ctx.fillText("♭", 113, 328); + // ctx.fillText("6", 175, 328); + ctx.fillText("6", 185, 328); + // ctx.fillText("dim", 123, 328); + ctx.fillText("dim", 132, 328); + ctx.font = '25px "Arial Web"'; + ctx.fillText("♭ 5", 105, 277); + ctx.fillText("sus4", 157, 300); + ctx.fillText("aug", 82, 300); + ctx.fillText("(9)", 157, 277); // Commit to display accordingly. let keyboardData = new Uint16Array([228, 238.5, 250.3, 263.5, 272.6, 295, 304.5, 317.3, 330, 339.5, 354, 361.8]); this.#nkdb.forEach((e, i) => { @@ -439,13 +487,13 @@ let PsrDisplay = class extends RootDisplay { this.#nadb.forEach((e, i) => { if (i < 6) { ctx.setTransform(0.03, 0, 0, -0.03, sharpPosX[i], sharpPosY[i]); - ctx.fillStyle = [inactivePixel, activePixel][e]; + ctx.fillStyle = [inactivePixel, mediumPixel, activePixel][e]; ctx.fill(upThis.sharpSign); ctx.resetTransform(); } else { ctx.setTransform(0.03, 0, 0, -0.03, flatPosX[i - 6], flatPosY[i - 6]); - ctx.fillStyle = [inactivePixel, activePixel][e]; + ctx.fillStyle = [inactivePixel, mediumPixel, activePixel][e]; ctx.fill(upThis.flatSign); ctx.resetTransform(); } diff --git a/src/fakePsr/index.js b/src/fakePsr/index.js index 3278c703..2fb50fef 100644 --- a/src/fakePsr/index.js +++ b/src/fakePsr/index.js @@ -27,7 +27,7 @@ let demoId = 0; // Generate Octavia channel switch SysEx let generateSwitch = function (ch = 0, min, max) { - let data = [67, 16, 73, 0, 0, 10, ch]; + let data = [67, 16, 73, 0, 0, 64, ch]; if (min?.constructor == Number) { data.push(min); if (max.constructor == Number) { @@ -195,9 +195,9 @@ visualizer.addEventListener("mode", function (ev) { gs: [71, 83], xg: [88, 71], g2: [71, 77, 50], + sd: [83, 68], mt32: [77, 84, 45, 51, 50], ns5r: [78, 83, 53, 82], - ag10: [65, 71, 45, 49, 48], "05rw": [48, 53, 82, 47, 87], x5d: [88, 53, 68], k11: [71, 77, 101, 103, 97], @@ -344,7 +344,7 @@ let renderThread = setInterval(function () { if (currentAnimation && !visualizer.demoInfo) { visualizer.demoInfo = currentAnimation; }; - visualizer.render(curTime, dispCtx, backlightColor, mixerView, tempoView, useMidiBus ? 0 : demoId, location.hash?.length > 1); + visualizer.render(curTime, dispCtx, backlightColor, mixerView, tempoView, useMidiBus ? 0 : demoId, location.hash == "#trueMode"); lastTime = curTime; }; }, 20); @@ -360,15 +360,15 @@ self.performance = currentPerformance; // Hardcoded animation reference { - let mu80Ani = {class: "mubasic", fps: 10, size: 16}; - let mu1kAni = {class: "munativ", fps: 8, size: 32}; + let mu80Ani = {class: "mubasic", fps: 10, size: 16, offset: 0}; + let mu1kAni = {class: "munativ", fps: 8, size: 32, offset: 0}; demoInfo["ninety_hipty"] = mu80Ani; demoInfo["OutOfTheMuse"] = mu80Ani; demoInfo["MU100DEMO"] = mu80Ani; demoInfo["TheMusithm"] = mu80Ani; demoInfo["MU128DEMO"] = mu80Ani; demoInfo["PhoenixA"] = mu1kAni; - demoInfo["PhoenixB"] = mu1kAni; + demoInfo["PhoenixB"] = {class: "munativ", fps: 8, size: 32, offset: 6}; demoInfo["R-love"] = mu1kAni; }; @@ -494,7 +494,8 @@ self.performance = currentPerformance; // PhoenixA let perf = new TimedEvents(); perf.push(new PointEvent(0, generateString(` YAMAHA TONE GENERATOR `))); - perf.push(new PointEvent(0, generateSwitch(0))); + perf.push(new PointEvent(0.5, {type: 15, data: [67, 16, 73, 0, 0, 18, 1]})); + perf.push(new PointEvent(0.8, generateSwitch(0))); perf.push(new PointEvent(2.52, generateString(` YAMAHA TONE GENERATOR `))); perf.push(new PointEvent(5.04, generateString(` YAMAHA TONE GENERATOR`))); perf.push(new PointEvent(5.21, generateString(` YAMAHA TONE GENERATO`))); @@ -560,7 +561,9 @@ self.performance = currentPerformance; // PhoenixB let perf = new TimedEvents(); perf.push(new PointEvent(0, generateString(` BrtFrHrn 066 061`))); - perf.push(new PointEvent(0, generateSwitch(11))); + perf.push(new PointEvent(0, generateSwitch(2))); + perf.push(new PointEvent(0.5, {type: 15, data: [67, 16, 73, 0, 0, 18, 1]})); + perf.push(new PointEvent(1, generateSwitch(11))); perf.push(new PointEvent(2.02, {type: 15, track: 0, data: [67, 16, 76, 6, 0, 64]})); perf.push(new PointEvent(38.19, generateSwitch(9))); perf.push(new PointEvent(40.05, generateSwitch(16))); @@ -664,6 +667,88 @@ self.performance = currentPerformance; perf.fresh(); demoPerfs["R-love"] = perf; }; +{ + // MU80 demo, Out of the Muse + let perf = new TimedEvents(); + perf.push(new PointEvent(1.6, generateSwitch(19))); + perf.push(new PointEvent(18.92, generateSwitch(3))); + perf.push(new PointEvent(27.29, generateSwitch(2))); + perf.push(new PointEvent(31.47, generateSwitch(9))); + perf.push(new PointEvent(33.49, generateSwitch(10))); + perf.push(new PointEvent(35.52, generateSwitch(19))); + perf.push(new PointEvent(37.62, generateSwitch(1))); + perf.push(new PointEvent(39.73, generateSwitch(3))); + perf.push(new PointEvent(41.83, generateSwitch(6))); + perf.push(new PointEvent(43.93, generateSwitch(18))); + perf.push(new PointEvent(46.03, generateSwitch(19))); + perf.push(new PointEvent(48.13, generateSwitch(21))); + perf.push(new PointEvent(50.23, generateSwitch(24))); + perf.push(new PointEvent(52.34, generateSwitch(3))); + perf.push(new PointEvent(57.76, generateSwitch(4))); + perf.push(new PointEvent(61.12, generateSwitch(3))); + perf.push(new PointEvent(64.11, generateSwitch(4))); + perf.push(new PointEvent(69.84, generateSwitch(6))); + perf.push(new PointEvent(87.48, generateSwitch(4))); + perf.push(new PointEvent(117.12, generateSwitch(23))); + perf.push(new PointEvent(125, generateSwitch(0))); + perf.fresh(); + demoPerfs["OutOfTheMuse"] = perf; +}; +{ + // MU100 demo, It's an AmaZing MU World!! + let perf = new TimedEvents(); + perf.push(new PointEvent(0.5, {type: 15, data: [67, 16, 73, 0, 0, 18, 1]})); + perf.push(new PointEvent(3.28, generateSwitch(1))); + perf.push(new PointEvent(6.22, generateSwitch(5))); + perf.push(new PointEvent(7.93, generateSwitch(6))); + perf.push(new PointEvent(10.92, generateSwitch(5))); + perf.push(new PointEvent(13.98, generateSwitch(6))); + perf.push(new PointEvent(17.31, generateSwitch(5))); + perf.push(new PointEvent(18.64, generateSwitch(6))); + perf.push(new PointEvent(23.93, generateSwitch(11))); + perf.push(new PointEvent(24.41, generateSwitch(2))); + perf.push(new PointEvent(24.89, generateSwitch(9))); + perf.push(new PointEvent(25.37, generateSwitch(10))); + perf.push(new PointEvent(25.89, generateSwitch(3))); + perf.push(new PointEvent(27.87, generateSwitch(1))); + perf.push(new PointEvent(29.85, generateSwitch(3))); + perf.push(new PointEvent(31.83, generateSwitch(2))); + perf.push(new PointEvent(33.81, generateSwitch(9))); + perf.push(new PointEvent(35.79, generateSwitch(10))); + perf.push(new PointEvent(37.75, generateSwitch(9))); + perf.push(new PointEvent(39.73, generateSwitch(25))); + perf.push(new PointEvent(41.84, generateSwitch(15))); + perf.push(new PointEvent(43.93, generateSwitch(14))); + perf.push(new PointEvent(46.02, generateSwitch(15))); + perf.push(new PointEvent(50.25, generateSwitch(16))); + perf.push(new PointEvent(54.46, generateSwitch(15))); + perf.push(new PointEvent(58.37, generateSwitch(16))); + perf.push(new PointEvent(62.34, generateSwitch(15))); + perf.push(new PointEvent(66.58, generateSwitch(16))); + perf.push(new PointEvent(70.41, generateSwitch(15))); + perf.push(new PointEvent(74.64, generateSwitch(25))); + perf.push(new PointEvent(77.96, generateSwitch(14))); + perf.push(new PointEvent(79.97, generateSwitch(25))); + perf.push(new PointEvent(80.47, generateSwitch(10))); + perf.push(new PointEvent(80.97, generateSwitch(9))); + perf.push(new PointEvent(81.48, generateSwitch(14))); + perf.push(new PointEvent(81.98, generateSwitch(17))); + perf.push(new PointEvent(85.99, generateSwitch(18))); + perf.push(new PointEvent(88.03, generateSwitch(19))); + perf.push(new PointEvent(91.49, generateSwitch(20))); + perf.push(new PointEvent(93.15, generateSwitch(21))); + perf.push(new PointEvent(95.98, generateSwitch(22))); + perf.push(new PointEvent(99.99, generateSwitch(24))); + perf.push(new PointEvent(103.91, generateSwitch(22))); + perf.push(new PointEvent(107.97, generateSwitch(24))); + perf.push(new PointEvent(112.04, generateSwitch(22))); + perf.push(new PointEvent(116.05, generateSwitch(24))); + perf.push(new PointEvent(120.07, generateSwitch(22))); + perf.push(new PointEvent(127.1, generateSwitch(9))); + perf.push(new PointEvent(130, generateSwitch(0))); + perf.fresh(); + demoPerfs["MU100DEMO"] = perf; +}; { // The Musithm let perf = new TimedEvents(); @@ -697,8 +782,9 @@ self.performance = currentPerformance; // MU128 demo let perf = new TimedEvents(); // Disable native RS - perf.push(new PointEvent(0, {type: 15, track: 0, data: [67, 16, 73, 0, 0, 14, 0]})); + perf.push(new PointEvent(0, {type: 15, track: 0, data: [67, 16, 73, 0, 0, 68, 0]})); perf.push(new PointEvent(0, generateSwitch(0))); + perf.push(new PointEvent(0.5, {type: 15, data: [67, 16, 73, 0, 0, 18, 1]})); perf.push(new PointEvent(1.6, generateSwitch(0))); perf.push(new PointEvent(40.02, generateSwitch(48))); perf.push(new PointEvent(41.68, generateSwitch(49))); diff --git a/test/fakePsr.htm b/test/fakePsr.htm index 1f8d43cc..609f9d45 100644 --- a/test/fakePsr.htm +++ b/test/fakePsr.htm @@ -42,10 +42,11 @@

Backlight color White, - Green, - Orange, + Green, + Yellowish green, + Orange, Red, - Light blue, + Light blue, Blue.