Skip to content

Commit

Permalink
add playback
Browse files Browse the repository at this point in the history
  • Loading branch information
hlorenzi committed Apr 25, 2019
1 parent c7f58da commit 36885e9
Show file tree
Hide file tree
Showing 17 changed files with 957 additions and 73 deletions.
Binary file added audio/piano/a1.mp3
Binary file not shown.
Binary file added audio/piano/a2.mp3
Binary file not shown.
Binary file added audio/piano/a3.mp3
Binary file not shown.
Binary file added audio/piano/a4.mp3
Binary file not shown.
Binary file added audio/piano/a5.mp3
Binary file not shown.
Binary file added audio/piano/a6.mp3
Binary file not shown.
Binary file added audio/piano/a7.mp3
Binary file not shown.
114 changes: 103 additions & 11 deletions src/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ export class Editor
.upsertMeterChange(new MeterChange(new Rational(0, 4), 4, 4))
.upsertMeterChange(new MeterChange(new Rational(11, 4), 5, 4))

.upsertKeyChange(new KeyChange(new Rational(0, 4), new Key(0, 0, scales.major.pitches)))
.upsertKeyChange(new KeyChange(new Rational(7, 4), new Key(5, 1, scales.minor.pitches)))
.upsertKeyChange(new KeyChange(new Rational(9, 4), new Key(7, -1, scales.doubleHarmonic.pitches)))
.upsertKeyChange(new KeyChange(new Rational(0, 4), new Key(0, 0, scales[0].pitches)))
.upsertKeyChange(new KeyChange(new Rational(7, 4), new Key(5, 1, scales[5].pitches)))
.upsertKeyChange(new KeyChange(new Rational(9, 4), new Key(7, -1, scales[7].pitches)))

this.timeScale = 200
this.timeScroll = 0
Expand All @@ -60,10 +60,14 @@ export class Editor
this.refreshLayout()

this.cursorTime = new Range(new Rational(0), new Rational(0))
this.cursorTrack = { start: 0, end: 0 }
this.cursorTrack = { start: 1, end: 1 }
this.cursorShow = true
this.insertionDuration = new Rational(1, 4)

this.playing = false
this.playbackTime = 0
this.playbackTimeRational = new Rational(0)

this.mouseDown = false
this.mouseDownDate = new Date()
this.mouseDownData = { pos: { x: -1, y: -1 }, time: new Rational(0) }
Expand Down Expand Up @@ -120,6 +124,43 @@ export class Editor
setSong(song)
{
this.song = song
this.toolboxRefreshFn()
this.draw()
}


setPlayback(playing)
{
this.playing = playing
this.playbackTime = this.cursorTime.min().asFloat()
this.scrollTimeIntoView(this.cursorTime.min())

this.toolboxRefreshFn()
this.draw()

this.onPlaybackToggle(this.playing)
}


rewind()
{
this.selectionClear()

this.cursorTime = new Range(new Rational(0), new Rational(0))
this.cursorShow = true
this.playbackTime = 0
this.playbackTimeRational = new Rational(0)

if (this.playing)
{
this.setPlayback(false)
this.setPlayback(true)
}
else
this.scrollTimeIntoView(this.cursorTime.start)

this.toolboxRefreshFn()
this.draw()
}


Expand Down Expand Up @@ -183,6 +224,18 @@ export class Editor
}


scrollPlaybackIntoView(time)
{
const margin = this.timeSnap.multiply(new Rational(16))

if (time.compare(this.screenRange.end.subtract(margin)) > 0)
this.timeScroll = time.subtract(margin).asFloat()

else if (time.compare(this.screenRange.start.add(margin)) < 0)
this.timeScroll = time.subtract(margin).asFloat()
}


*enumerateTracksUnderCursor()
{
const trackMin = Math.min(this.cursorTrack.start, this.cursorTrack.end)
Expand Down Expand Up @@ -368,6 +421,14 @@ export class Editor
this.mouseTime = this.getTimeAtPos(this.mousePos)
this.mouseTrack = this.tracks.findIndex(track => track.area.contains(this.mousePos))

const edgeAutoScroll = () =>
{
if (this.mousePos.x > this.width - this.mouseEdgeScrollThreshold)// && this.mousePos.x > mousePosPrev.x)
this.timeScroll += this.timeSnap.asFloat() * this.mouseEdgeScrollSpeed
else if (this.mousePos.x < this.mouseEdgeScrollThreshold)// && this.mousePos.x < mousePosPrev.x)
this.timeScroll -= this.timeSnap.asFloat() * this.mouseEdgeScrollSpeed
}

if (this.mouseDown)
{
if (this.mouseDownAction == Editor.ACTION_PAN)
Expand All @@ -384,17 +445,15 @@ export class Editor
this.cursorTrack = { ...this.cursorTrack, end: this.mouseTrack }

this.selectUnderCursor()

if (this.mousePos.x > this.width - this.mouseEdgeScrollThreshold)// && this.mousePos.x > mousePosPrev.x)
this.timeScroll += this.timeSnap.asFloat() * this.mouseEdgeScrollSpeed
else if (this.mousePos.x < this.mouseEdgeScrollThreshold)// && this.mousePos.x < mousePosPrev.x)
this.timeScroll -= this.timeSnap.asFloat() * this.mouseEdgeScrollSpeed
edgeAutoScroll()
}
else
{
this.curSanitizationMode = "mouse"
for (const track of this.tracks)
track.onDrag({ x: this.mousePos.x - track.area.x, y: this.mousePos.y - track.area.y })

edgeAutoScroll()
}
}
else
Expand Down Expand Up @@ -548,6 +607,12 @@ export class Editor
}
break
}
case " ":
{
this.setPlayback(!this.playing)
handled = true
break
}
case "enter":
case "escape":
{
Expand Down Expand Up @@ -661,6 +726,7 @@ export class Editor
this.ctx.fillRect(0, 0, this.width, this.height)

this.screenRange = new Range(this.getTimeAtPos({ x: 0, y: 0 }), this.getTimeAtPos({ x: this.width, y: 0 }).add(this.timeSnap))
this.playbackTimeRational = Rational.fromFloat(this.playbackTime, new Rational(1, 64))

for (const [curMeter, nextMeter] of this.song.meterChanges.enumerateAffectingRangePairwise(this.screenRange))
{
Expand Down Expand Up @@ -702,7 +768,7 @@ export class Editor
}
}

if (this.cursorShow)
if (this.cursorShow && !this.playing)
this.drawCursorRect()

for (const keyChange of this.song.keyChanges.enumerateOverlappingRange(this.screenRange))
Expand Down Expand Up @@ -741,12 +807,15 @@ export class Editor
this.ctx.restore()
}

if (this.cursorShow)
if (this.cursorShow && !this.playing)
{
this.drawCursorBeam(this.cursorTime.min(), true)
this.drawCursorBeam(this.cursorTime.max(), false)
}

if (this.playing)
this.drawPlaybackBeam(this.playbackTime)

this.ctx.restore()
}

Expand Down Expand Up @@ -807,4 +876,27 @@ export class Editor

this.ctx.restore()
}


drawPlaybackBeam(time)
{
const trackMin = 0
const trackMax = this.tracks.length - 1

this.ctx.save()

const offset = time - this.timeScroll
const x = offset * this.timeScale

this.ctx.strokeStyle = "#f00"
this.ctx.lineCap = "round"
this.ctx.lineWidth = 3

this.ctx.beginPath()
this.ctx.moveTo(this.tracks[trackMin].area.x + x, this.tracks[trackMin].area.y)
this.ctx.lineTo(this.tracks[trackMax].area.x + x, this.tracks[trackMax].area.y + this.tracks[trackMax].area.h)
this.ctx.stroke()

this.ctx.restore()
}
}
12 changes: 7 additions & 5 deletions src/editor/editorChords.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class EditorChords

this.alterSelectedChords((data, origData, changes) =>
{
const keyChange = this.owner.song.keyChanges.findActiveAt(data.range.start) || new KeyChange(data.range.start, new Key(0, 0, scales.major.pitches))
const keyChange = this.owner.song.keyChanges.findActiveAt(data.range.start) || new KeyChange(data.range.start, new Key(0, 0, scales[0].pitches))
const scaleDegree = getScaleDegreeForPitch(keyChange.key, data.chord.rootPitch)
changes.chord = data.chord.withChanges({ rootPitch: getPitchForScaleDegree(keyChange.key, scaleDegree + offset) })
})
Expand Down Expand Up @@ -300,8 +300,8 @@ export class EditorChords
{
for (const pair of this.owner.song.keyChanges.enumerateAffectingRangePairwise(this.owner.screenRange))
{
const curKey = pair[0] || new KeyChange(this.owner.screenRange.start, new Key(0, 0, scales.major.pitches))
const nextKey = pair[1] || new KeyChange(this.owner.screenRange.end, new Key(0, 0, scales.major.pitches))
const curKey = pair[0] || new KeyChange(this.owner.screenRange.start, new Key(0, 0, scales[0].pitches))
const nextKey = pair[1] || new KeyChange(this.owner.screenRange.end, new Key(0, 0, scales[0].pitches))

const xStart = (curKey .time.asFloat() - this.owner.timeScroll) * this.owner.timeScale
const xEnd = (nextKey.time.asFloat() - this.owner.timeScroll) * this.owner.timeScale
Expand Down Expand Up @@ -359,7 +359,9 @@ export class EditorChords
this.owner.ctx.fillText(chordData.symbol[2], rect.x + rect.w / 2 + mainStrWidth.width / 2, rect.y + rect.h / 2 - 8, rect.w - 6)
}

if (this.owner.selection.has(chord.id))
const playbackOverlaps = (this.owner.playing && chord.range.overlapsPoint(this.owner.playbackTimeRational))

if (playbackOverlaps || (!this.owner.playing && this.owner.selection.has(chord.id)))
{
this.owner.ctx.globalAlpha = 0.5
this.owner.ctx.fillStyle = "#fff"
Expand All @@ -368,7 +370,7 @@ export class EditorChords
this.owner.ctx.globalAlpha = 1
}

if (this.hoverId == chord.id)
if (playbackOverlaps || this.hoverId == chord.id)
{
this.owner.ctx.globalAlpha = 0.5
this.owner.ctx.fillStyle = "#fee"
Expand Down
18 changes: 10 additions & 8 deletions src/editor/editorNotes.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export class EditorNotes
this.hoverId = -1
for (const pair of this.owner.song.keyChanges.enumerateAffectingRangePairwise(this.owner.screenRange))
{
const curKey = pair[0] || new KeyChange(this.owner.screenRange.start, new Key(0, 0, scales.major.pitches))
const nextKey = pair[1] || new KeyChange(this.owner.screenRange.end, new Key(0, 0, scales.major.pitches))
const curKey = pair[0] || new KeyChange(this.owner.screenRange.start, new Key(0, 0, scales[0].pitches))
const nextKey = pair[1] || new KeyChange(this.owner.screenRange.end, new Key(0, 0, scales[0].pitches))

const xStart = (curKey .time.asFloat() - this.owner.timeScroll) * this.owner.timeScale
const xEnd = (nextKey.time.asFloat() - this.owner.timeScroll) * this.owner.timeScale
Expand Down Expand Up @@ -129,7 +129,7 @@ export class EditorNotes

this.alterSelectedNotes((data, origData, changes) =>
{
const keyChange = this.owner.song.keyChanges.findActiveAt(data.range.start) || new KeyChange(data.range.start, new Key(0, 0, scales.major.pitches))
const keyChange = this.owner.song.keyChanges.findActiveAt(data.range.start) || new KeyChange(data.range.start, new Key(0, 0, scales[0].pitches))
const scaleDegree = getScaleDegreeForPitch(keyChange.key, data.pitch)
changes.pitch = getPitchForScaleDegree(keyChange.key, scaleDegree + offset)
})
Expand Down Expand Up @@ -318,7 +318,7 @@ export class EditorNotes

if (this.owner.mouseDownAction & Editor.ACTION_DRAG_PITCH)
{
const keyChange = this.owner.song.keyChanges.findActiveAt(noteOrigData.range.start) || new KeyChange(noteOrigData.range.start, new Key(0, 0, scales.major.pitches))
const keyChange = this.owner.song.keyChanges.findActiveAt(noteOrigData.range.start) || new KeyChange(noteOrigData.range.start, new Key(0, 0, scales[0].pitches))
const scaleDegree = getScaleDegreeForPitch(keyChange.key, noteOrigData.pitch)
const newPitch = getPitchForScaleDegree(keyChange.key, scaleDegree + rowOffset)
changes.pitch = newPitch
Expand All @@ -339,8 +339,8 @@ export class EditorNotes
{
for (const pair of this.owner.song.keyChanges.enumerateAffectingRangePairwise(this.owner.screenRange))
{
const curKey = pair[0] || new KeyChange(this.owner.screenRange.start, new Key(0, 0, scales.major.pitches))
const nextKey = pair[1] || new KeyChange(this.owner.screenRange.end, new Key(0, 0, scales.major.pitches))
const curKey = pair[0] || new KeyChange(this.owner.screenRange.start, new Key(0, 0, scales[0].pitches))
const nextKey = pair[1] || new KeyChange(this.owner.screenRange.end, new Key(0, 0, scales[0].pitches))

const xStart = (curKey .time.asFloat() - this.owner.timeScroll) * this.owner.timeScale
const xEnd = (nextKey.time.asFloat() - this.owner.timeScroll) * this.owner.timeScale
Expand Down Expand Up @@ -384,7 +384,9 @@ export class EditorNotes
this.owner.ctx.fillStyle = color
this.owner.ctx.fillRect(rect.x + 1, rect.y, rect.w - 2, rect.h)

if (this.owner.selection.has(note.id))
const playbackOverlaps = (this.owner.playing && note.range.overlapsPoint(this.owner.playbackTimeRational))

if (playbackOverlaps || (!this.owner.playing && this.owner.selection.has(note.id)))
{
this.owner.ctx.globalAlpha = 0.5
this.owner.ctx.fillStyle = "#fff"
Expand All @@ -393,7 +395,7 @@ export class EditorNotes
this.owner.ctx.globalAlpha = 1
}

if (this.hoverId == note.id)
if (playbackOverlaps || this.hoverId == note.id)
{
this.owner.ctx.globalAlpha = 0.5
this.owner.ctx.fillStyle = "#fee"
Expand Down
Loading

0 comments on commit 36885e9

Please sign in to comment.