Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ development artifact builds use `vMAJOR.MINOR.PATCH-dev.N`.
- Added boxed Region start labels to Notation in the timeline track and Notation window.
- Added beat slash notation to Notation measures in the timeline track and Notation window.
- Added a synced Notation window that opens from the View menu or the Notation track context menu, showing the full chart in a notebook-style layout while sharing harmony editing with the timeline track.
- Added a MusicXML-ready notation track MVP with synced staff measures, persisted harmony editing, snapped `A`-key insertion, adaptive measure fitting, and editable project key/mode selectors backed by auto-detected tonal metadata.
- Added a MusicXML-ready notation track MVP with synced staff measures, persisted harmony editing, adaptive measure fitting, and editable project key/mode selectors backed by auto-detected tonal metadata.
- Fixed Notation key and time signature alignment for keys without accidentals and removed gaps between Notation window systems.
- Fixed key-signature accidentals on the Notation track so sharps and flats render on the correct staff positions.

Expand Down
2 changes: 0 additions & 2 deletions JammLab/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ struct ContentView: View {
viewModel.setLoopEndAtCurrentTime()
case .addNote:
viewModel.addNoteAtCurrentTime()
case .addHarmonyAtPlaybackMarker:
viewModel.requestAddHarmonyAtPlaybackMarker()
case .addTempoTimeSignatureMarker:
beginAddingTempoTimeSignatureMarker(at: viewModel.currentTime)
case .setBeatOne:
Expand Down
9 changes: 0 additions & 9 deletions JammLab/Utilities/AppHotkey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ enum AppHotkey: CaseIterable, Hashable {
case setLoopStart
case setLoopEnd
case addNote
case addHarmonyAtPlaybackMarker
case addTempoTimeSignatureMarker
case setBeatOne
case toggleClick
Expand Down Expand Up @@ -53,8 +52,6 @@ enum AppHotkey: CaseIterable, Hashable {
self = .setLoopEnd
case 46:
self = .addNote
case 0:
self = .addHarmonyAtPlaybackMarker
case 11:
self = .setBeatOne
case 8:
Expand All @@ -76,8 +73,6 @@ enum AppHotkey: CaseIterable, Hashable {
return "]"
case .addNote:
return "M"
case .addHarmonyAtPlaybackMarker:
return "A"
case .addTempoTimeSignatureMarker:
return "Shift+C"
case .setBeatOne:
Expand Down Expand Up @@ -105,8 +100,6 @@ enum AppHotkey: CaseIterable, Hashable {
return "Set Loop End"
case .addNote:
return "Add Marker"
case .addHarmonyAtPlaybackMarker:
return "Add Harmony"
case .addTempoTimeSignatureMarker:
return "Add Tempo / Time Signature Marker"
case .setBeatOne:
Expand Down Expand Up @@ -134,8 +127,6 @@ enum AppHotkey: CaseIterable, Hashable {
return "Move loop end to the current playback position."
case .addNote:
return "Add a timecoded note at the current playback position."
case .addHarmonyAtPlaybackMarker:
return "Open a harmony editor at the position marker, snapped to the Notation track resolution."
case .addTempoTimeSignatureMarker:
return "Add a tempo or time signature change marker at the current playback position."
case .setBeatOne:
Expand Down
4 changes: 0 additions & 4 deletions JammLab/ViewModels/AudioPlayerViewModel+Notes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ extension AudioPlayerViewModel {
harmonyInputResolutionDenominator = HarmonyInputResolution.normalizedDenominator(denominator)
}

func requestAddHarmonyAtPlaybackMarker() {
requestAddHarmony(at: playbackMarkerTime)
}

func requestAddHarmony(at time: TimeInterval) {
guard duration > 0,
let placement = harmonyPlacement(for: time, resolution: currentHarmonyInputResolution)
Expand Down
21 changes: 8 additions & 13 deletions JammLabTests/TimelineProjectLogicTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -610,8 +610,13 @@ final class TimelineProjectLogicTests: XCTestCase {
)
}

func testAppHotkeyRecognizesAForHarmonyAtPlaybackMarker() throws {
let event = try XCTUnwrap(NSEvent.keyEvent(
func testAppHotkeyDoesNotExposeHarmonyShortcutMetadata() {
XCTAssertFalse(AppHotkey.allCases.contains { $0.key == "A" })
XCTAssertFalse(AppHotkey.allCases.contains { $0.title == "Add Harmony" })
}

func testAppHotkeyDoesNotRecognizeAOrHForHarmony() throws {
let aEvent = try XCTUnwrap(NSEvent.keyEvent(
with: .keyDown,
location: .zero,
modifierFlags: [],
Expand All @@ -623,17 +628,6 @@ final class TimelineProjectLogicTests: XCTestCase {
isARepeat: false,
keyCode: 0
))

XCTAssertEqual(AppHotkey(event: event), .addHarmonyAtPlaybackMarker)
XCTAssertEqual(AppHotkey.addHarmonyAtPlaybackMarker.key, "A")
XCTAssertEqual(AppHotkey.addHarmonyAtPlaybackMarker.title, "Add Harmony")
XCTAssertEqual(
AppHotkey.addHarmonyAtPlaybackMarker.detail,
"Open a harmony editor at the position marker, snapped to the Notation track resolution."
)
}

func testAppHotkeyDoesNotRecognizeHOrModifiedAForHarmony() throws {
let hEvent = try XCTUnwrap(NSEvent.keyEvent(
with: .keyDown,
location: .zero,
Expand Down Expand Up @@ -671,6 +665,7 @@ final class TimelineProjectLogicTests: XCTestCase {
keyCode: 0
))

XCTAssertNil(AppHotkey(event: aEvent))
XCTAssertNil(AppHotkey(event: hEvent))
XCTAssertNil(AppHotkey(event: commandAEvent))
XCTAssertNil(AppHotkey(event: shiftAEvent))
Expand Down
4 changes: 2 additions & 2 deletions JammLabTests/ViewModelLifecycleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ final class ViewModelLifecycleTests: XCTestCase {
}

@MainActor
func testRequestAddHarmonyAtPlaybackMarkerUsesNotationResolutionSnapWhilePlaying() throws {
func testRequestAddHarmonyAtTimeUsesNotationResolutionSnapWhilePlaying() throws {
let engine = MockPlaybackEngine()
engine.isLoaded = true
let viewModel = AudioPlayerViewModel(playbackEngine: engine)
Expand All @@ -155,7 +155,7 @@ final class ViewModelLifecycleTests: XCTestCase {
XCTAssertEqual(viewModel.playbackMarkerTime, 1.26, accuracy: 0.0001)
XCTAssertEqual(viewModel.currentTime, 3.0, accuracy: 0.0001)

viewModel.requestAddHarmonyAtPlaybackMarker()
viewModel.requestAddHarmony(at: 1.26)

let request = try XCTUnwrap(viewModel.pendingHarmonyEditorRequest)
XCTAssertEqual(request.time, 1.5, accuracy: 0.0001)
Expand Down