Skip to content

Commit

Permalink
Fixed disappearing notes with the new rendering engine
Browse files Browse the repository at this point in the history
- onlinesequencer is a wonderful debugging tool
  • Loading branch information
spessasus committed Aug 10, 2023
1 parent 9cfc1ee commit 9e1545f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 97 deletions.
63 changes: 22 additions & 41 deletions src/spessasynth_lib/sequencer/sequencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,6 @@ export class Sequencer {
this.play();
if(this.renderer)
{
this.rendererEventIndex = this.eventIndex;
this.renderedTime = this.playedTime - (this.renderer.noteAfterTriggerTimeMs / 1000);
this.rendererOTTS = this.oneTickToSeconds;
this.renderer.noteStartTime = this.absoluteStartTime;
this.resetRendererIndexes();
}
Expand All @@ -125,16 +122,6 @@ export class Sequencer {
{
this.renderer = renderer;

/**
* Offset by rendere's note falling time
* @type {number}
*/
this.rendererEventIndex = 0;

// for the renderer
this.renderedTime = this.playedTime;

this.rendererOTTS = this.oneTickToSeconds;

/**
* an array of 16 arrays (channels) and the notes are stored there
Expand All @@ -151,7 +138,6 @@ export class Sequencer {
*/

/**
*
* @type {NoteTimes}
*/
const noteTimes = [];
Expand Down Expand Up @@ -364,8 +350,6 @@ export class Sequencer {
if(this.renderer)
{
this.renderer.clearNotes();
this.rendererEventIndex = this.eventIndex;
this.renderedTime = this.playedTime;
}

// unpause if paused
Expand Down Expand Up @@ -397,9 +381,6 @@ export class Sequencer {
this.play();
if(this.renderer)
{
this.rendererEventIndex = this.eventIndex;
this.renderedTime = this.playedTime - (this.renderer.noteAfterTriggerTimeMs / 1000);
this.rendererOTTS = this.oneTickToSeconds;
this.renderer.noteStartTime = this.absoluteStartTime;
this.resetRendererIndexes();
}
Expand Down Expand Up @@ -502,28 +483,6 @@ export class Sequencer {
const statusByteData = getEvent(event.messageStatusByte);
// process the event
switch (statusByteData.status) {
case messageTypes.setTempo:
this.oneTickToSeconds = 60 / (this.getTempo(event) * this.midiData.timeDivision);
if(this.oneTickToSeconds === 0)
{
this.oneTickToSeconds = 60 / (120 * this.midiData.timeDivision);
console.warn("invalid tempo! falling back to 120 BPM");
}
break;

case messageTypes.endOfTrack:
case messageTypes.midiChannelPrefix:
case messageTypes.timeSignature:
case messageTypes.songPosition:
case messageTypes.activeSensing:
case messageTypes.keySignature:
case messageTypes.midiPort:
break;

default:
console.log("Unrecognized Event:", event.messageStatusByte, "status byte:", Object.keys(messageTypes).find(k => messageTypes[k] === statusByteData.status));
break;

case messageTypes.noteOn:
const velocity = event.messageData[1];
if(velocity > 0) {
Expand All @@ -548,6 +507,28 @@ export class Sequencer {
n.midiNote === event.messageData[0] && n.channel === statusByteData.channel), 1);
break;

case messageTypes.setTempo:
this.oneTickToSeconds = 60 / (this.getTempo(event) * this.midiData.timeDivision);
if(this.oneTickToSeconds === 0)
{
this.oneTickToSeconds = 60 / (120 * this.midiData.timeDivision);
console.warn("invalid tempo! falling back to 120 BPM");
}
break;

case messageTypes.endOfTrack:
case messageTypes.midiChannelPrefix:
case messageTypes.timeSignature:
case messageTypes.songPosition:
case messageTypes.activeSensing:
case messageTypes.keySignature:
case messageTypes.midiPort:
break;

default:
console.log("Unrecognized Event:", event.messageStatusByte, "status byte:", Object.keys(messageTypes).find(k => messageTypes[k] === statusByteData.status));
break;

case messageTypes.pitchBend:
this.synth.pitchWheel(statusByteData.channel, event.messageData[1], event.messageData[0]);
break;
Expand Down
2 changes: 0 additions & 2 deletions src/website/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ export class Manager
window.addEventListener("resize", () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
this.renderer.noteFieldHeight = window.innerHeight;
this.renderer.noteFieldWidth = window.innerWidth;
});

this.renderer = new Renderer(this.channelColors, this.synth, canvas);
Expand Down
67 changes: 13 additions & 54 deletions src/website/ui/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ const NOTE_MARGIN = 1;
const FONT_SIZE = 16;

// limits
const MIN_NOTE_HEIGHT_PX = 7;
const MIN_NOTE_HEIGHT_PX = 5;
const MAX_NOTES = 81572;
const MIN_NOTE_TIME_MS = 20;


export class Renderer
Expand All @@ -33,7 +32,6 @@ export class Renderer
this.renderBool = true;
this.renderAnalysers = true;
this.renderNotes = true;
this.noteCap = MAX_NOTES * (this.noteFallingTimeMs + this.noteAfterTriggerTimeMs) / 1000;

this.channelColors = channelColors;
this.darkerColors = this.channelColors.map(c => calculateRGB(c, v => v * DARKER_MULTIPLIER));
Expand Down Expand Up @@ -91,47 +89,6 @@ export class Renderer
}
}

/**
* Creates a new note that starts falling
* @param midiNote {number}
* @param channel {number}
* @param timeOffsetMs {number} in miliseconds, how low should the note start. 0 means it starts falling from the top
*/
startNoteFall(midiNote, channel, timeOffsetMs = 0)
{
if(this.noteCap < this.fallingNotes.length)
{
return;
}
if(this.renderNotes) {
this.fallingNotes.push({
midiNote: midiNote,
channel: channel,
timeMs: Infinity,
startMs: this.getCurrentTime() - timeOffsetMs
});
}
};

/**
* Ends the falling note
* @param midiNote {number}
* @param channel {number}
* @param timeOffsetMs {number} in miliseconds, how low should the note cut off. 0 means it cuts off from the top
*/
stopNoteFall(midiNote, channel, timeOffsetMs = 0)
{
for(const note of this.fallingNotes.filter(note =>
note.midiNote === midiNote &&
note.channel === channel &&
note.timeMs === Infinity))
{
note.timeMs = this.getCurrentTime() - timeOffsetMs - note.startMs;
if(note.timeMs < MIN_NOTE_TIME_MS) note.timeMs = MIN_NOTE_TIME_MS;
}
//this.fallingNotes.sort((na, nb) => (nb.timeMs - na.timeMs) + (na.channel - nb.channel));
}

/**
* @param noteTimes {NoteTimes}
* @param sequencer {Sequencer}
Expand Down Expand Up @@ -203,8 +160,6 @@ export class Renderer
this.drawingContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
}

this.noteCap = MAX_NOTES * (this.noteFallingTimeMs + this.noteAfterTriggerTimeMs) / 1000;

this.drawingContext.textAlign = "start";
this.drawingContext.textBaseline = "hanging";
this.drawingContext.fillStyle = "#ccc";
Expand Down Expand Up @@ -245,6 +200,7 @@ export class Renderer
const currentStartTime = currentSeqTime - afterTime;
const fallingTimeSeconds = fallingTime + afterTime;
const currentEndTime = currentStartTime + fallingTimeSeconds;
const minNoteHeight = MIN_NOTE_HEIGHT_PX / fallingTimeSeconds;

this.noteTimes.forEach((channel, channelNumder) => {

Expand All @@ -254,27 +210,29 @@ export class Renderer
const notes = channel.notes;
let note = notes[noteIndex];

let firstNoteIndex = -1;

// while the note start is in range
while(note.start <= currentEndTime){
noteIndex++;
// cap notes
if(this.notesOnScreen > MAX_NOTES)
{
return;
break;
}

const noteSum = note.start + note.length

// if the note is out of range, append the render start index
if(noteSum < currentStartTime)
{
channel.renderStartIndex = noteIndex - 1;
}
else {
if(noteSum > currentStartTime) {
const height = (note.length / fallingTimeSeconds) * this.canvas.height - (NOTE_MARGIN * 2);

// height less than that can be ommitted (come on)
if(height > MIN_NOTE_HEIGHT_PX) {
if(height > minNoteHeight) {
if(firstNoteIndex === -1)
{
firstNoteIndex = noteIndex - 1;
}
const yPos = this.canvas.height - height
- (((note.start - currentStartTime) / fallingTimeSeconds) * this.canvas.height + NOTE_MARGIN);

Expand All @@ -294,11 +252,12 @@ export class Renderer

if(noteIndex >= notes.length)
{
return;
break;
}

note = notes[noteIndex];
}
if(firstNoteIndex > -1) channel.renderStartIndex = firstNoteIndex;
})


Expand Down

0 comments on commit 9e1545f

Please sign in to comment.