@kano/stem-daw 0.1.0
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/README.md +253 -0
- package/dist/chat-actions-54Z6URC4.js +7 -0
- package/dist/chat-actions-54Z6URC4.js.map +1 -0
- package/dist/chunk-56PWIP7O.js +1029 -0
- package/dist/chunk-56PWIP7O.js.map +1 -0
- package/dist/chunk-AAVC7KUW.js +145 -0
- package/dist/chunk-AAVC7KUW.js.map +1 -0
- package/dist/chunk-KCOOE2OP.js +1764 -0
- package/dist/chunk-KCOOE2OP.js.map +1 -0
- package/dist/chunk-LO74ZJ4H.js +23923 -0
- package/dist/chunk-LO74ZJ4H.js.map +1 -0
- package/dist/chunk-OFGZURP6.js +247 -0
- package/dist/chunk-OFGZURP6.js.map +1 -0
- package/dist/chunk-OYNES5W3.js +3085 -0
- package/dist/chunk-OYNES5W3.js.map +1 -0
- package/dist/chunk-QQ5NZTHT.js +336 -0
- package/dist/chunk-QQ5NZTHT.js.map +1 -0
- package/dist/chunk-TBXCZFAY.js +13713 -0
- package/dist/chunk-TBXCZFAY.js.map +1 -0
- package/dist/chunk-U44X6QP5.js +281 -0
- package/dist/chunk-U44X6QP5.js.map +1 -0
- package/dist/chunk-UKMELGZL.js +27 -0
- package/dist/chunk-UKMELGZL.js.map +1 -0
- package/dist/components/DAWView.d.ts +19 -0
- package/dist/components/DAWView.js +11 -0
- package/dist/components/DAWView.js.map +1 -0
- package/dist/daw-controller-BjRWcTol.d.ts +339 -0
- package/dist/engine/daw-controller.d.ts +3 -0
- package/dist/engine/daw-controller.js +5 -0
- package/dist/engine/daw-controller.js.map +1 -0
- package/dist/engine/daw-import-stem-fm-config.d.ts +224 -0
- package/dist/engine/daw-import-stem-fm-config.js +7 -0
- package/dist/engine/daw-import-stem-fm-config.js.map +1 -0
- package/dist/fetchStationTracks-SKFT4V3U.js +3 -0
- package/dist/fetchStationTracks-SKFT4V3U.js.map +1 -0
- package/dist/index.d.ts +308 -0
- package/dist/index.js +332 -0
- package/dist/index.js.map +1 -0
- package/dist/interface-DaRj7RkY.d.ts +66 -0
- package/dist/interfaces-5ZlG0Y4Y.d.ts +549 -0
- package/dist/media-session-XTP6PP7Q.js +3 -0
- package/dist/media-session-XTP6PP7Q.js.map +1 -0
- package/dist/note-detection-PPLM7R2H.js +148 -0
- package/dist/note-detection-PPLM7R2H.js.map +1 -0
- package/dist/sampler-audio-B7MBG3YN.js +3 -0
- package/dist/sampler-audio-B7MBG3YN.js.map +1 -0
- package/dist/sampler-store-QPHANXYP.js +3 -0
- package/dist/sampler-store-QPHANXYP.js.map +1 -0
- package/dist/services/track-search-api.d.ts +152 -0
- package/dist/services/track-search-api.js +4 -0
- package/dist/services/track-search-api.js.map +1 -0
- package/dist/store/daw-auth-store.d.ts +31 -0
- package/dist/store/daw-auth-store.js +3 -0
- package/dist/store/daw-auth-store.js.map +1 -0
- package/dist/store/daw-session-store.d.ts +255 -0
- package/dist/store/daw-session-store.js +3 -0
- package/dist/store/daw-session-store.js.map +1 -0
- package/dist/vite/index.d.ts +46 -0
- package/dist/vite/index.js +94 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/workers/analysis-worker.js +379 -0
- package/dist/workers/buffer-player-processor-202602.lavv8e32-ts.js +1 -0
- package/dist/workers/daw-stem-processor.js +228 -0
- package/dist/workers/manifest.json +10 -0
- package/dist/workers/phase-vocoder3.js +920 -0
- package/dist/workers/realtime-pitch-shift-processor.js +2 -0
- package/package.json +151 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const FADE_SAMPLES = 480;
|
|
2
|
+
const MUTE_FADE = 64;
|
|
3
|
+
class DAWStemProcessor extends AudioWorkletProcessor {
|
|
4
|
+
channels = [];
|
|
5
|
+
numChannels = 0;
|
|
6
|
+
bufferLength = 0;
|
|
7
|
+
playing = false;
|
|
8
|
+
readPos = 0;
|
|
9
|
+
// fractional sample position in native buffer
|
|
10
|
+
speed = 1;
|
|
11
|
+
// fallback uniform speed (used when no bar map)
|
|
12
|
+
globalRate = 1;
|
|
13
|
+
// global playback rate multiplier
|
|
14
|
+
// Per-bar speed map: sorted by sampleStart ascending.
|
|
15
|
+
barMap = [];
|
|
16
|
+
barMapIdx = 0;
|
|
17
|
+
// Per-bar pitch map: 1:1 with barMap, each entry is the pitchFactor for that bar.
|
|
18
|
+
// Sent to the main thread at each bar crossing for relay to Rubberband.
|
|
19
|
+
pitchMap = [];
|
|
20
|
+
// Mute regions: sorted by sampleStart. Audio in these ranges outputs silence.
|
|
21
|
+
muteRegions = [];
|
|
22
|
+
// Fade state
|
|
23
|
+
fadeGain = 0;
|
|
24
|
+
fadeTarget = 0;
|
|
25
|
+
fadeStep = 0;
|
|
26
|
+
constructor() {
|
|
27
|
+
super();
|
|
28
|
+
this.port.onmessage = (e) => {
|
|
29
|
+
const { type } = e.data;
|
|
30
|
+
switch (type) {
|
|
31
|
+
case "load-buffer": {
|
|
32
|
+
this.channels = e.data.channels;
|
|
33
|
+
this.numChannels = this.channels.length;
|
|
34
|
+
this.bufferLength = this.numChannels > 0 ? this.channels[0].length : 0;
|
|
35
|
+
this.readPos = 0;
|
|
36
|
+
this.playing = false;
|
|
37
|
+
this.fadeGain = 0;
|
|
38
|
+
this.fadeTarget = 0;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case "dump-buffer": {
|
|
42
|
+
this.channels = [];
|
|
43
|
+
this.numChannels = 0;
|
|
44
|
+
this.bufferLength = 0;
|
|
45
|
+
this.playing = false;
|
|
46
|
+
this.readPos = 0;
|
|
47
|
+
this.fadeGain = 0;
|
|
48
|
+
this.fadeTarget = 0;
|
|
49
|
+
this.barMapIdx = 0;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case "patch-buffer": {
|
|
53
|
+
const patch = e.data.channels;
|
|
54
|
+
const offset = e.data.sampleOffset | 0;
|
|
55
|
+
for (let ch = 0; ch < patch.length; ch++) {
|
|
56
|
+
const dst = this.channels[ch];
|
|
57
|
+
if (!dst) continue;
|
|
58
|
+
const src = patch[ch];
|
|
59
|
+
const remaining = dst.length - offset;
|
|
60
|
+
if (remaining <= 0) continue;
|
|
61
|
+
const copyLen = src.length <= remaining ? src.length : remaining;
|
|
62
|
+
if (copyLen === src.length) {
|
|
63
|
+
dst.set(src, offset);
|
|
64
|
+
} else {
|
|
65
|
+
dst.set(src.subarray(0, copyLen), offset);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "load-bar-map": {
|
|
71
|
+
this.barMap = e.data.entries;
|
|
72
|
+
this.barMapIdx = 0;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "load-pitch-map": {
|
|
76
|
+
const entries = e.data.entries;
|
|
77
|
+
this.pitchMap = entries.map((e2) => e2.pitchFactor);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "load-mute-regions": {
|
|
81
|
+
this.muteRegions = e.data.regions;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "play": {
|
|
85
|
+
this.playing = true;
|
|
86
|
+
this.fadeTarget = 1;
|
|
87
|
+
this.fadeStep = 1 / FADE_SAMPLES;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "pause": {
|
|
91
|
+
this.fadeTarget = 0;
|
|
92
|
+
this.fadeStep = 1 / FADE_SAMPLES;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "seek": {
|
|
96
|
+
this.readPos = e.data.position;
|
|
97
|
+
this.barMapIdx = this.findBarIndex(this.readPos);
|
|
98
|
+
if (this.playing) {
|
|
99
|
+
this.fadeGain = 0;
|
|
100
|
+
this.fadeTarget = 1;
|
|
101
|
+
this.fadeStep = 1 / FADE_SAMPLES;
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case "set-speed": {
|
|
106
|
+
this.speed = e.data.speed;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "set-global-rate": {
|
|
110
|
+
this.globalRate = e.data.rate;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case "stop": {
|
|
114
|
+
this.playing = false;
|
|
115
|
+
this.readPos = 0;
|
|
116
|
+
this.fadeGain = 0;
|
|
117
|
+
this.fadeTarget = 0;
|
|
118
|
+
this.barMapIdx = 0;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/** Binary search to find which bar entry the given sample position falls in */
|
|
125
|
+
findBarIndex(pos) {
|
|
126
|
+
const map = this.barMap;
|
|
127
|
+
if (map.length === 0) return 0;
|
|
128
|
+
let lo = 0, hi = map.length - 1;
|
|
129
|
+
while (lo < hi) {
|
|
130
|
+
const mid = lo + hi + 1 >> 1;
|
|
131
|
+
if (map[mid].sampleStart <= pos) lo = mid;
|
|
132
|
+
else hi = mid - 1;
|
|
133
|
+
}
|
|
134
|
+
return lo;
|
|
135
|
+
}
|
|
136
|
+
/** Check if a sample position falls inside any mute region, with short crossfade */
|
|
137
|
+
muteGainAt(pos) {
|
|
138
|
+
for (let i = 0; i < this.muteRegions.length; i++) {
|
|
139
|
+
const r = this.muteRegions[i];
|
|
140
|
+
if (pos >= r.sampleStart && pos < r.sampleEnd) {
|
|
141
|
+
const distIn = pos - r.sampleStart;
|
|
142
|
+
const distOut = r.sampleEnd - pos;
|
|
143
|
+
if (distIn < MUTE_FADE) return distIn / MUTE_FADE;
|
|
144
|
+
if (distOut < MUTE_FADE) return distOut / MUTE_FADE;
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return 1;
|
|
149
|
+
}
|
|
150
|
+
/** Send the pre-computed pitch factor to the main thread for relay to Rubberband.
|
|
151
|
+
* Includes sampleOffset (where in the 128-sample block the bar boundary fell)
|
|
152
|
+
* and audioTime so the pitch worklet can align its delay precisely. */
|
|
153
|
+
sendPitchForBar(barIdx, sampleOffset) {
|
|
154
|
+
if (barIdx >= this.pitchMap.length) return;
|
|
155
|
+
const factor = this.pitchMap[barIdx];
|
|
156
|
+
if (factor === void 0) return;
|
|
157
|
+
this.port.postMessage({
|
|
158
|
+
type: "pitch-for-bar",
|
|
159
|
+
barIndex: barIdx,
|
|
160
|
+
pitchFactor: factor,
|
|
161
|
+
sampleOffset,
|
|
162
|
+
audioTime: currentTime
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/** Get the effective speed for the current readPos, using bar map if available.
|
|
166
|
+
* sampleOffset is the current position within the output block (0..127). */
|
|
167
|
+
currentSpeed(sampleOffset) {
|
|
168
|
+
if (this.barMap.length === 0) {
|
|
169
|
+
return this.speed * this.globalRate;
|
|
170
|
+
}
|
|
171
|
+
while (this.barMapIdx < this.barMap.length - 1 && this.readPos >= this.barMap[this.barMapIdx + 1].sampleStart) {
|
|
172
|
+
this.barMapIdx++;
|
|
173
|
+
this.port.postMessage({ type: "bar-changed", barIndex: this.barMapIdx, sampleOffset, audioTime: currentTime });
|
|
174
|
+
this.sendPitchForBar(this.barMapIdx, sampleOffset);
|
|
175
|
+
}
|
|
176
|
+
return this.barMap[this.barMapIdx].speed * this.globalRate;
|
|
177
|
+
}
|
|
178
|
+
process(_inputs, outputs) {
|
|
179
|
+
const output = outputs[0];
|
|
180
|
+
if (!output || output.length === 0) return true;
|
|
181
|
+
const blockSize = output[0].length;
|
|
182
|
+
const outChannels = output.length;
|
|
183
|
+
if (this.bufferLength === 0 || !this.playing && this.fadeGain === 0) {
|
|
184
|
+
for (let ch = 0; ch < outChannels; ch++) {
|
|
185
|
+
output[ch].fill(0);
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
const hasMuteRegions = this.muteRegions.length > 0;
|
|
190
|
+
for (let i = 0; i < blockSize; i++) {
|
|
191
|
+
if (this.fadeGain < this.fadeTarget) {
|
|
192
|
+
this.fadeGain = Math.min(this.fadeGain + this.fadeStep, 1);
|
|
193
|
+
} else if (this.fadeGain > this.fadeTarget) {
|
|
194
|
+
this.fadeGain = Math.max(this.fadeGain - this.fadeStep, 0);
|
|
195
|
+
if (this.fadeGain === 0 && this.fadeTarget === 0) {
|
|
196
|
+
this.playing = false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const pos = this.readPos;
|
|
200
|
+
const intPos = Math.floor(pos);
|
|
201
|
+
const frac = pos - intPos;
|
|
202
|
+
if (intPos >= 0 && intPos < this.bufferLength) {
|
|
203
|
+
const mg = hasMuteRegions ? this.muteGainAt(pos) : 1;
|
|
204
|
+
const gain = this.fadeGain * mg;
|
|
205
|
+
if (gain === 0) {
|
|
206
|
+
for (let ch = 0; ch < outChannels; ch++) output[ch][i] = 0;
|
|
207
|
+
} else {
|
|
208
|
+
for (let ch = 0; ch < outChannels; ch++) {
|
|
209
|
+
const srcCh = ch < this.numChannels ? ch : 0;
|
|
210
|
+
const buf = this.channels[srcCh];
|
|
211
|
+
const s0 = buf[intPos];
|
|
212
|
+
const s1 = intPos + 1 < this.bufferLength ? buf[intPos + 1] : s0;
|
|
213
|
+
output[ch][i] = (s0 + frac * (s1 - s0)) * gain;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
for (let ch = 0; ch < outChannels; ch++) {
|
|
218
|
+
output[ch][i] = 0;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (this.playing) {
|
|
222
|
+
this.readPos += this.currentSpeed(i);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
registerProcessor("daw-stem-processor", DAWStemProcessor);
|