Skip to content

Commit 1428c50

Browse files
committed
更新版本号至1.1.0-rc.202512100936;波形优化
1 parent 7adfae1 commit 1428c50

2 files changed

Lines changed: 109 additions & 9 deletions

File tree

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "frkb",
3-
"version": "1.1.0-rc.202512100918",
3+
"version": "1.1.0-rc.202512100936",
44
"description": "Rapid Audio Organization Tool",
55
"main": "./out/main/index.js",
66
"author": "CoderDJing",

‎src/renderer/src/pages/modules/songPlayer/useWaveform.ts‎

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,75 @@ export function useWaveform(params: {
8383

8484
const useHalfWaveform = () => (runtime.setting?.waveformMode ?? 'half') !== 'full'
8585

86+
const drawFineWaveform = (width: number, height: number) => {
87+
if (!soundCloudMinMaxData || !audioBuffer) {
88+
clearCanvases()
89+
return
90+
}
91+
92+
const totalBars = soundCloudMinMaxData.length
93+
if (!totalBars) {
94+
clearCanvases()
95+
return
96+
}
97+
98+
if (!baseCtx || !progressCtx) throw new Error('canvas context is null')
99+
100+
const pixelRatio = window.devicePixelRatio || 1
101+
resizeCanvas(baseCanvas, baseCtx, width, height, pixelRatio)
102+
resizeCanvas(progressCanvas, progressCtx, width, height, pixelRatio)
103+
104+
const spacing = width / totalBars
105+
const gap = Math.min(barGap, spacing * 0.25)
106+
let drawWidth = spacing - gap
107+
drawWidth = Math.min(barWidth, drawWidth)
108+
if (drawWidth <= 0) {
109+
drawWidth = spacing || 1
110+
}
111+
drawWidth = Math.max(0.2, Math.min(drawWidth, spacing))
112+
const offset = spacing > drawWidth ? (spacing - drawWidth) / 2 : 0
113+
114+
const midY = height / 2
115+
const isHalf = useHalfWaveform()
116+
const baselineY = isHalf ? height : midY
117+
const scaleY = isHalf ? baselineY : midY
118+
119+
const baseGradient = baseCtx.createLinearGradient(0, 0, 0, height)
120+
baseGradient.addColorStop(0, '#cccccc')
121+
baseGradient.addColorStop(1, '#cccccc')
122+
123+
const progressGradient = progressCtx.createLinearGradient(0, 0, 0, height)
124+
progressGradient.addColorStop(0, '#0078d4')
125+
progressGradient.addColorStop(1, '#0078d4')
126+
127+
baseCtx.fillStyle = baseGradient
128+
progressCtx.fillStyle = progressGradient
129+
130+
for (let index = 0; index < totalBars; index++) {
131+
const { min, max } = soundCloudMinMaxData[index]
132+
const x = index * spacing + offset
133+
const clampedX = Math.max(0, Math.min(width - drawWidth, x))
134+
135+
if (isHalf) {
136+
const amplitude = Math.max(Math.abs(min), Math.abs(max))
137+
const rectHeight = Math.max(1, amplitude * scaleY)
138+
const y = baselineY - rectHeight
139+
baseCtx.fillRect(clampedX, y, drawWidth, rectHeight)
140+
progressCtx.fillRect(clampedX, y, drawWidth, rectHeight)
141+
} else {
142+
const barMin = midY + min * midY
143+
const barMax = midY + max * midY
144+
const rectHeight = Math.max(1, barMax - barMin)
145+
baseCtx.fillRect(clampedX, barMin, drawWidth, rectHeight)
146+
progressCtx.fillRect(clampedX, barMin, drawWidth, rectHeight)
147+
}
148+
}
149+
}
150+
86151
const computeColumnMetrics = (
87152
columnCount: number,
88-
waveformData: RGBWaveformData | null
153+
waveformData: RGBWaveformData | null,
154+
skipDownsample = false
89155
): ColumnMetrics[] => {
90156
if (!waveformData || columnCount <= 0) return []
91157

@@ -99,10 +165,10 @@ export function useWaveform(params: {
99165

100166
const duration = waveformData.duration || 0
101167
const targetPoints =
102-
duration > 0
103-
? Math.max(1, Math.floor(duration * REKORDBOX_MINI_POINTS_PER_SECOND))
104-
: totalPoints
105-
const reductionStride = Math.max(1, Math.floor(totalPoints / targetPoints))
168+
skipDownsample || duration <= 0
169+
? totalPoints
170+
: Math.max(1, Math.floor(duration * REKORDBOX_MINI_POINTS_PER_SECOND))
171+
const reductionStride = skipDownsample ? 1 : Math.max(1, Math.floor(totalPoints / targetPoints))
106172
const effectiveTotalPoints = Math.max(1, Math.floor(totalPoints / reductionStride))
107173

108174
const samplesPerColumn = Math.max(1, effectiveTotalPoints / Math.max(1, columnCount))
@@ -286,6 +352,7 @@ export function useWaveform(params: {
286352

287353
let animationFrameId: number | null = null
288354
let audioBuffer: AudioBuffer | null = null
355+
let soundCloudMinMaxData: Array<{ min: number; max: number }> | null = null
289356
let hoverEl: HTMLElement | null = null
290357
let isPointerDown = false
291358
type AudioEventName = keyof WebAudioPlayerEvents
@@ -426,7 +493,7 @@ export function useWaveform(params: {
426493
const targetBarWidth = style === WAVEFORM_STYLE_FINE ? fineBarWidth : barWidth
427494
const targetGap = style === WAVEFORM_STYLE_FINE ? barGap * 0.3 : barGap
428495
const columnCount = Math.max(1, Math.floor(width / (targetBarWidth + targetGap)))
429-
const columns = computeColumnMetrics(columnCount, waveformData)
496+
const columns = computeColumnMetrics(columnCount, waveformData, style === WAVEFORM_STYLE_FINE)
430497
if (!columns.length) {
431498
clearCanvases()
432499
return
@@ -532,14 +599,19 @@ export function useWaveform(params: {
532599
return
533600
}
534601

602+
const style = getWaveformStyle()
603+
if (style === WAVEFORM_STYLE_FINE) {
604+
drawFineWaveform(width, height)
605+
return
606+
}
607+
535608
const waveformData = player.rgbWaveformData ?? null
536609
if (!waveformData) {
537610
clearCanvases()
538611
return
539612
}
540613

541-
const style = getWaveformStyle()
542-
if (style === WAVEFORM_STYLE_SOUND_CLOUD || style === WAVEFORM_STYLE_FINE) {
614+
if (style === WAVEFORM_STYLE_SOUND_CLOUD) {
543615
drawBarWaveform(width, height, style, waveformData)
544616
} else {
545617
drawRgbStyleWaveform(width, height, waveformData)
@@ -551,10 +623,12 @@ export function useWaveform(params: {
551623
const updateWaveform = () => {
552624
if (!audioPlayer.value) return
553625
const player = audioPlayer.value
626+
const style = getWaveformStyle()
554627
const buffer = player.audioBuffer
555628

556629
if (!buffer) {
557630
audioBuffer = null
631+
soundCloudMinMaxData = null
558632
clearCanvases()
559633
updateProgressVisual(0)
560634
syncHoverOverlay(0)
@@ -563,6 +637,32 @@ export function useWaveform(params: {
563637

564638
audioBuffer = buffer
565639

640+
if (style === WAVEFORM_STYLE_FINE) {
641+
const channelData = buffer.getChannelData(0)
642+
const samples = channelData.length
643+
const downsampleFactor = Math.max(1, Math.floor(samples / 2000))
644+
645+
const length = Math.min(5000, Math.floor(samples / downsampleFactor))
646+
soundCloudMinMaxData = new Array(length)
647+
for (let i = 0; i < length; i++) {
648+
const start = i * downsampleFactor
649+
const end = Math.min(start + downsampleFactor, samples)
650+
let min = 1
651+
let max = -1
652+
for (let j = start; j < end; j++) {
653+
const v = channelData[j]
654+
if (v < min) min = v
655+
if (v > max) max = v
656+
}
657+
soundCloudMinMaxData[i] = { min, max }
658+
}
659+
660+
drawWaveform(true)
661+
return
662+
}
663+
664+
soundCloudMinMaxData = null
665+
566666
if (player.rgbWaveformData) {
567667
drawWaveform(true)
568668
return

0 commit comments

Comments
 (0)