mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 21:58:31 +00:00
improve csound bindings:
- better timing - can now pass instrument to .csound(...) - can now write instruments with csound(...)
This commit is contained in:
parent
729e0afdbe
commit
c40078ffc9
60
packages/csound/csd.mjs
Normal file
60
packages/csound/csd.mjs
Normal file
@ -0,0 +1,60 @@
|
||||
export function csd(code = '') {
|
||||
return `
|
||||
<CsoundSynthesizer>
|
||||
<CsOptions>
|
||||
-o dac --port=10000 --sample-accurate
|
||||
</CsOptions>
|
||||
<CsInstruments>
|
||||
sr=48000
|
||||
ksmps=64
|
||||
nchnls=2
|
||||
0dbfs=1
|
||||
|
||||
instr organ
|
||||
iduration = p3
|
||||
ifreq = p4
|
||||
igain = p5
|
||||
ioct = octcps(ifreq)
|
||||
|
||||
asig = vco2(igain, ifreq, 12, .5) ; my edit
|
||||
kpwm = oscili(.1, 5)
|
||||
asig = vco2(igain, ifreq, 4, .5 + kpwm)
|
||||
asig += vco2(igain/4, ifreq * 2)
|
||||
|
||||
; filter
|
||||
; idepth = 2
|
||||
; acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0) ; filter envelope
|
||||
; asig = zdf_2pole(asig, cpsoct(ioct + acut), 0.5)
|
||||
|
||||
; amp envelope
|
||||
iattack = .001
|
||||
irelease = .05
|
||||
asig *= linsegr:a(0, iattack, 1, iduration, 1, irelease, 0)
|
||||
|
||||
out(asig, asig)
|
||||
|
||||
endin
|
||||
|
||||
instr triangle
|
||||
iduration = p3
|
||||
ifreq = p4
|
||||
igain = p5
|
||||
ioct = octcps(ifreq)
|
||||
|
||||
asig = vco2(igain, ifreq, 12, .5)
|
||||
|
||||
; amp envelope
|
||||
iattack = .001
|
||||
irelease = .05
|
||||
asig *= linsegr:a(0, iattack, 1, iduration, 1, irelease, 0)
|
||||
|
||||
out(asig, asig)
|
||||
|
||||
endin
|
||||
|
||||
${code}
|
||||
|
||||
</CsInstruments>
|
||||
</CsoundSynthesizer>
|
||||
`;
|
||||
}
|
||||
@ -1,33 +1,72 @@
|
||||
import { Pattern } from '@strudel.cycles/core';
|
||||
import { getFrequency, logger, Pattern } from '@strudel.cycles/core';
|
||||
import { Csound } from '@csound/browser'; // TODO: use dynamic import for code splitting..
|
||||
import csd from './sounds.csd?raw';
|
||||
import { csd } from './csd.mjs';
|
||||
import { getAudioContext } from '@strudel.cycles/webaudio';
|
||||
|
||||
let csoundLoader;
|
||||
let csoundLoader, _csound;
|
||||
|
||||
Pattern.prototype.csound = async function () {
|
||||
if (!csoundLoader) {
|
||||
csoundLoader = (async () => {
|
||||
const csound = await Csound({ audioContext: getAudioContext() });
|
||||
await csound.setOption('-m0');
|
||||
await csound.compileCsdText(csd);
|
||||
await csound.setControlChannel('main.note.amp', -12);
|
||||
await csound.start();
|
||||
return csound;
|
||||
})();
|
||||
}
|
||||
const csound = await csoundLoader;
|
||||
// triggers given instrument name using csound. expects csound function to be called in advance `await csound()`
|
||||
Pattern.prototype._csound = function (instrument) {
|
||||
instrument = instrument || 'triangle';
|
||||
return this.onTrigger((time, hap, currentTime) => {
|
||||
const { gain = 0.8 } = hap.value;
|
||||
const deadline = time - currentTime;
|
||||
const midi = toMidi(getPlayableNoteValue(hap));
|
||||
if (!_csound) {
|
||||
logger('[csound] not loaded yet', 'warning');
|
||||
return;
|
||||
}
|
||||
let { gain = 0.8 } = hap.value;
|
||||
gain *= 0.2;
|
||||
|
||||
// const midi = toMidi(getPlayableNoteValue(hap));
|
||||
const freq = getFrequency(hap);
|
||||
// TODO: find out how to send a precise ctx based time
|
||||
// const ctime = `next_time(0.0001)+${deadline.toFixed(4)}`;
|
||||
const ctime = `${deadline.toFixed(8)}`;
|
||||
const cmidi = `cpsmidinn(${midi})`;
|
||||
const cgain = gain ? `ampdbfs(-32 + 32*${gain})` : `0`;
|
||||
const code = `schedule(1, ${ctime}, .125, ${cmidi}, ${cgain})`;
|
||||
// console.log('code', code);
|
||||
csound.evalCode(code);
|
||||
// http://www.csounds.com/manual/html/i.html
|
||||
const params = [
|
||||
`"${instrument}"`, // p1: instrument name
|
||||
time - currentTime, //.toFixed(precision), // p2: starting time in arbitrary unit called beats
|
||||
hap.duration + 0, // p3: duration in beats
|
||||
// instrument specific params:
|
||||
freq, //.toFixed(precision), // p4: frequency
|
||||
// -48 + gain * 24, // p5: gain
|
||||
gain, // p5: gain
|
||||
];
|
||||
const msg = `i ${params.join(' ')}`;
|
||||
// console.log('msg', msg);
|
||||
_csound.inputMessage(msg);
|
||||
// _csound.readScore(msg); // slower alternative
|
||||
// even slower alternative:
|
||||
/* const code = `schedule(${params.join(', ')})`;
|
||||
_csound.evalCode(code); */
|
||||
});
|
||||
};
|
||||
|
||||
// initializes csound + can be used to reevaluate given instrument code
|
||||
export async function csound(code = '') {
|
||||
code = csd(code);
|
||||
let isInit = false;
|
||||
if (!csoundLoader) {
|
||||
isInit = true;
|
||||
csoundLoader = (async () => {
|
||||
_csound = await Csound({ audioContext: getAudioContext() });
|
||||
await _csound.setOption('-m0');
|
||||
await _csound.compileCsdText(code);
|
||||
await _csound.start();
|
||||
})();
|
||||
}
|
||||
await csoundLoader;
|
||||
!isInit && (await _csound?.compileCsdText(code));
|
||||
}
|
||||
|
||||
// experimental: allows using jsx to eval csound
|
||||
window.jsxPragma = function (fn, args, text) {
|
||||
return fn(text);
|
||||
};
|
||||
|
||||
// experimental: for use via JSX as <CsInstruments>...</CsInstruments>
|
||||
export function CsInstruments(text) {
|
||||
if (Array.isArray(text)) {
|
||||
text = text[0];
|
||||
}
|
||||
return csound(text);
|
||||
}
|
||||
|
||||
Pattern.prototype.define('csound', (a, pat) => pat.csound(a), { composable: false, patternified: true });
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
;; based on https://kunstmusik.github.io/icsc2022-csound-web/tutorial2-interacting-with-csound/
|
||||
<CsoundSynthesizer>
|
||||
<CsOptions>
|
||||
-o dac --port=10000
|
||||
</CsOptions>
|
||||
<CsInstruments>
|
||||
sr=48000
|
||||
ksmps=64
|
||||
nchnls=2
|
||||
0dbfs=1
|
||||
|
||||
instr 1
|
||||
ioct = octcps(p4)
|
||||
kpwm = oscili(.1, 5)
|
||||
asig = vco2(p5, p4, 4, .5 + kpwm)
|
||||
asig += vco2(p5, p4 * 2)
|
||||
|
||||
idepth = 3
|
||||
acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0)
|
||||
asig = zdf_2pole(asig, cpsoct(ioct + acut), 0.125)
|
||||
|
||||
asig *= linsegr:a(1, p3, 1, .125, 0)
|
||||
|
||||
out(asig, asig)
|
||||
|
||||
endin
|
||||
|
||||
opcode next_time, i, i
|
||||
inext xin
|
||||
|
||||
itime = times:i()
|
||||
iticks = round(itime / inext)
|
||||
iticks += 1
|
||||
|
||||
iout = (iticks * inext) - itime
|
||||
xout iout
|
||||
endop
|
||||
|
||||
|
||||
</CsInstruments>
|
||||
</CsoundSynthesizer>
|
||||
@ -991,3 +991,115 @@ export const juxUndTollerei = `note("c3 eb3 g3 bb3").palindrome()
|
||||
.room(.6)
|
||||
.delay(.5).delaytime(.1).delayfeedback(.4)
|
||||
.pianoroll()`;
|
||||
|
||||
export const csoundTest = `await csound\`
|
||||
instr sawtooth
|
||||
iduration = p3
|
||||
ifreq = p4
|
||||
igain = p5
|
||||
ioct = octcps(ifreq)
|
||||
|
||||
asig = vco2(igain, ifreq, 0)
|
||||
|
||||
; amp envelope
|
||||
iattack = .5
|
||||
irelease = .1
|
||||
asig *= linsegr:a(0, iattack, 1, iduration, 1, irelease, 0)
|
||||
|
||||
idepth = 2
|
||||
acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0)
|
||||
asig = zdf_2pole(asig, 1000, 2)
|
||||
|
||||
out(asig, asig)
|
||||
endin\`
|
||||
|
||||
stack(
|
||||
note("<C^7 A7b13 Dm7 G7b9>/2".voicings()).s('sawtooth'),
|
||||
note("<c2 a2 d2 g2>/2").s('sawtooth')
|
||||
)
|
||||
.csound('sawtooth')`;
|
||||
|
||||
export const csoundTest2 = `await csound\`
|
||||
instr organ
|
||||
iduration = p3
|
||||
ifreq = p4
|
||||
igain = p5
|
||||
ioct = octcps(ifreq)
|
||||
|
||||
kpwm = oscili(.5, 2)
|
||||
asig = vco2(igain, ifreq, 4, .5 + kpwm)
|
||||
asig += vco2(igain/4, ifreq * 2)
|
||||
|
||||
iattack = .01
|
||||
irelease = .005
|
||||
asig *= linsegr:a(0, iattack, 1, iduration, 0, irelease, 0)
|
||||
|
||||
out(asig, asig)
|
||||
endin\`
|
||||
|
||||
"<0 2 [4 6](3,4,1) 3*2>"
|
||||
.off(1/4, add(2))
|
||||
.off(1/2, add(6))
|
||||
.scale('D minor')
|
||||
.legato(perlin.range(.2,2).slow(8))
|
||||
// .echo(4, 1/8, .5)
|
||||
.note()
|
||||
.pianoroll()
|
||||
.csound('organ');`;
|
||||
|
||||
export const csoundTest3 = `await csound\`
|
||||
instr CoolSynth
|
||||
iduration = p3
|
||||
ifreq = p4
|
||||
igain = p5
|
||||
ioct = octcps(ifreq)
|
||||
|
||||
kpwm = oscili(.05, 8)
|
||||
asig = vco2(igain, ifreq, 4, .5 + kpwm)
|
||||
asig += vco2(igain, ifreq * 2)
|
||||
|
||||
idepth = 2
|
||||
acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0) ; filter envelope
|
||||
asig = zdf_2pole(asig, cpsoct(ioct + acut + 2), 0.5)
|
||||
|
||||
iattack = .01
|
||||
isustain = .5
|
||||
idecay = .1
|
||||
irelease = .1
|
||||
asig *= linsegr:a(0, iattack, 1, idecay, isustain, iduration, isustain, irelease, 0)
|
||||
|
||||
out(asig, asig)
|
||||
endin\`
|
||||
|
||||
"<0 2 [4 6](3,4,1) 3*2>"
|
||||
.off(1/4, add(2))
|
||||
.off(1/2, add(6))
|
||||
.scale('D minor')
|
||||
.note()
|
||||
//.pianoroll()
|
||||
.csound("<CoolSynth triangle>/4")`;
|
||||
|
||||
export const csoundTest4 = `await csound()
|
||||
|
||||
stack(
|
||||
note("<C^7 A7b13 Dm7 G7b9>/2".voicings()).csound('organ').gain(.5),
|
||||
note("<c2 a2 d2 g2>/2".superimpose(add(.1))).s('sawtooth').cutoff(800).resonance(10).shape(.3)
|
||||
)`;
|
||||
|
||||
export const csoundMixed = `await csound()
|
||||
|
||||
stack(
|
||||
"<C^7 A7b13 Dm7 G7b9>/2".voicings()
|
||||
.add(rand.range(-.1,.1)).note()
|
||||
.csound('organ').gain(1).struct("[~@2 x]*2").legato(.25)
|
||||
,
|
||||
"<c2 a2 d2 g2>/2"
|
||||
.superimpose(add(rand.range(-.1,.1))).note()
|
||||
.s('sawtooth').cutoff(perlin.range(200,500)).resonance(10)
|
||||
.struct("x(4,6,1) x(5,6,2)")
|
||||
.decay(.1).sustain(0)
|
||||
,
|
||||
s("bd*2,hh:1(4,6),[~ sd]/2")
|
||||
.room(.5)
|
||||
.speed(perlin.range(.9,1.1).slow(4))
|
||||
).slow(2)`;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user