performance updates
This commit is contained in:
@@ -942,23 +942,26 @@ private struct DJPlatter: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
private struct DJWaveform: View {
|
||||
struct DJWaveform: View {
|
||||
@State private var frozenStart: Double?
|
||||
@ObservedObject var player: Player
|
||||
let color: Color
|
||||
var bpm: Double?
|
||||
var body: some View {
|
||||
TimelineView(.animation(minimumInterval:1.0/60,paused:!player.playing)) { _ in
|
||||
let displayTime = player.displayTime
|
||||
GeometryReader { geometry in
|
||||
Canvas { context,size in
|
||||
let values = player.waveform
|
||||
guard !values.isEmpty else { return }
|
||||
let count = max(1,Int(size.width/2))
|
||||
var played = Path(),remaining = Path()
|
||||
for i in 0..<count {
|
||||
let index = min(values.count-1,i*values.count/count),height = max(1,Double(values[index])*size.height)
|
||||
context.fill(Path(CGRect(x:Double(i)*size.width/Double(count),y:(size.height-height)/2,width:1.4,height:height)),with:.color(color.opacity(Double(i)/Double(count) < displayTime/max(0.001,player.duration) ? 0.4 : 0.9)))
|
||||
let rect = CGRect(x:Double(i)*size.width/Double(count),y:(size.height-height)/2,width:1.4,height:height)
|
||||
if Double(i)/Double(count) < displayTime/max(0.001,player.duration) { played.addRect(rect) } else { remaining.addRect(rect) }
|
||||
}
|
||||
context.fill(played,with:.color(color.opacity(0.4)))
|
||||
context.fill(remaining,with:.color(color.opacity(0.9)))
|
||||
DJWaveMarkers.draw(context:&context,size:size,start:0,span:player.duration,bpm:bpm,loop:player.loopEnabled ? player.loopIn.flatMap { a in player.loopOut.map { a...$0 } } : nil)
|
||||
|
||||
let x = displayTime/max(0.001,player.duration)*size.width
|
||||
@@ -967,7 +970,6 @@ private struct DJWaveform: View {
|
||||
.overlay { if player.waveformLoading { ProgressView().controlSize(.mini) } else if player.waveformUnavailable { Text("Waveform unavailable").font(.caption2).foregroundStyle(.secondary) } }
|
||||
.modifier(DJLoopWaveInteraction(player:player,start:0,span:player.duration,width:geometry.size.width,frozenStart:$frozenStart))
|
||||
}.accessibilityLabel("Track waveform and position").accessibilityValue(DJStyle.stamp(player.time)).accessibilityAdjustableAction { player.jog($0 == .increment ? 1 : -1) }
|
||||
}
|
||||
}
|
||||
}
|
||||
private struct DJMappingSheet: View {
|
||||
@@ -1226,41 +1228,26 @@ private struct DJCentreWaveform: View {
|
||||
@ObservedObject var player: Player
|
||||
let letter: String
|
||||
let color: Color
|
||||
private var bpm: Double? { deck.bpmConfirmed ? deck.bpm : nil }
|
||||
var settings = DJPreferences()
|
||||
@State private var frozenStart: Double?
|
||||
var body: some View {
|
||||
TimelineView(.animation(minimumInterval:1.0/60,paused:!player.playing)) { _ in
|
||||
let displayTime = player.displayTime
|
||||
GeometryReader { geometry in
|
||||
Canvas { context,size in
|
||||
guard !player.waveform.isEmpty,player.duration > 0 else { return }
|
||||
let span = settings.waveformSeconds,start = frozenStart ?? (displayTime-span/2),count = max(1,Int(size.width/2))
|
||||
for second in 0...8 {
|
||||
let x = Double(second)/8*size.width
|
||||
context.fill(Path(CGRect(x:x,y:0,width:0.5,height:size.height)),with:.color(.white.opacity(settings.showTimeGrid ? 0.15 : 0)))
|
||||
}
|
||||
for i in 0..<count {
|
||||
let seconds = start+Double(i)/Double(count)*span
|
||||
guard seconds >= 0,seconds < player.duration else { continue }
|
||||
let sample = min(Double(player.waveform.count-1),seconds/player.duration*Double(player.waveform.count))
|
||||
let index = Int(sample),next = min(player.waveform.count-1,index+1),fraction = sample-Double(index)
|
||||
let amplitude = Double(player.waveform[index])*(1-fraction)+Double(player.waveform[next])*fraction
|
||||
let height = max(1,amplitude*size.height*0.85)
|
||||
var shade = color
|
||||
if settings.spectralWaveforms,player.waveformBands.indices.contains(index) {
|
||||
let band = player.waveformBands[index],sum = max(0.0001,band.low+band.mid+band.high)
|
||||
shade = Color(hue:Double(band.mid/sum)*0.38+Double(band.high/sum)*0.72,saturation:0.85,brightness:0.95)
|
||||
}
|
||||
context.fill(Path(CGRect(x:Double(i)*size.width/Double(count),y:(size.height-height)/2,width:1.5,height:height)),with:.color(shade))
|
||||
}
|
||||
DJWaveMarkers.draw(context:&context,size:size,start:start,span:span,bpm:bpm,loop:player.loopEnabled ? player.loopIn.flatMap { a in player.loopOut.map { a...$0 } } : nil)
|
||||
let playhead = (displayTime-start)/span*size.width
|
||||
context.fill(Path(CGRect(x:playhead,y:0,width:1.5,height:size.height)),with:.color(.red))
|
||||
}.overlay(alignment:.topLeading) { Text(letter+" · \(Int(settings.waveformSeconds)) s").font(.system(size:9,weight:.semibold)).foregroundStyle(color).padding(5) }
|
||||
.modifier(DJLoopWaveInteraction(player:player,start:displayTime-settings.waveformSeconds/2,span:settings.waveformSeconds,width:geometry.size.width,frozenStart:$frozenStart))
|
||||
}.accessibilityLabel("Deck \(letter) scrolling waveform").accessibilityValue(DJStyle.stamp(player.time))
|
||||
}
|
||||
DJScrollingSpectrum(player:player,bpm:deck.bpmConfirmed ? deck.bpm : nil,color:color,seconds:settings.waveformSeconds,label:letter,accessibilityName:"Deck \(letter) scrolling waveform",showTimeGrid:settings.showTimeGrid,spectralWaveforms:settings.spectralWaveforms)
|
||||
}
|
||||
}
|
||||
|
||||
// The same audio-clock drawing and native mouse interaction serve both studios.
|
||||
struct DJScrollingSpectrum: View {
|
||||
@ObservedObject var player: Player
|
||||
var bpm: Double?
|
||||
var color: Color = .cyan
|
||||
var seconds: Double = 16
|
||||
var label = "KARAOKE"
|
||||
var accessibilityName = "Karaoke scrolling waveform"
|
||||
var showTimeGrid = true
|
||||
var spectralWaveforms = true
|
||||
var body: some View {
|
||||
DJNativeSpectrum(player:player,bpm:bpm,color:NSColor(color),seconds:seconds,label:label,showTimeGrid:showTimeGrid,spectralWaveforms:spectralWaveforms)
|
||||
.accessibilityLabel(accessibilityName).accessibilityValue(DJStyle.stamp(player.time))
|
||||
.help("Hold the left button and drag left to advance or right to rewind. Shift-drag creates a loop; drag green loop edges to resize or its centre to move it.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user