@opendaw/studio-core 0.0.122 → 0.0.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AssetService.d.ts +4 -3
- package/dist/AssetService.d.ts.map +1 -1
- package/dist/AssetService.js +3 -5
- package/dist/RecordingWorklet.d.ts +2 -0
- package/dist/RecordingWorklet.d.ts.map +1 -1
- package/dist/RecordingWorklet.js +8 -25
- package/dist/capture/CaptureAudio.d.ts.map +1 -1
- package/dist/capture/CaptureAudio.js +2 -1
- package/dist/capture/RecordMidi.d.ts.map +1 -1
- package/dist/capture/RecordMidi.js +24 -2
- package/dist/processors.js +8 -8
- package/dist/processors.js.map +3 -3
- package/dist/project/ProjectEnv.d.ts +4 -0
- package/dist/project/ProjectEnv.d.ts.map +1 -1
- package/dist/samples/SampleService.d.ts +5 -3
- package/dist/samples/SampleService.d.ts.map +1 -1
- package/dist/samples/SampleService.js +16 -7
- package/dist/soundfont/SoundfontService.d.ts +2 -2
- package/dist/soundfont/SoundfontService.d.ts.map +1 -1
- package/dist/soundfont/SoundfontService.js +3 -3
- package/dist/ui/renderer/audio.d.ts +13 -1
- package/dist/ui/renderer/audio.d.ts.map +1 -1
- package/dist/ui/renderer/audio.js +28 -20
- package/dist/ui/renderer/fading.d.ts.map +1 -1
- package/dist/ui/renderer/fading.js +23 -20
- package/dist/ui/renderer/index.d.ts +1 -0
- package/dist/ui/renderer/index.d.ts.map +1 -1
- package/dist/ui/renderer/index.js +1 -0
- package/dist/ui/renderer/notes.d.ts.map +1 -1
- package/dist/ui/renderer/notes.js +7 -4
- package/dist/ui/renderer/riffle.d.ts +3 -0
- package/dist/ui/renderer/riffle.d.ts.map +1 -0
- package/dist/ui/renderer/riffle.js +106 -0
- package/package.json +6 -6
|
@@ -2,11 +2,15 @@ import { SampleLoaderManager, SoundfontLoaderManager } from "@opendaw/studio-ada
|
|
|
2
2
|
import { Editing, Func } from "@opendaw/lib-std";
|
|
3
3
|
import { BoxGraph } from "@opendaw/lib-box";
|
|
4
4
|
import { AudioWorklets } from "../AudioWorklets";
|
|
5
|
+
import { SampleService } from "../samples";
|
|
6
|
+
import { SoundfontService } from "../soundfont";
|
|
5
7
|
export interface ProjectEnv {
|
|
6
8
|
audioContext: AudioContext;
|
|
7
9
|
audioWorklets: AudioWorklets;
|
|
8
10
|
sampleManager: SampleLoaderManager;
|
|
9
11
|
soundfontManager: SoundfontLoaderManager;
|
|
12
|
+
sampleService: SampleService;
|
|
13
|
+
soundfontService: SoundfontService;
|
|
10
14
|
createEditing?: Func<BoxGraph, Editing>;
|
|
11
15
|
}
|
|
12
16
|
//# sourceMappingURL=ProjectEnv.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../../src/project/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAE,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AACpF,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../../src/project/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAE,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AACpF,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,aAAa,EAAC,MAAM,YAAY,CAAA;AACxC,OAAO,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAA;AAE7C,MAAM,WAAW,UAAU;IACvB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,mBAAmB,CAAA;IAClC,gBAAgB,EAAE,sBAAsB,CAAA;IACxC,aAAa,EAAE,aAAa,CAAA;IAC5B,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,aAAa,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;CAC1C"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Class
|
|
1
|
+
import { Class } from "@opendaw/lib-std";
|
|
2
2
|
import { Box } from "@opendaw/lib-box";
|
|
3
|
+
import { AudioData } from "@opendaw/lib-dsp";
|
|
3
4
|
import { Sample } from "@opendaw/studio-adapters";
|
|
4
5
|
import { AssetService } from "../AssetService";
|
|
5
6
|
export declare class SampleService extends AssetService<Sample> {
|
|
@@ -9,8 +10,9 @@ export declare class SampleService extends AssetService<Sample> {
|
|
|
9
10
|
protected readonly nameSingular: string;
|
|
10
11
|
protected readonly boxType: Class<Box>;
|
|
11
12
|
protected readonly filePickerOptions: FilePickerOptions;
|
|
12
|
-
constructor(audioContext: AudioContext
|
|
13
|
-
|
|
13
|
+
constructor(audioContext: AudioContext);
|
|
14
|
+
importRecording(audioData: AudioData, name?: string): Promise<Sample>;
|
|
15
|
+
importFile({ uuid, name, arrayBuffer, progressHandler, origin }: AssetService.ImportArgs): Promise<Sample>;
|
|
14
16
|
protected collectAllFiles(): Promise<ReadonlyArray<Sample>>;
|
|
15
17
|
}
|
|
16
18
|
//# sourceMappingURL=SampleService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,
|
|
1
|
+
{"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAA2B,MAAM,kBAAkB,CAAA;AACxE,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AACpC,OAAO,EAAC,SAAS,EAAc,MAAM,kBAAkB,CAAA;AAIvD,OAAO,EAAC,MAAM,EAAiB,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAO5C,qBAAa,aAAc,SAAQ,YAAY,CAAC,MAAM,CAAC;;IAMvC,QAAQ,CAAC,YAAY,EAAE,YAAY;IAL/C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAW;IAClD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAe;IACrD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAiC;gBAEnE,YAAY,EAAE,YAAY;IAEzC,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,GAAE,MAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUlF,UAAU,CAAC,EAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,eAAgC,EAAE,MAAiB,EAAC,EAC5E,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;cAyB5C,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;CAkBpE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Arrays,
|
|
1
|
+
import { Arrays, Progress, tryCatch, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { AudioData, estimateBpm } from "@opendaw/lib-dsp";
|
|
3
3
|
import { Promises } from "@opendaw/lib-runtime";
|
|
4
4
|
import { SamplePeaks } from "@opendaw/lib-fusion";
|
|
@@ -15,11 +15,20 @@ export class SampleService extends AssetService {
|
|
|
15
15
|
nameSingular = "Sample";
|
|
16
16
|
boxType = AudioFileBox;
|
|
17
17
|
filePickerOptions = FilePickerAcceptTypes.WavFiles;
|
|
18
|
-
constructor(audioContext
|
|
19
|
-
super(
|
|
18
|
+
constructor(audioContext) {
|
|
19
|
+
super();
|
|
20
20
|
this.audioContext = audioContext;
|
|
21
21
|
}
|
|
22
|
-
async
|
|
22
|
+
async importRecording(audioData, name = "Recording") {
|
|
23
|
+
const arrayBuffer = WavFile.encodeFloats({
|
|
24
|
+
frames: audioData.frames.slice(),
|
|
25
|
+
numberOfFrames: audioData.numberOfFrames,
|
|
26
|
+
numberOfChannels: audioData.numberOfChannels,
|
|
27
|
+
sampleRate: audioData.sampleRate
|
|
28
|
+
});
|
|
29
|
+
return this.importFile({ name, arrayBuffer, origin: "recording" });
|
|
30
|
+
}
|
|
31
|
+
async importFile({ uuid, name, arrayBuffer, progressHandler = Progress.Empty, origin = "import" }) {
|
|
23
32
|
console.debug(`importSample '${name}' (${arrayBuffer.byteLength >> 10}kb)`);
|
|
24
33
|
uuid ??= await UUID.sha256(arrayBuffer);
|
|
25
34
|
const audioData = await this.#decodeAudio(arrayBuffer);
|
|
@@ -28,14 +37,14 @@ export class SampleService extends AssetService {
|
|
|
28
37
|
const peaks = await Workers.Peak.generateAsync(progressHandler, shifts, audioData.frames, audioData.numberOfFrames, audioData.numberOfChannels);
|
|
29
38
|
const meta = {
|
|
30
39
|
bpm: estimateBpm(duration),
|
|
31
|
-
name:
|
|
40
|
+
name: name ?? "Unnnamed",
|
|
32
41
|
duration,
|
|
33
42
|
sample_rate: audioData.sampleRate,
|
|
34
|
-
origin
|
|
43
|
+
origin
|
|
35
44
|
};
|
|
36
45
|
await SampleStorage.get().save({ uuid, audio: audioData, peaks, meta });
|
|
37
46
|
const sample = { uuid: UUID.toString(uuid), ...meta };
|
|
38
|
-
this.
|
|
47
|
+
this.notifier.notify(sample);
|
|
39
48
|
return sample;
|
|
40
49
|
}
|
|
41
50
|
async collectAllFiles() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Class, Option
|
|
1
|
+
import { Class, Option } from "@opendaw/lib-std";
|
|
2
2
|
import { Box } from "@opendaw/lib-box";
|
|
3
3
|
import { Soundfont } from "@opendaw/studio-adapters";
|
|
4
4
|
import { AssetService } from "../AssetService";
|
|
@@ -8,7 +8,7 @@ export declare class SoundfontService extends AssetService<Soundfont> {
|
|
|
8
8
|
protected readonly nameSingular: string;
|
|
9
9
|
protected readonly boxType: Class<Box>;
|
|
10
10
|
protected readonly filePickerOptions: FilePickerOptions;
|
|
11
|
-
constructor(
|
|
11
|
+
constructor();
|
|
12
12
|
get local(): Option<ReadonlyArray<Soundfont>>;
|
|
13
13
|
get remote(): Option<ReadonlyArray<Soundfont>>;
|
|
14
14
|
importFile({ uuid, arrayBuffer }: AssetService.ImportArgs): Promise<Soundfont>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SoundfontService.d.ts","sourceRoot":"","sources":["../../src/soundfont/SoundfontService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"SoundfontService.d.ts","sourceRoot":"","sources":["../../src/soundfont/SoundfontService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,EAA+B,MAAM,kBAAkB,CAAA;AACpF,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAGpC,OAAO,EAAC,SAAS,EAAoB,MAAM,0BAA0B,CAAA;AAIrE,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAG5C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,SAAS,CAAC;;IACzD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAc;IACrD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAmB;IACzD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAuC;;IAgB9F,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAqB;IAClE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAsB;IAE9D,UAAU,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;cA4ClE,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAKvE"}
|
|
@@ -13,8 +13,8 @@ export class SoundfontService extends AssetService {
|
|
|
13
13
|
filePickerOptions = FilePickerAcceptTypes.SoundfontFiles;
|
|
14
14
|
#local = Option.None;
|
|
15
15
|
#remote = Option.None;
|
|
16
|
-
constructor(
|
|
17
|
-
super(
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
18
|
Promise.all([
|
|
19
19
|
SoundfontStorage.get().list(),
|
|
20
20
|
OpenSoundfontAPI.get().all()
|
|
@@ -64,7 +64,7 @@ export class SoundfontService extends AssetService {
|
|
|
64
64
|
if (!list.some(other => other.uuid === soundfont.uuid)) {
|
|
65
65
|
list.push(soundfont);
|
|
66
66
|
}
|
|
67
|
-
this.
|
|
67
|
+
this.notifier.notify(soundfont);
|
|
68
68
|
updater.terminate();
|
|
69
69
|
return soundfont;
|
|
70
70
|
}
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { RegionBound } from "./env";
|
|
2
2
|
import { Option } from "@opendaw/lib-std";
|
|
3
3
|
import { LoopableRegion, TempoMap } from "@opendaw/lib-dsp";
|
|
4
|
+
import { Peaks } from "@opendaw/lib-fusion";
|
|
4
5
|
import { AudioFileBoxAdapter, AudioPlayMode } from "@opendaw/studio-adapters";
|
|
5
6
|
import { TimelineRange } from "../timeline/TimelineRange";
|
|
6
7
|
export declare namespace AudioRenderer {
|
|
7
|
-
|
|
8
|
+
type Segment = {
|
|
9
|
+
x0: number;
|
|
10
|
+
x1: number;
|
|
11
|
+
u0: number;
|
|
12
|
+
u1: number;
|
|
13
|
+
outside: boolean;
|
|
14
|
+
};
|
|
15
|
+
interface Strategy {
|
|
16
|
+
render(context: CanvasRenderingContext2D, segments: ReadonlyArray<Segment>, peaks: Peaks, bound: RegionBound, gain: number): void;
|
|
17
|
+
}
|
|
18
|
+
const DefaultStrategy: Strategy;
|
|
19
|
+
const render: (context: CanvasRenderingContext2D, range: TimelineRange, file: AudioFileBoxAdapter, tempoMap: TempoMap, playMode: Option<AudioPlayMode>, waveformOffset: number, gain: number, bound: RegionBound, contentColor: string, { rawStart, resultStart, resultEnd }: LoopableRegion.LoopCycle, clip?: boolean, strategy?: Strategy) => void;
|
|
8
20
|
}
|
|
9
21
|
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AACjC,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAW,cAAc,EAAyB,QAAQ,EAAC,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AACjC,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAW,cAAc,EAAyB,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAC1F,OAAO,EAAC,KAAK,EAAe,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,0BAA0B,CAAA;AAC3E,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAA;AAEvD,yBAAiB,aAAa,CAAC;IAC3B,KAAY,OAAO,GAAG;QAClB,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,MAAM,CAAA;QACV,OAAO,EAAE,OAAO,CAAA;KACnB,CAAA;IAED,UAAiB,QAAQ;QACrB,MAAM,CAAC,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAC7B;IAEM,MAAM,eAAe,EAAE,QAyB7B,CAAA;IAEM,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,MAAM,mBAAmB,EACzB,UAAU,QAAQ,EAClB,UAAU,MAAM,CAAC,aAAa,CAAC,EAC/B,gBAAgB,MAAM,EACtB,MAAM,MAAM,EACZ,OAAO,WAAW,EAClB,cAAc,MAAM,EACpB,sCAAoC,cAAc,CAAC,SAAS,EAC5D,OAAM,OAAc,EACpB,WAAU,QAA0B,SAyU1D,CAAA;CACJ"}
|
|
@@ -2,17 +2,39 @@ import { dbToGain, PPQN, TempoChangeGrid } from "@opendaw/lib-dsp";
|
|
|
2
2
|
import { PeaksPainter } from "@opendaw/lib-fusion";
|
|
3
3
|
export var AudioRenderer;
|
|
4
4
|
(function (AudioRenderer) {
|
|
5
|
-
AudioRenderer.
|
|
5
|
+
AudioRenderer.DefaultStrategy = {
|
|
6
|
+
render(context, segments, peaks, { top, bottom }, gain) {
|
|
7
|
+
const dpr = devicePixelRatio;
|
|
8
|
+
const actualTop = top * dpr;
|
|
9
|
+
const actualBottom = bottom * dpr;
|
|
10
|
+
const height = actualBottom - actualTop;
|
|
11
|
+
const numberOfChannels = peaks.numChannels;
|
|
12
|
+
const peaksHeight = Math.floor((height - 4) / numberOfChannels);
|
|
13
|
+
const scale = dbToGain(-gain);
|
|
14
|
+
for (const { x0, x1, u0, u1, outside } of segments) {
|
|
15
|
+
context.globalAlpha = outside ? 0.25 : 1.0;
|
|
16
|
+
for (let channel = 0; channel < numberOfChannels; channel++) {
|
|
17
|
+
PeaksPainter.renderPixelStrips(context, peaks, channel, {
|
|
18
|
+
u0,
|
|
19
|
+
u1,
|
|
20
|
+
v0: -scale,
|
|
21
|
+
v1: +scale,
|
|
22
|
+
x0,
|
|
23
|
+
x1,
|
|
24
|
+
y0: 3 + actualTop + channel * peaksHeight,
|
|
25
|
+
y1: 3 + actualTop + (channel + 1) * peaksHeight
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
AudioRenderer.render = (context, range, file, tempoMap, playMode, waveformOffset, gain, bound, contentColor, { rawStart, resultStart, resultEnd }, clip = true, strategy = AudioRenderer.DefaultStrategy) => {
|
|
6
32
|
if (file.peaks.isEmpty()) {
|
|
7
33
|
return;
|
|
8
34
|
}
|
|
9
35
|
const peaks = file.peaks.unwrap();
|
|
10
36
|
const durationInSeconds = file.endInSeconds - file.startInSeconds;
|
|
11
37
|
const numFrames = peaks.numFrames;
|
|
12
|
-
const numberOfChannels = peaks.numChannels;
|
|
13
|
-
const ht = bottom - top;
|
|
14
|
-
const peaksHeight = Math.floor((ht - 4) / numberOfChannels);
|
|
15
|
-
const scale = dbToGain(-gain);
|
|
16
38
|
const segments = [];
|
|
17
39
|
if (playMode.nonEmpty()) {
|
|
18
40
|
const { warpMarkers } = playMode.unwrap();
|
|
@@ -258,20 +280,6 @@ export var AudioRenderer;
|
|
|
258
280
|
}
|
|
259
281
|
}
|
|
260
282
|
context.fillStyle = contentColor;
|
|
261
|
-
|
|
262
|
-
context.globalAlpha = outside && !clip ? 0.25 : 1.0;
|
|
263
|
-
for (let channel = 0; channel < numberOfChannels; channel++) {
|
|
264
|
-
PeaksPainter.renderBlocks(context, peaks, channel, {
|
|
265
|
-
u0,
|
|
266
|
-
u1,
|
|
267
|
-
v0: -scale,
|
|
268
|
-
v1: +scale,
|
|
269
|
-
x0,
|
|
270
|
-
x1,
|
|
271
|
-
y0: 3 + top + channel * peaksHeight,
|
|
272
|
-
y1: 3 + top + (channel + 1) * peaksHeight
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
283
|
+
strategy.render(context, segments, peaks, bound, gain);
|
|
276
284
|
};
|
|
277
285
|
})(AudioRenderer || (AudioRenderer = {}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fading.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/fading.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AAEjC,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,QAAQ,cAAc,CAAC,MAAM,EAC7B,iBAAe,WAAW,EAC1B,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,OAAO,MAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"fading.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/fading.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AAEjC,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,QAAQ,cAAc,CAAC,MAAM,EAC7B,iBAAe,WAAW,EAC1B,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,OAAO,MAAM,KAAG,IAqDtC,CAAA;CACJ"}
|
|
@@ -2,6 +2,9 @@ import { Curve, TAU } from "@opendaw/lib-std";
|
|
|
2
2
|
export var AudioFadingRenderer;
|
|
3
3
|
(function (AudioFadingRenderer) {
|
|
4
4
|
AudioFadingRenderer.render = (context, range, fading, { top, bottom }, startPPQN, endPPQN, color) => {
|
|
5
|
+
const dpr = devicePixelRatio;
|
|
6
|
+
const actualTop = top * dpr;
|
|
7
|
+
const actualBottom = bottom * dpr;
|
|
5
8
|
const { inSlope: fadeInSlope, outSlope: fadeOutSlope } = fading;
|
|
6
9
|
const duration = endPPQN - startPPQN;
|
|
7
10
|
const totalFading = fading.in + fading.out;
|
|
@@ -10,46 +13,46 @@ export var AudioFadingRenderer;
|
|
|
10
13
|
const fadeOut = fading.out * scale;
|
|
11
14
|
context.strokeStyle = color;
|
|
12
15
|
context.fillStyle = "rgba(0,0,0,0.25)";
|
|
13
|
-
context.lineWidth =
|
|
16
|
+
context.lineWidth = dpr;
|
|
14
17
|
if (fadeIn > 0) {
|
|
15
18
|
const fadeInEndPPQN = startPPQN + fadeIn;
|
|
16
|
-
const x0 = range.unitToX(startPPQN) *
|
|
17
|
-
const x1 = range.unitToX(fadeInEndPPQN) *
|
|
19
|
+
const x0 = range.unitToX(startPPQN) * dpr;
|
|
20
|
+
const x1 = range.unitToX(fadeInEndPPQN) * dpr;
|
|
18
21
|
const xn = x1 - x0;
|
|
19
22
|
const path = new Path2D();
|
|
20
|
-
path.moveTo(x0,
|
|
23
|
+
path.moveTo(x0, actualBottom);
|
|
21
24
|
let x = x0;
|
|
22
|
-
Curve.run(fadeInSlope, xn,
|
|
23
|
-
path.lineTo(x1,
|
|
25
|
+
Curve.run(fadeInSlope, xn, actualBottom, actualTop, y => path.lineTo(++x, y));
|
|
26
|
+
path.lineTo(x1, actualTop);
|
|
24
27
|
context.stroke(path);
|
|
25
|
-
path.lineTo(x0,
|
|
26
|
-
path.lineTo(x0,
|
|
28
|
+
path.lineTo(x0, actualTop);
|
|
29
|
+
path.lineTo(x0, actualBottom);
|
|
27
30
|
context.fill(path);
|
|
28
31
|
}
|
|
29
32
|
if (fadeOut > 0) {
|
|
30
|
-
const x0 = range.unitToX(endPPQN - fadeOut) *
|
|
31
|
-
const x1 = range.unitToX(endPPQN) *
|
|
33
|
+
const x0 = range.unitToX(endPPQN - fadeOut) * dpr;
|
|
34
|
+
const x1 = range.unitToX(endPPQN) * dpr;
|
|
32
35
|
const xn = x1 - x0;
|
|
33
36
|
const path = new Path2D();
|
|
34
|
-
path.moveTo(x0,
|
|
37
|
+
path.moveTo(x0, actualTop);
|
|
35
38
|
let x = x0;
|
|
36
|
-
Curve.run(fadeOutSlope, xn,
|
|
37
|
-
path.lineTo(x1,
|
|
39
|
+
Curve.run(fadeOutSlope, xn, actualTop, actualBottom, y => path.lineTo(++x, y));
|
|
40
|
+
path.lineTo(x1, actualBottom);
|
|
38
41
|
context.strokeStyle = color;
|
|
39
42
|
context.stroke(path);
|
|
40
|
-
path.lineTo(x1,
|
|
41
|
-
path.lineTo(x0,
|
|
43
|
+
path.lineTo(x1, actualTop);
|
|
44
|
+
path.lineTo(x0, actualTop);
|
|
42
45
|
context.fill(path);
|
|
43
46
|
}
|
|
44
|
-
const handleRadius = 1.5 *
|
|
45
|
-
const x0 = Math.max(range.unitToX(startPPQN + fadeIn), range.unitToX(startPPQN)) *
|
|
46
|
-
const x1 = Math.min(range.unitToX(endPPQN - fadeOut), range.unitToX(endPPQN)) *
|
|
47
|
+
const handleRadius = 1.5 * dpr;
|
|
48
|
+
const x0 = Math.max(range.unitToX(startPPQN + fadeIn), range.unitToX(startPPQN)) * dpr;
|
|
49
|
+
const x1 = Math.min(range.unitToX(endPPQN - fadeOut), range.unitToX(endPPQN)) * dpr;
|
|
47
50
|
context.fillStyle = color;
|
|
48
51
|
context.beginPath();
|
|
49
|
-
context.arc(x0,
|
|
52
|
+
context.arc(x0, actualTop, handleRadius, 0, TAU);
|
|
50
53
|
context.fill();
|
|
51
54
|
context.beginPath();
|
|
52
|
-
context.arc(x1,
|
|
55
|
+
context.arc(x1, actualTop, handleRadius, 0, TAU);
|
|
53
56
|
context.fill();
|
|
54
57
|
};
|
|
55
58
|
})(AudioFadingRenderer || (AudioFadingRenderer = {}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,6BAA6B,EAAC,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,WAAW,EAAE,aAAa,EAAC,MAAM,aAAa,CAAA;AAEtD,yBAAiB,aAAa,CAAC;IACpB,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,YAAY,6BAA6B,EACzC,iBAAe,WAAW,EAC1B,cAAc,MAAM,EACpB,mDAAiD,cAAc,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,6BAA6B,EAAC,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,WAAW,EAAE,aAAa,EAAC,MAAM,aAAa,CAAA;AAEtD,yBAAiB,aAAa,CAAC;IACpB,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,YAAY,6BAA6B,EACzC,iBAAe,WAAW,EAC1B,cAAc,MAAM,EACpB,mDAAiD,cAAc,CAAC,SAAS,SAmB/F,CAAA;CACJ"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export var NotesRenderer;
|
|
2
2
|
(function (NotesRenderer) {
|
|
3
3
|
NotesRenderer.render = (context, range, collection, { top, bottom }, contentColor, { rawStart, regionStart, resultStart, resultEnd }) => {
|
|
4
|
-
const
|
|
4
|
+
const dpr = devicePixelRatio;
|
|
5
|
+
const actualTop = top * dpr;
|
|
6
|
+
const actualBottom = bottom * dpr;
|
|
7
|
+
const height = actualBottom - actualTop;
|
|
5
8
|
context.fillStyle = contentColor;
|
|
6
9
|
const padding = 8;
|
|
7
10
|
const noteHeight = 5;
|
|
@@ -13,9 +16,9 @@ export var NotesRenderer;
|
|
|
13
16
|
continue;
|
|
14
17
|
}
|
|
15
18
|
const complete = Math.min(rawStart + note.complete, resultEnd);
|
|
16
|
-
const x0 = Math.floor(range.unitToX(position) *
|
|
17
|
-
const x1 = Math.floor(range.unitToX(complete) *
|
|
18
|
-
const y =
|
|
19
|
+
const x0 = Math.floor(range.unitToX(position) * dpr);
|
|
20
|
+
const x1 = Math.floor(range.unitToX(complete) * dpr);
|
|
21
|
+
const y = actualTop + padding + Math.floor(note.normalizedPitch() * (height - (padding * 2 + noteHeight)));
|
|
19
22
|
context.fillRect(x0, y, Math.max(1, x1 - x0), noteHeight);
|
|
20
23
|
}
|
|
21
24
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"riffle.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/riffle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,aAAa,EAAC,MAAM,SAAS,CAAA;AAErC,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,QAuF1C,CAAA"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { dbToGain } from "@opendaw/lib-dsp";
|
|
2
|
+
import { Peaks } from "@opendaw/lib-fusion";
|
|
3
|
+
export const RiffleStrategy = {
|
|
4
|
+
render(context, segments, peaks, { top, bottom }, gain) {
|
|
5
|
+
if (segments.length === 0) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const dpr = devicePixelRatio;
|
|
9
|
+
const actualTop = top * dpr;
|
|
10
|
+
const actualBottom = bottom * dpr;
|
|
11
|
+
const height = actualBottom - actualTop;
|
|
12
|
+
const numberOfChannels = peaks.numChannels;
|
|
13
|
+
const peaksHeight = Math.floor(height / numberOfChannels);
|
|
14
|
+
const gainScale = dbToGain(-gain);
|
|
15
|
+
const blockWidth = 3 * dpr;
|
|
16
|
+
// noinspection PointlessArithmeticExpressionJS
|
|
17
|
+
const gap = dpr * 1;
|
|
18
|
+
const pixelsPerBlock = blockWidth + gap;
|
|
19
|
+
let globalX0 = Infinity;
|
|
20
|
+
let globalX1 = -Infinity;
|
|
21
|
+
for (const { x0, x1 } of segments) {
|
|
22
|
+
globalX0 = Math.min(globalX0, Math.floor(x0));
|
|
23
|
+
globalX1 = Math.max(globalX1, Math.floor(x1));
|
|
24
|
+
}
|
|
25
|
+
if (globalX0 >= globalX1) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const seg0 = segments[0];
|
|
29
|
+
const pxPerUnit = (seg0.x1 - seg0.x0) / (seg0.u1 - seg0.u0);
|
|
30
|
+
const anchorX = seg0.x0 - seg0.u0 * pxPerUnit;
|
|
31
|
+
const gridPhase = ((globalX0 - anchorX) % pixelsPerBlock + pixelsPerBlock) % pixelsPerBlock;
|
|
32
|
+
const firstBlockX = globalX0 - gridPhase;
|
|
33
|
+
for (let channel = 0; channel < numberOfChannels; channel++) {
|
|
34
|
+
const data = peaks.data[channel];
|
|
35
|
+
const channelY0 = actualTop + channel * peaksHeight;
|
|
36
|
+
const channelY1 = actualTop + (channel + 1) * peaksHeight;
|
|
37
|
+
const centerY = (channelY0 + channelY1) / 2;
|
|
38
|
+
const yScale = (channelY1 - channelY0 - 1.0) / (gainScale * 2);
|
|
39
|
+
for (let bx = firstBlockX; bx < globalX1; bx += pixelsPerBlock) {
|
|
40
|
+
const bxEnd = bx + pixelsPerBlock;
|
|
41
|
+
let blockMin = 0.0;
|
|
42
|
+
let blockMax = 0.0;
|
|
43
|
+
let blockAlpha = 0.0;
|
|
44
|
+
let hasData = false;
|
|
45
|
+
for (const seg of segments) {
|
|
46
|
+
const segX0 = Math.floor(seg.x0);
|
|
47
|
+
const segX1 = Math.floor(seg.x1);
|
|
48
|
+
if (segX0 >= bxEnd || segX1 <= bx) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const pixelSpan = seg.x1 - seg.x0;
|
|
52
|
+
if (pixelSpan <= 0) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const uPerPx = (seg.u1 - seg.u0) / pixelSpan;
|
|
56
|
+
const stage = peaks.nearest(uPerPx);
|
|
57
|
+
if (stage === null) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const uPerPeak = stage.unitsEachPeak();
|
|
61
|
+
const peaksPerPx = uPerPx / uPerPeak;
|
|
62
|
+
const overflow = seg.x0 - segX0;
|
|
63
|
+
const fromAtX0 = (seg.u0 - overflow * uPerPx) / uPerPx * peaksPerPx;
|
|
64
|
+
const overlapStart = Math.max(bx, segX0);
|
|
65
|
+
const overlapEnd = Math.min(bxEnd, segX1);
|
|
66
|
+
const fromPeak = fromAtX0 + (overlapStart - segX0) * peaksPerPx;
|
|
67
|
+
const toPeak = fromAtX0 + (overlapEnd - segX0) * peaksPerPx;
|
|
68
|
+
const idxFrom = Math.max(0, Math.floor(fromPeak));
|
|
69
|
+
const idxTo = Math.floor(toPeak);
|
|
70
|
+
for (let idx = idxFrom; idx < idxTo; idx++) {
|
|
71
|
+
const bits = data[stage.dataOffset + idx];
|
|
72
|
+
blockMin = Math.min(Peaks.unpack(bits, 0), blockMin);
|
|
73
|
+
blockMax = Math.max(Peaks.unpack(bits, 1), blockMax);
|
|
74
|
+
}
|
|
75
|
+
if (idxFrom < idxTo) {
|
|
76
|
+
hasData = true;
|
|
77
|
+
}
|
|
78
|
+
blockAlpha = Math.max(blockAlpha, seg.outside ? 0.25 : 1.0);
|
|
79
|
+
}
|
|
80
|
+
if (!hasData) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
context.globalAlpha = blockAlpha;
|
|
84
|
+
const x = Math.max(bx, globalX0);
|
|
85
|
+
const w = Math.min(blockWidth, Math.min(bxEnd, globalX1) - x);
|
|
86
|
+
if (w <= 0) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const yMin = channelY0 + Math.floor((blockMin + gainScale) * yScale);
|
|
90
|
+
const yMax = channelY0 + Math.floor((blockMax + gainScale) * yScale);
|
|
91
|
+
const ry0 = Math.max(channelY0, Math.min(yMin, yMax));
|
|
92
|
+
const ry1 = Math.min(channelY1, Math.max(yMin, yMax));
|
|
93
|
+
const finalY1 = ry0 === ry1 ? ry0 + 1 : ry1;
|
|
94
|
+
const maxDist = Math.max(centerY - ry0, finalY1 - centerY);
|
|
95
|
+
const symY0 = centerY - maxDist;
|
|
96
|
+
const symY1 = centerY + maxDist;
|
|
97
|
+
const h = symY1 - symY0;
|
|
98
|
+
const r = Math.min(dpr, w / 2, h / 2);
|
|
99
|
+
context.beginPath();
|
|
100
|
+
context.roundRect(x, symY0, w, h, r);
|
|
101
|
+
context.fill();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
context.globalAlpha = 1.0;
|
|
105
|
+
}
|
|
106
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendaw/studio-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.124",
|
|
4
4
|
"license": "LGPL-3.0-or-later",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"@opendaw/lib-dawproject": "^0.0.63",
|
|
38
38
|
"@opendaw/lib-dom": "^0.0.77",
|
|
39
39
|
"@opendaw/lib-dsp": "^0.0.77",
|
|
40
|
-
"@opendaw/lib-fusion": "^0.0.
|
|
40
|
+
"@opendaw/lib-fusion": "^0.0.85",
|
|
41
41
|
"@opendaw/lib-runtime": "^0.0.73",
|
|
42
42
|
"@opendaw/lib-std": "^0.0.72",
|
|
43
43
|
"@opendaw/nam-wasm": "^1.0.3",
|
|
44
|
-
"@opendaw/studio-adapters": "^0.0.
|
|
44
|
+
"@opendaw/studio-adapters": "^0.0.99",
|
|
45
45
|
"@opendaw/studio-boxes": "^0.0.83",
|
|
46
46
|
"@opendaw/studio-enums": "^0.0.68",
|
|
47
47
|
"dropbox": "^10.34.0",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"@ffmpeg/ffmpeg": "^0.12.15",
|
|
58
58
|
"@ffmpeg/util": "^0.12.2",
|
|
59
59
|
"@opendaw/eslint-config": "^0.0.27",
|
|
60
|
-
"@opendaw/studio-core-processors": "^0.0.
|
|
61
|
-
"@opendaw/studio-core-workers": "^0.0.
|
|
60
|
+
"@opendaw/studio-core-processors": "^0.0.103",
|
|
61
|
+
"@opendaw/studio-core-workers": "^0.0.94",
|
|
62
62
|
"@opendaw/studio-forge-boxes": "^0.0.83",
|
|
63
63
|
"@opendaw/typescript-config": "^0.0.29"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "bcacc3de31ba8c899be229f7ca0b9186a21cd290"
|
|
66
66
|
}
|