replace AudioFileBox with new UUID
This commit is contained in:
Generated
+3
-3
@@ -8329,9 +8329,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mediabunny": {
|
||||
"version": "1.39.0",
|
||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.39.0.tgz",
|
||||
"integrity": "sha512-NDeht2Sf7kYfrUu7b/9AhVK4KdQhy6UeTF/EPNXW+PdpIYvSv36ZQ/SRBoFAJN2LRl6XrGb8JYY4MCnhsGQ2yg==",
|
||||
"version": "1.39.1",
|
||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.39.1.tgz",
|
||||
"integrity": "sha512-gaQKDWtfLhgSN9tRj37lgznHf9MOvey7sbT6GdQA7mWl1kaE5R+P1lfl9CDsgtzongx12IG9X/y2vgZmTHzGDg==",
|
||||
"license": "MPL-2.0",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
|
||||
@@ -22,6 +22,7 @@ export namespace AssetService {
|
||||
export type ImportArgs = {
|
||||
uuid?: UUID.Bytes
|
||||
name?: string,
|
||||
bpm?: number,
|
||||
arrayBuffer: ArrayBuffer,
|
||||
progressHandler?: Progress.Handler,
|
||||
origin?: "import" | "recording"
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import {int, Notifier, Observer, Option, panic, Procedure, Subscription, Terminable, Terminator, UUID} from "@opendaw/lib-std"
|
||||
import {
|
||||
int,
|
||||
Notifier,
|
||||
Observer,
|
||||
Option,
|
||||
panic,
|
||||
Procedure,
|
||||
Subscription,
|
||||
Terminable,
|
||||
Terminator,
|
||||
UUID
|
||||
} from "@opendaw/lib-std"
|
||||
import {AudioData} from "@opendaw/lib-dsp"
|
||||
import {Peaks} from "@opendaw/lib-fusion"
|
||||
import {mergeChunkPlanes, RingBuffer, SampleLoader, SampleLoaderState} from "@opendaw/studio-adapters"
|
||||
@@ -23,6 +34,7 @@ export class RecordingWorklet extends AudioWorkletNode implements Terminable, Sa
|
||||
#state: SampleLoaderState = {type: "record"}
|
||||
#onSaved: Option<Procedure<UUID.Bytes>> = Option.None
|
||||
#sampleService: Option<SampleService> = Option.None
|
||||
#bpm: Option<number> = Option.None
|
||||
|
||||
constructor(context: BaseAudioContext, config: RingBuffer.Config) {
|
||||
super(context, "recording-processor", {
|
||||
@@ -57,6 +69,7 @@ export class RecordingWorklet extends AudioWorkletNode implements Terminable, Sa
|
||||
}
|
||||
|
||||
set onSaved(callback: Procedure<UUID.Bytes>) {this.#onSaved = Option.wrap(callback)}
|
||||
set bpm(value: number) {this.#bpm = Option.wrap(value)}
|
||||
set sampleService(service: SampleService) {this.#sampleService = Option.wrap(service)}
|
||||
|
||||
setFillLength(value: int): void {this.#peakWriter.numFrames = value}
|
||||
@@ -94,7 +107,9 @@ export class RecordingWorklet extends AudioWorkletNode implements Terminable, Sa
|
||||
const audioData = AudioData.create(this.context.sampleRate, totalSamples, this.channelCount)
|
||||
mergedFrames.forEach((frame, index) => audioData.frames[index].set(frame))
|
||||
this.#data = Option.wrap(audioData)
|
||||
const sample = await this.#sampleService.unwrap("SampleService not set").importRecording(audioData)
|
||||
const sample = await this.#sampleService
|
||||
.unwrap("SampleService not set")
|
||||
.importRecording(audioData, this.#bpm.unwrapOrElse(120))
|
||||
this.#onSaved.ifSome(callback => callback(UUID.parse(sample.uuid)))
|
||||
this.#setState({type: "loaded"})
|
||||
this.terminate()
|
||||
|
||||
@@ -122,6 +122,7 @@ export class CaptureAudio extends Capture<CaptureAudioBox> {
|
||||
}
|
||||
const {gainNode, channelCount} = audioChain
|
||||
const recordingWorklet = audioWorklets.createRecording(channelCount, RenderQuantum)
|
||||
recordingWorklet.bpm = project.timelineBox.bpm.getValue()
|
||||
recordingWorklet.sampleService = sampleService
|
||||
sampleManager.record(recordingWorklet)
|
||||
gainNode.connect(recordingWorklet)
|
||||
|
||||
@@ -124,7 +124,27 @@ export namespace RecordAudio {
|
||||
currentTake = Option.wrap(createTakeRegion(position, currentWaveformOffset, previousTrack))
|
||||
}
|
||||
|
||||
recordingWorklet.onSaved = uuid => project.trackUserCreatedSample(uuid)
|
||||
recordingWorklet.onSaved = uuid => {
|
||||
project.trackUserCreatedSample(uuid)
|
||||
editing.modify(() => {
|
||||
fileBox.ifSome(oldFileBox => {
|
||||
editing.modify(() => {
|
||||
const newFileBox = AudioFileBox.create(boxGraph, uuid, box => {
|
||||
box.fileName.setValue(oldFileBox.fileName.getValue())
|
||||
box.startInSeconds.setValue(oldFileBox.startInSeconds.getValue())
|
||||
box.endInSeconds.setValue(oldFileBox.endInSeconds.getValue())
|
||||
})
|
||||
for (const pointer of [...oldFileBox.pointerHub.incoming()]) {
|
||||
pointer.refer(newFileBox)
|
||||
}
|
||||
for (const pointer of [...oldFileBox.transientMarkers.pointerHub.incoming()]) {
|
||||
pointer.refer(newFileBox.transientMarkers)
|
||||
}
|
||||
oldFileBox.delete()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
terminator.ownAll(
|
||||
Terminable.create(() => {
|
||||
tryCatch(() => sourceNode.disconnect(recordingWorklet))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Arrays, Class, Progress, tryCatch, UUID} from "@opendaw/lib-std"
|
||||
import {Arrays, Class, isDefined, Progress, tryCatch, UUID} from "@opendaw/lib-std"
|
||||
import {Box} from "@opendaw/lib-box"
|
||||
import {AudioData, estimateBpm} from "@opendaw/lib-dsp"
|
||||
import {Promises} from "@opendaw/lib-runtime"
|
||||
@@ -20,18 +20,19 @@ export class SampleService extends AssetService<Sample> {
|
||||
|
||||
constructor(readonly audioContext: AudioContext) {super()}
|
||||
|
||||
async importRecording(audioData: AudioData, name: string = "Recording"): Promise<Sample> {
|
||||
async importRecording(audioData: AudioData, bpm: number, name: string = "Recording"): Promise<Sample> {
|
||||
const arrayBuffer = WavFile.encodeFloats({
|
||||
frames: audioData.frames.slice(),
|
||||
numberOfFrames: audioData.numberOfFrames,
|
||||
numberOfChannels: audioData.numberOfChannels,
|
||||
sampleRate: audioData.sampleRate
|
||||
})
|
||||
return this.importFile({name, arrayBuffer, origin: "recording"})
|
||||
return this.importFile({name, bpm, arrayBuffer, origin: "recording"})
|
||||
}
|
||||
|
||||
async importFile({uuid, name, arrayBuffer, progressHandler = Progress.Empty, origin = "import"}
|
||||
: AssetService.ImportArgs): Promise<Sample> {
|
||||
async importFile({uuid, name, bpm, arrayBuffer, progressHandler = Progress.Empty, origin = "import"}
|
||||
: AssetService.ImportArgs,
|
||||
transformMeta?: (meta: SampleMetaData, audioData: Readonly<AudioData>) => Promise<void>): Promise<Sample> {
|
||||
console.debug(`importSample '${name}' (${arrayBuffer.byteLength >> 10}kb)`)
|
||||
uuid ??= await UUID.sha256(arrayBuffer)
|
||||
const audioData = await this.#decodeAudio(arrayBuffer)
|
||||
@@ -44,14 +45,17 @@ export class SampleService extends AssetService<Sample> {
|
||||
audioData.numberOfFrames,
|
||||
audioData.numberOfChannels) as ArrayBuffer
|
||||
const meta: SampleMetaData = {
|
||||
bpm: estimateBpm(duration),
|
||||
bpm: bpm ?? estimateBpm(duration),
|
||||
name: name ?? "Unnnamed",
|
||||
duration,
|
||||
sample_rate: audioData.sampleRate,
|
||||
origin
|
||||
}
|
||||
await SampleStorage.get().save({uuid, audio: audioData, peaks, meta})
|
||||
if (isDefined(transformMeta)) {
|
||||
await transformMeta(meta, audioData)
|
||||
}
|
||||
const sample = {uuid: UUID.toString(uuid), ...meta}
|
||||
await SampleStorage.get().save({uuid, audio: audioData, peaks, meta})
|
||||
this.notifier.notify(sample)
|
||||
return sample
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user