Skip to content

Commit

Permalink
Fix: [Record] use all wavesufer options (#2993)
Browse files Browse the repository at this point in the history
* Fix: [Record] use all wavesufer options

* Prevent interaction when recording
  • Loading branch information
katspaugh authored Jul 9, 2023
1 parent 0467efe commit 521f49e
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 47 deletions.
2 changes: 1 addition & 1 deletion examples/fm-synth.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ function drawWaveform() {
// Get the waveform data from the analyser
analyser.getFloatTimeDomainData(dataArray)
const duration = document.getElementById('duration').valueAsNumber
waveform && wavesurfer.load('', [dataArray], duration)
wavesurfer && wavesurfer.load('', [dataArray], duration)
}

function animate() {
Expand Down
2 changes: 1 addition & 1 deletion examples/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ recButton.onclick = () => {
recButton.disabled = true

record.startRecording().then(() => {
recButton.textContent = 'Stop'
recButton.textContent = 'Stop'
recButton.disabled = false
})
}
Expand Down
77 changes: 32 additions & 45 deletions src/plugins/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import BasePlugin, { type BasePluginEvents } from '../base-plugin.js'

export type RecordPluginOptions = {
realtimeWaveColor?: string
lineWidth?: number
mimeType?: MediaRecorderOptions['mimeType']
audioBitsPerSecond?: MediaRecorderOptions['audioBitsPerSecond']
}
Expand All @@ -22,65 +20,55 @@ const findSupportedMimeType = () => MIME_TYPES.find((mimeType) => MediaRecorder.
class RecordPlugin extends BasePlugin<RecordPluginEvents, RecordPluginOptions> {
private mediaRecorder: MediaRecorder | null = null
private recordedUrl = ''
private savedCursorWidth = 1
private savedInteractive = true

public static create(options?: RecordPluginOptions) {
return new RecordPlugin(options || {})
}

private preventInteraction() {
if (this.wavesurfer) {
this.savedCursorWidth = this.wavesurfer.options.cursorWidth || 1
this.savedInteractive = this.wavesurfer.options.interact || true
this.wavesurfer.options.cursorWidth = 0
this.wavesurfer.options.interact = false
}
}

private restoreInteraction() {
if (this.wavesurfer) {
this.wavesurfer.options.cursorWidth = this.savedCursorWidth
this.wavesurfer.options.interact = this.savedInteractive
}
}

onInit() {
this.preventInteraction()
}

private loadBlob(data: Blob[], type: string) {
const blob = new Blob(data, { type })
this.recordedUrl = URL.createObjectURL(blob)
this.restoreInteraction()
this.wavesurfer?.load(this.recordedUrl)
}

render(stream: MediaStream): () => void {
if (!this.wavesurfer) return () => undefined

const container = this.wavesurfer.getWrapper()
const canvas = document.createElement('canvas')
canvas.width = container.clientWidth
canvas.height = container.clientHeight
canvas.style.zIndex = '10'
container.appendChild(canvas)

const canvasCtx = canvas.getContext('2d')
const audioContext = new AudioContext()
const audioContext = new AudioContext({ sampleRate: 8000 })
const source = audioContext.createMediaStreamSource(stream)
const analyser = audioContext.createAnalyser()
source.connect(analyser)
let animationId: number

const drawWaveform = () => {
if (!canvasCtx) return

canvasCtx.clearRect(0, 0, canvas.width, canvas.height)
const bufferLength = analyser.frequencyBinCount
const dataArray = new Uint8Array(bufferLength)
analyser.getByteTimeDomainData(dataArray)

canvasCtx.lineWidth = this.options.lineWidth || 2
const color = this.options.realtimeWaveColor || this.wavesurfer?.options.waveColor || ''
canvasCtx.strokeStyle = Array.isArray(color) ? color[0] : color
canvasCtx.beginPath()

const sliceWidth = (canvas.width * 1.0) / bufferLength
let x = 0

for (let i = 0; i < bufferLength; i++) {
const v = dataArray[i] / 128.0
const y = (v * canvas.height) / 2
const bufferLength = analyser.frequencyBinCount
const dataArray = new Float32Array(bufferLength)
const sampleDuration = bufferLength / audioContext.sampleRate

if (i === 0) {
canvasCtx.moveTo(x, y)
} else {
canvasCtx.lineTo(x, y)
}

x += sliceWidth
}
let animationId: number

canvasCtx.lineTo(canvas.width, canvas.height / 2)
canvasCtx.stroke()
const drawWaveform = () => {
analyser.getFloatTimeDomainData(dataArray)
this.wavesurfer?.load('', [dataArray], sampleDuration)
animationId = requestAnimationFrame(drawWaveform)
}

Expand All @@ -99,8 +87,6 @@ class RecordPlugin extends BasePlugin<RecordPluginEvents, RecordPluginOptions> {
if (audioContext) {
audioContext.close()
}

canvas?.remove()
}
}

Expand All @@ -114,6 +100,7 @@ class RecordPlugin extends BasePlugin<RecordPluginEvents, RecordPluginOptions> {
}

public async startRecording() {
this.preventInteraction()
this.cleanUp()

let stream: MediaStream
Expand Down

0 comments on commit 521f49e

Please sign in to comment.