@audio/shift-sample 1.0.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/index.js +46 -0
- package/package.json +41 -0
package/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { bufferedStream, makePitchShift, resolveRatio, sincRead } from '@audio/shift-core'
|
|
2
|
+
|
|
3
|
+
// Canonical sampler pitch shift. A Hann-windowed sinc interpolator reads the source at
|
|
4
|
+
// a fractional stride of `ratio` per output sample — the same intuition as a hardware
|
|
5
|
+
// sampler playing a one-shot at a different rate, or a tracker module running the same
|
|
6
|
+
// waveform faster. There is no time preservation: output duration is `input_length /
|
|
7
|
+
// ratio`. The tail is zero-padded so the unified batch API (`output.length === input
|
|
8
|
+
// .length`) still holds, but the active region is genuinely shorter on pitch-up.
|
|
9
|
+
//
|
|
10
|
+
// Pitch preservation is exact (fractional-stride sinc over a clean buffer is an ideal
|
|
11
|
+
// resampler), at the cost of losing time — the one thing every other algorithm in this
|
|
12
|
+
// package keeps. Use it when that is the intended effect: instrument one-shots, sampler
|
|
13
|
+
// voices, tracker playback, anything where "higher pitch = shorter clip" is the point.
|
|
14
|
+
// Anti-aliasing is inherited from the shared `sincRead`: `cutoff = min(1, 1/ratio)`
|
|
15
|
+
// suppresses content above the new Nyquist before it folds.
|
|
16
|
+
function sampleBatch(data, opts) {
|
|
17
|
+
let { ratio, ratioFn } = resolveRatio(opts)
|
|
18
|
+
let r = opts?.sincRadius ?? 8
|
|
19
|
+
let n = data.length
|
|
20
|
+
let out = new Float32Array(n)
|
|
21
|
+
let readPos = 0
|
|
22
|
+
// Scalar ratio (the common case) hoists cutoff out of the loop and never calls a host
|
|
23
|
+
// closure — the repo's one per-output-sample dynamic call otherwise sits in this loop.
|
|
24
|
+
if (!ratioFn) {
|
|
25
|
+
let cutoff = ratio > 1 ? 1 / ratio : 1
|
|
26
|
+
for (let i = 0; i < n; i++) {
|
|
27
|
+
if (readPos >= n) break
|
|
28
|
+
out[i] = sincRead(data, readPos, r, cutoff)
|
|
29
|
+
readPos += ratio
|
|
30
|
+
}
|
|
31
|
+
return out
|
|
32
|
+
}
|
|
33
|
+
let sr = opts?.sampleRate || 44100
|
|
34
|
+
for (let i = 0; i < n; i++) {
|
|
35
|
+
if (readPos >= n) break
|
|
36
|
+
let rNow = ratioFn(i / sr)
|
|
37
|
+
let cutoff = rNow > 1 ? 1 / rNow : 1
|
|
38
|
+
out[i] = sincRead(data, readPos, r, cutoff)
|
|
39
|
+
readPos += rNow
|
|
40
|
+
}
|
|
41
|
+
return out
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let sampleStream = (opts) => bufferedStream(sampleBatch, opts)
|
|
45
|
+
|
|
46
|
+
export default makePitchShift(sampleBatch, sampleStream)
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audio/shift-sample",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Sampler-style pitch shift — sinc-interpolated fractional-stride resample (no time preservation)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.js"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@audio/shift-core": "^1.0.0"
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "audiojs",
|
|
23
|
+
"homepage": "https://github.com/audiojs/shift/tree/main/packages/shift-sample#readme",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/audiojs/shift.git",
|
|
27
|
+
"directory": "packages/shift-sample"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"audio",
|
|
31
|
+
"pitch-shift",
|
|
32
|
+
"sampler",
|
|
33
|
+
"resample",
|
|
34
|
+
"sinc",
|
|
35
|
+
"tracker",
|
|
36
|
+
"dsp"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
}
|
|
41
|
+
}
|