@grame/faustwasm 0.1.4 → 0.1.5
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/cjs-bundle/index.js +1 -1
- package/dist/esm-bundle/index.js +1 -1
- package/libfaust-wasm/libfaust-wasm.js +1 -1
- package/libfaust-wasm/libfaust-wasm.wasm +0 -0
- package/out/clarinetMIDI.html +50 -0
- package/out/clarinetMIDI.js +63 -0
- package/out/clarinetMIDI.json +431 -0
- package/out/clarinetMIDI.wasm +0 -0
- package/out/faustwasm/index.d.ts +1495 -0
- package/out/faustwasm/index.js +4470 -0
- package/out/faustwasm/index.js.map +7 -0
- package/package.json +1 -1
- package/test/Timestrech.dsp +150 -0
- package/test/emsc.dsp +5 -0
- package/test/tp1-mono.dsp +20 -0
- package/test/tp1.dsp +20 -0
package/package.json
CHANGED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Time Stretch Sampler
|
|
2
|
+
// written in Faust by David Braun
|
|
3
|
+
// Based on
|
|
4
|
+
// https://github.com/dar-io-p/potenza-time-stretch/blob/main/TimeStretch.h
|
|
5
|
+
// License: GNU GPLv3
|
|
6
|
+
// https://github.com/dar-io-p/potenza-time-stretch/blob/main/LICENSE
|
|
7
|
+
|
|
8
|
+
// todo:
|
|
9
|
+
// * Figure out why the various Loop modes aren't working
|
|
10
|
+
// * Add Portamento glide
|
|
11
|
+
// * Use Lagrange interpolation of soundfile
|
|
12
|
+
|
|
13
|
+
import("stdfaust.lib");
|
|
14
|
+
|
|
15
|
+
s = IGNORE(soundfile("sound[url:{'SixMillionVox.wav']", 2));
|
|
16
|
+
|
|
17
|
+
Sampler(s) = (resetState : advance) ~ init : si.bus(4), totalPhase, direction : ro.interleave(2,2) : grainPlayer, grainPlayer :> si.bus(2)
|
|
18
|
+
with {
|
|
19
|
+
totalPhase = !;
|
|
20
|
+
direction = !;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
ENVELOPE(x) = vgroup("[0] Envelope", x);
|
|
24
|
+
Markers(x) = vgroup("[1] Markers", x);
|
|
25
|
+
PLAYMODES(x) = vgroup("[2] Modes", x);
|
|
26
|
+
STRETCH(x) = vgroup("[3] Stretch", x);
|
|
27
|
+
PITCH(x) = vgroup("[4] Pitch", x);
|
|
28
|
+
IGNORE(x) = vgroup("[99] Ignore", x);
|
|
29
|
+
|
|
30
|
+
rootNote = PITCH(hslider("Root Note [style:knob]", 36, 20, 127, 1));
|
|
31
|
+
fineTune = PITCH(hslider("Fine Tune [style:knob]", 0, -99, 99, 1));
|
|
32
|
+
|
|
33
|
+
ratio = IGNORE(hslider("freq [style:knob]", 440, 20, 20000, 1)) : ba.hz2midikey : _-rootNote + (fineTune/100) : ba.semi2ratio;
|
|
34
|
+
gain = IGNORE(hslider("gain [style:knob]", 0, 0, 1, .01));
|
|
35
|
+
gate = IGNORE(button("gate"));
|
|
36
|
+
|
|
37
|
+
envEnable = ENVELOPE(checkbox("[0] Enable")); // todo: default to ON somehow
|
|
38
|
+
envAttack = ENVELOPE(hslider("[1] Attack [unit:seconds]", 0, 0, 5, .01)); // todo: better scale
|
|
39
|
+
envRelease = ENVELOPE(hslider("[2] Release [unit:seconds]", 0.005, 0, 5, .01)); // todo: better scale
|
|
40
|
+
|
|
41
|
+
envGain = ba.if(envEnable, en.asr(envAttack, 1, envRelease, gate), 1);
|
|
42
|
+
|
|
43
|
+
c = STRETCH(hslider("Crossfade [style:knob]", 0.4, 0.01, 0.5, .01));
|
|
44
|
+
grainSize = STRETCH(hslider("Grain Size [style:knob]", 1000, 20, 2000, 10));
|
|
45
|
+
stretchFactor = STRETCH(hslider("Stretch [style:knob]", 1, 1, 20, .1)
|
|
46
|
+
// : ba.if(stretchComp, _, 1) // todo: I want to do this but can't until stretchComp can default to ON.
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
pitchCompensator = ba.if(PLAYMODES(checkbox("Pitch Comp")), stretchFactor, 1);
|
|
50
|
+
stretchComp = PLAYMODES(checkbox("Stretch Enable"));
|
|
51
|
+
reverse = PLAYMODES(checkbox("[0] Reverse"));
|
|
52
|
+
loop = PLAYMODES(checkbox("[1] Loop Enable"));
|
|
53
|
+
pong = PLAYMODES(checkbox("[2] Pong Enable")); // pong only matters if loop is ON
|
|
54
|
+
|
|
55
|
+
cPrime = 1-c;
|
|
56
|
+
|
|
57
|
+
MAX_AUDIO_LENGTH = 44100*10; // 10 seconds
|
|
58
|
+
|
|
59
|
+
sampleStart = Markers(hslider("[0] Sample Start", 0, 0, MAX_AUDIO_LENGTH, 1));
|
|
60
|
+
loopPos = Markers(hslider("[1] Loop Position", 0, 0, MAX_AUDIO_LENGTH, 1));
|
|
61
|
+
sampleEnd = Markers(hslider("[2] Sample End", MAX_AUDIO_LENGTH, 0, MAX_AUDIO_LENGTH, 1));
|
|
62
|
+
|
|
63
|
+
resetState(_phase1, _phase2, _grain1, _grain2, _totalPhase, _direction) = result
|
|
64
|
+
with {
|
|
65
|
+
doReset = gate & (gate'==0); // noteOn
|
|
66
|
+
samplePos = ba.if(reverse, sampleEnd, sampleStart);
|
|
67
|
+
resultIfResetForward = 0, -1, samplePos, samplePos, samplePos, 1;
|
|
68
|
+
resultIfResetBackward = grainSize, -1, (samplePos-grainSize), (samplePos-grainSize), samplePos, -1;
|
|
69
|
+
resultIfNotReset = _phase1, _phase2, _grain1, _grain2, _totalPhase, _direction;
|
|
70
|
+
result = ba.selectmulti(0, (resultIfNotReset, resultIfResetForward, resultIfResetBackward), doReset*ba.if(reverse, 2, 1));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
advance(_phase1, _phase2, _grain1, _grain2, _totalPhase, _direction) = ba.selectmulti(0, (resultBackward, resultForward), ba.if(_direction>0, 1, 0))
|
|
74
|
+
with {
|
|
75
|
+
// local vars
|
|
76
|
+
f1 = grainSize * c;
|
|
77
|
+
f2 = grainSize * cPrime;
|
|
78
|
+
stretchFactorInverse = 1. / stretchFactor;
|
|
79
|
+
grainOffset = grainSize*cPrime*stretchFactorInverse;
|
|
80
|
+
|
|
81
|
+
pitchDelta = ratio * pitchCompensator;
|
|
82
|
+
|
|
83
|
+
resultForward = ba.selectmulti(0, (resultIfNoNewGrain, resultIfNewGrain), (phase1 >= f2)), totalPhase, direction
|
|
84
|
+
with {
|
|
85
|
+
totalPhase = _totalPhase + pitchDelta*stretchFactorInverse;
|
|
86
|
+
phase1 = _phase1 + ba.if((_grain1 + _phase1) < sampleEnd, pitchDelta, 0);
|
|
87
|
+
|
|
88
|
+
phase2a = _phase2 + ba.if((_phase2 > -1) & (_grain2 + _phase2 < sampleEnd), pitchDelta, 0);
|
|
89
|
+
|
|
90
|
+
phase2 = ba.if(phase2a >= grainSize, -1, phase2a);
|
|
91
|
+
|
|
92
|
+
doLoop = loop & (_grain1 + phase1 >= sampleEnd); // todo: or use totalPhase >= sampleEnd?
|
|
93
|
+
doPong = pong & doLoop;
|
|
94
|
+
direction = ba.if(doPong, -1, 1);
|
|
95
|
+
grain1 = ba.if(doPong, sampleEnd, ba.if(doLoop, loopPos, _grain1+grainOffset));
|
|
96
|
+
|
|
97
|
+
resultIfNoNewGrain = phase1, phase2, _grain1, _grain2;
|
|
98
|
+
resultIfNewGrain = ba.if(doPong, grainSize, 0), phase1, grain1, _grain1;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
resultBackward = ba.selectmulti(0, (resultIfNoNewGrain, resultIfNewGrain), (phase1 <= f1)), totalPhase, direction
|
|
102
|
+
with {
|
|
103
|
+
totalPhase = _totalPhase - pitchDelta*stretchFactorInverse;
|
|
104
|
+
phase1 = _phase1 - ba.if((_grain1 + _phase1) > sampleStart, pitchDelta, 0);
|
|
105
|
+
|
|
106
|
+
phase2a = _phase2 - ba.if((_phase2 > -1) & (_grain2 + _phase2 > sampleStart), pitchDelta, 0);
|
|
107
|
+
|
|
108
|
+
phase2 = ba.if(phase2a <= 0, -1, phase2a);
|
|
109
|
+
|
|
110
|
+
doLoop = loop & (_grain1+phase1 <= loopPos); // todo: or use totalPhase < loopPos?
|
|
111
|
+
doPong = pong & doLoop;
|
|
112
|
+
direction = ba.if(doPong, 1, -1);
|
|
113
|
+
grain1 = ba.if(doPong, loopPos, ba.if(doLoop, sampleEnd, _grain1-grainOffset));
|
|
114
|
+
|
|
115
|
+
resultIfNoNewGrain = phase1, phase2, _grain1, _grain2;
|
|
116
|
+
resultIfNewGrain = ba.if(doPong, 0, grainSize), phase1, grain1, _grain1;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
grainPlayer(phase, grain) = (part, pos) : outs(s) : sp.stereoize(_* windowGain * gain * envGain * safeGain)
|
|
121
|
+
with {
|
|
122
|
+
pos = phase+grain;
|
|
123
|
+
windowGain = phase : ba.bpf.start(0, 0) : ba.bpf.point(grainSize*c, 1) : ba.bpf.point(grainSize*cPrime, 1) : ba.bpf.end(grainSize, 0)
|
|
124
|
+
: _*ma.PI*.5 : sin <: _*_ :>_ // enable this line for constant-powered window blending
|
|
125
|
+
;
|
|
126
|
+
safeGain = ba.if(pos>=sampleEnd, 0, 1);
|
|
127
|
+
part = 0;
|
|
128
|
+
// get file's properties
|
|
129
|
+
length(s) = part,0 : s : _,si.block(outputs(s)-1);
|
|
130
|
+
srate(s) = part,0 : s : !,_,si.block(outputs(s)-2);
|
|
131
|
+
// play sample
|
|
132
|
+
outs(s) = s : si.block(2), si.bus(outputs(s)-2);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
init(_phase1, _phase2, _grain1, _grain2, _totalPhase, _direction) = _phase1, _phase2, _grain1, _grain2, _totalPhase, ba.if(ba.time==0, 1, _direction);
|
|
136
|
+
|
|
137
|
+
phaseEffect = sp.stereoize((+ ~ (de.fdelayltv(N, MAX_DELAY_SAMPLES, delayAmt)*fbGain)))
|
|
138
|
+
with {
|
|
139
|
+
fbGain = ba.if(phaseAmt == 0, 0, 0.6);
|
|
140
|
+
phaseAmt = hslider("Phase", 0, 0, 30, .01);
|
|
141
|
+
N = 2;
|
|
142
|
+
MAX_DELAY_SAMPLES = 30/1000:ba.sec2samp;
|
|
143
|
+
delayAmt = phaseAmt: si.smoo : _/1000:ba.sec2samp;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Remember to use ScriptProcessor instead of AudioWorklet!
|
|
147
|
+
process = hgroup("Amigo", Sampler(s));
|
|
148
|
+
|
|
149
|
+
effect = phaseEffect;
|
|
150
|
+
// effect = _, _;
|
package/test/emsc.dsp
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import("stdfaust.lib");
|
|
2
|
+
|
|
3
|
+
part = nentry("file", 0, 0, 1, 1);
|
|
4
|
+
speed = hslider("speed", 1, 0, 4, 0.01);
|
|
5
|
+
level = hslider("level", 0.5, 0, 1, 0.01);
|
|
6
|
+
|
|
7
|
+
//process = (part, +(1)~_) : soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav'}]",2) :(!,!,_,_);
|
|
8
|
+
|
|
9
|
+
//process = so.loop(soundfile("files [url: {'/Documents/faust-github-faust2/tests/soundfile/RnB.wav';'/Documents/faust-github-faust2/tests/soundfile/tango.wav';'/Documents/faust-github-faust2/tests/soundfile/levot.wav'}]",2), part);
|
|
10
|
+
|
|
11
|
+
//process = so.loop_speed(soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav'}]",2), part, speed);
|
|
12
|
+
|
|
13
|
+
//process = so.loop_speed_level(soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav'}]",2), part, speed, level);
|
|
14
|
+
|
|
15
|
+
//process = so.loop_speed_level(soundfile("files [url: {'RnB.wav';'tango.wav';'levot-all.wav'}]",2), part, speed, level);
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
//process = so.loop_speed_level(soundfile("files [url: {'http://127.0.0.1:8000/RnB.wav';'http://127.0.0.1:8000/tango.wav';'http://127.0.0.1:8000/levot.wav'}]",2), part, speed, level);
|
|
19
|
+
|
|
20
|
+
process = so.loop_speed_level(soundfile("files [url: {'levot-15-mono.wav';'violon.wav'}]",2), part, speed, level) : dm.freeverb_demo;
|
package/test/tp1.dsp
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import("stdfaust.lib");
|
|
2
|
+
|
|
3
|
+
part = nentry("file", 0, 0, 5, 1);
|
|
4
|
+
speed = hslider("speed", 1, 0, 4, 0.01);
|
|
5
|
+
level = hslider("level", 0.5, 0, 1, 0.01);
|
|
6
|
+
|
|
7
|
+
//process = (part, +(1)~_) : soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav'}]",2) :(!,!,_,_);
|
|
8
|
+
|
|
9
|
+
//process = so.loop(soundfile("files [url: {'/Documents/faust-github-faust2/tests/soundfile/RnB.wav';'/Documents/faust-github-faust2/tests/soundfile/tango.wav';'/Documents/faust-github-faust2/tests/soundfile/levot.wav'}]",2), part);
|
|
10
|
+
|
|
11
|
+
//process = so.loop_speed(soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav'}]",2), part, speed);
|
|
12
|
+
|
|
13
|
+
//process = so.loop_speed_level(soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav'}]",2), part, speed, level);
|
|
14
|
+
|
|
15
|
+
//process = so.loop_speed_level(soundfile("files [url: {'RnB.wav';'tango.wav';'levot-all.wav'}]",2), part, speed, level);
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
//process = so.loop_speed_level(soundfile("files [url: {'http://127.0.0.1:8000/RnB.wav';'http://127.0.0.1:8000/tango.wav';'http://127.0.0.1:8000/levot.wav'}]",2), part, speed, level);
|
|
19
|
+
|
|
20
|
+
process = so.loop_speed_level(soundfile("files [url: {'RnB.wav';'tango.wav';'levot.wav';'violon.wav';'RnB.wav';'tango.wav';'levot.wav';'violon.wav'}]",2), part, speed, level);
|