Skip to content

Commit

Permalink
fix #7: automatically add note block when using number keys
Browse files Browse the repository at this point in the history
  • Loading branch information
hlorenzi committed Feb 5, 2021
1 parent 8fc7a94 commit 5795734
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 51 deletions.
50 changes: 50 additions & 0 deletions src/timeline/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,18 @@ export function cursorSetTrack(
}


export function cursorSetTrackByParentId(
data: WorkData,
parentId: Project.ID)
{
const trackIndex = data.state.tracks.findIndex(tr => tr.parentId === parentId)
if (trackIndex < 0)
return

data.state.cursor.trackIndex1 = data.state.cursor.trackIndex2 = trackIndex
}


export function findPreviousAnchor(
data: WorkData,
time: Rational,
Expand Down Expand Up @@ -1034,6 +1046,44 @@ export function insertChord(data: WorkData, time: Rational, chord: Theory.Chord)
}


export function insertNoteBlock(data: WorkData, time: Rational): Project.ID | null
{
keyHandlePendingFinish(data)

const track = data.state.tracks[data.state.cursor.trackIndex1]
if (!(track instanceof Timeline.TimelineTrackNoteBlocks))
return null

let endTime = time.add(new Rational(4))

const list = Project.global.project.lists.get(track.projectTrackId)
if (list)
{
for (const elem of list.iterAtRange(new Range(time, endTime)))
endTime = endTime.min(elem.range.start)
}

if (endTime.compare(time) <= 0)
return null

const noteBlock = Project.makeNoteBlock(
track.projectTrackId,
new Range(time, endTime))

let project = Project.global.project
const id = project.nextId
project = Project.upsertElement(project, noteBlock)
project = Project.withRefreshedRange(project)
Project.global.project = project

scrollTimeIntoView(data, time)
selectionClear(data)
selectionAdd(data, id)
selectionRemoveConflictingBehind(data)
return id
}


export function visibleTimeRange(data: WorkData): Range
{
return new Range(
Expand Down
126 changes: 75 additions & 51 deletions src/timeline/state_keyDown.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as Editor from "./index"
import * as Timeline from "./index"
import * as Project from "../project"
import * as Prefs from "../prefs"
import * as Theory from "../theory"
Expand All @@ -7,7 +7,7 @@ import Range from "../util/range"
import Rational from "../util/rational"


export function keyDown(data: Editor.WorkData, key: string)
export function keyDown(data: Timeline.WorkData, key: string)
{
data.state.keysDown.add(key)

Expand Down Expand Up @@ -52,7 +52,7 @@ export function keyDown(data: Editor.WorkData, key: string)
case "c":
{
if (data.state.keysDown.has("control"))
Editor.selectionCopy(data)
Timeline.selectionCopy(data)

break
}
Expand All @@ -61,8 +61,8 @@ export function keyDown(data: Editor.WorkData, key: string)
{
if (data.state.keysDown.has("control"))
{
Editor.selectionCopy(data)
Editor.selectionDelete(data)
Timeline.selectionCopy(data)
Timeline.selectionDelete(data)
Project.splitUndoPoint()
Project.addUndoPoint("cut")
}
Expand All @@ -74,7 +74,7 @@ export function keyDown(data: Editor.WorkData, key: string)
{
if (data.state.keysDown.has("control"))
{
Editor.paste(data)
Timeline.paste(data)
Project.splitUndoPoint()
Project.addUndoPoint("copy")
}
Expand Down Expand Up @@ -163,7 +163,7 @@ export function keyDown(data: Editor.WorkData, key: string)


function modifySelectedElems(
data: Editor.WorkData,
data: Timeline.WorkData,
func: (elem: Project.Element) => Project.Element)
{
let newProject = Project.global.project
Expand All @@ -185,7 +185,7 @@ function modifySelectedElems(
}


function handleEscape(data: Editor.WorkData)
function handleEscape(data: Timeline.WorkData)
{
if (Playback.global.playing)
{
Expand All @@ -194,12 +194,12 @@ function handleEscape(data: Editor.WorkData)
}
else
{
Editor.rewind(data)
Timeline.rewind(data)
}
}


function handleEnter(data: Editor.WorkData)
function handleEnter(data: Timeline.WorkData)
{
if (data.state.cursor.visible && data.state.selection.size != 0)
{
Expand All @@ -209,7 +209,7 @@ function handleEnter(data: Editor.WorkData)

data.state.cursor.visible = true

const range = Editor.selectionRange(data)
const range = Timeline.selectionRange(data)
if (range)
{
let trackId = data.state.tracks[0].projectTrackId
Expand All @@ -220,27 +220,27 @@ function handleEnter(data: Editor.WorkData)

const trackIndex = data.state.tracks.findIndex(tr => tr.projectTrackId === trackId)

Editor.cursorSetTime(data, range.end, range.end)
Editor.cursorSetTrack(data, trackIndex, trackIndex)
Editor.scrollTimeIntoView(data, range.end)
Timeline.cursorSetTime(data, range.end, range.end)
Timeline.cursorSetTrack(data, trackIndex, trackIndex)
Timeline.scrollTimeIntoView(data, range.end)
}

Editor.keyHandlePendingFinish(data)
Editor.selectionClear(data)
Timeline.keyHandlePendingFinish(data)
Timeline.selectionClear(data)
}


function handleDelete(data: Editor.WorkData)
function handleDelete(data: Timeline.WorkData)
{
Editor.selectionDelete(data)
Timeline.selectionDelete(data)
}


function handleBackspace(data: Editor.WorkData)
function handleBackspace(data: Timeline.WorkData)
{
if (!data.state.cursor.visible)
{
Editor.selectionDelete(data)
Timeline.selectionDelete(data)
return
}

Expand All @@ -250,31 +250,31 @@ function handleBackspace(data: Editor.WorkData)
if (data.state.cursor.time1.compare(data.state.cursor.time2) == 0)
{
const time = data.state.cursor.time1.min(data.state.cursor.time2)
const prevAnchor = Editor.findPreviousAnchor(data, time, track1, track2)
const prevAnchor = Timeline.findPreviousAnchor(data, time, track1, track2)
const range = new Range(prevAnchor, time, false, false)
Editor.deleteRange(data, range, track1, track2)
Timeline.deleteRange(data, range, track1, track2)

data.state.cursor.visible = true
Editor.cursorSetTime(data, prevAnchor, prevAnchor)
Editor.scrollTimeIntoView(data, prevAnchor)
Timeline.cursorSetTime(data, prevAnchor, prevAnchor)
Timeline.scrollTimeIntoView(data, prevAnchor)
}
else
{
const time1 = data.state.cursor.time1.min(data.state.cursor.time2)
const time2 = data.state.cursor.time1.max(data.state.cursor.time2)
const range = new Range(time1, time2, false, false)
Editor.deleteRange(data, range, track1, track2)
Timeline.deleteRange(data, range, track1, track2)

data.state.cursor.visible = true
Editor.cursorSetTime(data, time1, time1)
Editor.scrollTimeIntoView(data, time1)
Timeline.cursorSetTime(data, time1, time1)
Timeline.scrollTimeIntoView(data, time1)
}

Project.global.project = Project.withRefreshedRange(Project.global.project)
}


function handleLeftRight(data: Editor.WorkData, isLeft: boolean)
function handleLeftRight(data: Timeline.WorkData, isLeft: boolean)
{
const keyFast = data.state.keysDown.has(Prefs.global.editor.keyDisplaceFast)
const keyCursor2 = data.state.keysDown.has(Prefs.global.editor.keyDisplaceCursor2)
Expand All @@ -294,15 +294,15 @@ function handleLeftRight(data: Editor.WorkData, isLeft: boolean)
const timeDelta = data.state.timeSnap.multiplyByFloat(
(keyFast ? 16 : 1) * (isLeft ? -1 : 1))

Editor.keyHandlePendingFinish(data)
Timeline.keyHandlePendingFinish(data)

if (keyCursor2)
{
const newTime = data.state.cursor.time2.add(timeDelta)
Editor.cursorSetTime(data, null, newTime)
Editor.selectionClear(data)
Editor.selectionAddAtCursor(data)
Editor.scrollTimeIntoView(data, newTime)
Timeline.cursorSetTime(data, null, newTime)
Timeline.selectionClear(data)
Timeline.selectionAddAtCursor(data)
Timeline.scrollTimeIntoView(data, newTime)
Playback.setStartTime(newTime)
}
else
Expand All @@ -312,8 +312,8 @@ function handleLeftRight(data: Editor.WorkData, isLeft: boolean)

const newTime = (isLeft ? timeMin : timeMax).add(timeDelta)

Editor.cursorSetTime(data, newTime, newTime)
Editor.scrollTimeIntoView(data, newTime)
Timeline.cursorSetTime(data, newTime, newTime)
Timeline.scrollTimeIntoView(data, newTime)
Playback.setStartTime(newTime)
}
}
Expand All @@ -322,7 +322,7 @@ function handleLeftRight(data: Editor.WorkData, isLeft: boolean)
const timeDelta = data.state.timeSnap.multiplyByFloat(
(keyFast ? 16 : 1) * (isLeft ? -1 : 1))

const selectionRange = Editor.selectionRange(data)
const selectionRange = Timeline.selectionRange(data)

let playedPreview = false
modifySelectedElems(data, (elem) =>
Expand Down Expand Up @@ -368,18 +368,18 @@ function handleLeftRight(data: Editor.WorkData, isLeft: boolean)
})
})

const range = Editor.selectionRange(data) || new Range(new Rational(0), new Rational(0))
const range = Timeline.selectionRange(data) || new Range(new Rational(0), new Rational(0))
const newTime = (isLeft && !keyStretch ? range.start : range.end)
data.state.cursor.visible = false
Editor.cursorSetTime(data, newTime, newTime)
Editor.scrollTimeIntoView(data, newTime)
Timeline.cursorSetTime(data, newTime, newTime)
Timeline.scrollTimeIntoView(data, newTime)

data.state.needsKeyFinish = true
}
}


function handleUpDown(data: Editor.WorkData, isUp: boolean, isChromatic: boolean)
function handleUpDown(data: Timeline.WorkData, isUp: boolean, isChromatic: boolean)
{
const keyFast = data.state.keysDown.has(Prefs.global.editor.keyDisplaceFast)
const keyCursor2 = data.state.keysDown.has(Prefs.global.editor.keyDisplaceCursor2)
Expand All @@ -390,22 +390,22 @@ function handleUpDown(data: Editor.WorkData, isUp: boolean, isChromatic: boolean
{
const trackDelta = (isUp ? -1 : 1)

Editor.keyHandlePendingFinish(data)
Timeline.keyHandlePendingFinish(data)

if (keyCursor2)
{
const newTrack = data.state.cursor.trackIndex2 + trackDelta
Editor.cursorSetTrack(data, null, newTrack)
Editor.selectionClear(data)
Editor.selectionAddAtCursor(data)
Timeline.cursorSetTrack(data, null, newTrack)
Timeline.selectionClear(data)
Timeline.selectionAddAtCursor(data)
}
else
{
const trackMin = Math.min(data.state.cursor.trackIndex1, data.state.cursor.trackIndex2)
const trackMax = Math.max(data.state.cursor.trackIndex1, data.state.cursor.trackIndex2)

const newTrack = (isUp ? trackMin : trackMax) + trackDelta
Editor.cursorSetTrack(data, newTrack, newTrack)
Timeline.cursorSetTrack(data, newTrack, newTrack)
}
}
else
Expand Down Expand Up @@ -471,14 +471,14 @@ function handleUpDown(data: Editor.WorkData, isUp: boolean, isChromatic: boolean
}


function handleNumber(data: Editor.WorkData, degree: number)
function handleNumber(data: Timeline.WorkData, degree: number)
{
const time = data.state.cursor.time1.min(data.state.cursor.time2)
const track = data.state.tracks[data.state.cursor.trackIndex1]
const trackId = track.projectTrackId
const key = Project.keyAt(Project.global.project, trackId, time)

if (track instanceof Editor.TimelineTrackChords)
if (track instanceof Timeline.TimelineTrackChords)
{
const root = key.midiForDegree(degree)

Expand All @@ -488,17 +488,33 @@ function handleNumber(data: Editor.WorkData, degree: number)

const kind = Theory.Chord.kindFromPitches(pitches)
const chord = new Theory.Chord(root, kind, 0, [])
Editor.insertChord(data, time, chord)
Timeline.insertChord(data, time, chord)
}
else if (track instanceof Timeline.TimelineTrackNoteBlocks)
{
const noteBlockId = Timeline.insertNoteBlock(data, time)
if (!noteBlockId)
return

Timeline.modeStackPush(data)
data.state.mode = Timeline.Mode.NoteBlock
data.state.modeNoteBlockId = noteBlockId
Timeline.refreshTracks(data)

Timeline.cursorSetTrackByParentId(data, noteBlockId)

const chroma = key.chromaForDegree(degree)
Timeline.insertNote(data, time, chroma)
}
else
{
const chroma = key.chromaForDegree(degree)
Editor.insertNote(data, time, chroma)
Timeline.insertNote(data, time, chroma)
}
}


function handleLengthChange(data: Editor.WorkData, lengthIndex: number)
function handleLengthChange(data: Timeline.WorkData, lengthIndex: number)
{
const lengths = [
new Rational(1, 16),
Expand All @@ -514,12 +530,20 @@ function handleLengthChange(data: Editor.WorkData, lengthIndex: number)
{
if (elem.type == "note" || elem.type == "chord")
{
data.state.insertion.duration = length

const newRange = Range.fromStartDuration(elem.range.start, length)
return Project.elemModify(elem, { range: newRange })
}
else
return elem
})


const range = Timeline.selectionRange(data) || new Range(new Rational(0), new Rational(0))
const newTime = range.end
data.state.cursor.visible = false
Timeline.cursorSetTime(data, newTime, newTime)
Timeline.scrollTimeIntoView(data, newTime)

data.state.needsKeyFinish = true
}

0 comments on commit 5795734

Please sign in to comment.