Initial commit: sound_algo SuperCollider live coding system
23 generative tracks (A-W), 5 live API namespaces (kicks/melodies/fx/ chains/patterns), 38 SynthDef, mixer/scenes/loops/jump infrastructure, 130+ melodies in 4 length classes (32/64/96/128 steps), 16 scales, 10 harmony presets, 16 drum kits, 30 genre patterns. Tests: 10 E2E suites, 365 assertions, all passing. Local Claude Code skills: validating-scd-files, scaffolding-track, registering-jump-section, adding-synthdef, generating-live-wrappers.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
---
|
||||
name: adding-synthdef
|
||||
description: Use when the user asks to "add a SynthDef", "create a new instrument", "ajouter un instrument", or names a synthesis technique to package (FM, granular, Karplus-Strong, formant, etc.). Generates a SynthDef in `synthdefs/asia.scd`, `synthdefs/extra.scd`, or `synthdefs/authentic.scd` following the rigid 32-SynthDef convention of sound_algo: standard arg signature (freq/gate/ADSR/amp/pan/scBus/scAmt), `EnvGen.kr(..., doneAction: 2)`, `Pan2.ar` final, `LeakDC.ar` after feedback, `clip` on freq, `tanh` saturation pattern. Forgetting `doneAction: 2` creates Synth zombies that accumulate in RAM until the server crashes.
|
||||
---
|
||||
|
||||
# Adding a SynthDef
|
||||
|
||||
## Where to put it
|
||||
|
||||
| File | Theme |
|
||||
| --- | --- |
|
||||
| `synthdefs/asia.scd` | World/exotic timbres (koto, erhu, gong, growl) |
|
||||
| `synthdefs/extra.scd` | Misc additions |
|
||||
| `synthdefs/authentic.scd` | Vintage/authentic emulations |
|
||||
| `engine.scd` | DO NOT add here -- it's the core, kept stable |
|
||||
|
||||
## Standard arg signature
|
||||
|
||||
Every SynthDef MUST accept these args (with defaults) :
|
||||
|
||||
```supercollider
|
||||
arg freq = 220, gate = 1, cutoff = 6000, rq = 0.5,
|
||||
attack = 0.001, decay = 0.04, sustain = 0.0, release = 0.6,
|
||||
drive = 1.2, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
```
|
||||
|
||||
This way the SynthDef is a drop-in replacement in `~melodyInst`, `~kickInst`, etc.
|
||||
|
||||
## Template
|
||||
|
||||
```supercollider
|
||||
SynthDef(\<instName>, {
|
||||
arg freq = 220, gate = 1, cutoff = 6000, rq = 0.5,
|
||||
attack = 0.001, decay = 0.04, sustain = 0.0, release = 0.6,
|
||||
drive = 1.2, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck;
|
||||
|
||||
// --- 1. Synthesis core (oscillator / noise / sample / ...) -------
|
||||
sig = ...;
|
||||
|
||||
// --- 2. Filter (LPF/RLPF/HPF/...) --------------------------------
|
||||
sig = LPF.ar(sig, freq.clip(40, 18000));
|
||||
|
||||
// --- 3. Drive / saturation (preserve gain) -----------------------
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
|
||||
// --- 4. Leak DC if any feedback / waveshaping --------------------
|
||||
sig = LeakDC.ar(sig);
|
||||
|
||||
// --- 5. Envelope with doneAction:2 (free node when env ends) ----
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release),
|
||||
gate, doneAction: 2);
|
||||
|
||||
// --- 6. Sidechain duck (kick -> instrument) ---------------------
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
|
||||
// --- 7. Output : Pan2 stereo ------------------------------------
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
```
|
||||
|
||||
## Mandatory invariants
|
||||
|
||||
| Rule | Reason |
|
||||
| --- | --- |
|
||||
| `doneAction: 2` on EnvGen.kr | Without it, Synth zombies pile up forever |
|
||||
| `Pan2.ar(sig, pan)` | Mono `[sig, sig]` breaks the mixer's stereo bus |
|
||||
| `freq.clip(min, max)` | Unclamped freq -> NaN/Inf at filter |
|
||||
| `(sig * drive).tanh / drive.sqrt` | Preserves perceived loudness across drive |
|
||||
| `LeakDC.ar` after feedback | Comb/Karplus need it or DC offset accumulates |
|
||||
| `In.kr(scBus, 1) * scAmt` | Standard sidechain bus pattern |
|
||||
| Defaults on EVERY arg | Pdef breaks if any arg is missing |
|
||||
|
||||
## Synthesis recipes
|
||||
|
||||
```supercollider
|
||||
// Karplus-Strong (plucked string)
|
||||
exciter = WhiteNoise.ar(0.6) * EnvGen.kr(Env.perc(0.0005, 0.003));
|
||||
sig = LeakDC.ar(CombC.ar(exciter, 0.05, freq.reciprocal, 3.0));
|
||||
|
||||
// FM bell
|
||||
mod = SinOsc.ar(freq * 1.4) * 200 * EnvGen.kr(Env.perc(0.001, 0.5));
|
||||
sig = SinOsc.ar(freq + mod);
|
||||
|
||||
// Granular pad
|
||||
sig = GrainSin.ar(2, Impulse.kr(20), 0.1, freq, pan);
|
||||
|
||||
// Formant vowel
|
||||
sig = Formant.ar(freq, formantFreq, bw);
|
||||
```
|
||||
|
||||
## After creation
|
||||
|
||||
1. Run `validating-scd-files` on the synthdefs file (P:0 B:0, TLB:1).
|
||||
2. Test SynthDef compilation : `tests/e2e_04_synthdef_compile.scd` should
|
||||
still pass.
|
||||
3. Add the new symbol to the README's instrument list if user-facing.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- **No `doneAction: 2`** -> Synth zombies, RAM leak, eventual crash.
|
||||
- **`Out.ar(0, sig)`** -> mono, breaks panning + stereo mixer.
|
||||
- **Hardcoded `0.5` for amp** -> not user-controllable.
|
||||
- **Missing default value for an arg** -> Pdef crashes when scheduling.
|
||||
- **Duplicating an existing SynthDef name** -> silently overwrites.
|
||||
- **`SinOsc.ar(freq)` without clip** -> NaN if freq <= 0 from a modulator.
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: generating-live-wrappers
|
||||
description: Use when the user asks to "add a live wrapper", "expose dict X to live API", "ajouter une API live", or creates a new dict catalogue (`~newDict = ()`) that needs a live entry. Generates the dual API pattern used across the 5 sound_algo namespaces (`~kk`, `~mm`, `~ff`, `~cc`, `~p`): a dict for catalogue access AND env-direct wrappers for actual calls. Pseudo-method `~dict.key.(args)` is broken in SC (Event passes ~dict as 1st arg, real args lost — empirical bug on SC 3.14.1, see `live/melodies.scd`). Without env-direct wrappers, the live API is unusable.
|
||||
---
|
||||
|
||||
# Generating live wrappers
|
||||
|
||||
## The problem this solves
|
||||
|
||||
```supercollider
|
||||
// FAUX -- args lost, ~m passed as 1st arg
|
||||
~m.short.(50)
|
||||
|
||||
// OK
|
||||
~m[\short].(50) // bracket notation
|
||||
~mShort.(50) // env-direct wrapper (PREFERRED)
|
||||
~mm.(50) // short alias
|
||||
```
|
||||
|
||||
Toute API live exposée via dict DOIT avoir des wrappers env directs, sinon
|
||||
les utilisateurs se retrouvent à taper de la bracket-notation lourdingue.
|
||||
|
||||
## Reserved-name collisions
|
||||
|
||||
Ces clefs explosent silencieusement à cause de méthodes Object/Server :
|
||||
|
||||
| Réservé | Renommer en |
|
||||
| --- | --- |
|
||||
| `.s` | `.short` |
|
||||
| `.l` | `.long` |
|
||||
| `.x` | `.xlong` |
|
||||
| `.e` | `.epic` |
|
||||
| `.r` | `.rnd` |
|
||||
| `.p` | `.pat` |
|
||||
| `.t` | `.tim` |
|
||||
| `.next` | `.nx` |
|
||||
| `.prev` | `.pv` |
|
||||
| `.send` | `.snd` |
|
||||
| `.set` | `.st` |
|
||||
| `.tap` | `.tp` |
|
||||
| `.value` | (interdit -- méthode Function) |
|
||||
|
||||
## Template (1 dict + N wrappers)
|
||||
|
||||
```supercollider
|
||||
(
|
||||
// --- Dict catalogue ----------------------------------------------
|
||||
~<dict> = (
|
||||
\<key1>: { |arg1, arg2| /* impl */ },
|
||||
\<key2>: { |arg1| /* impl */ },
|
||||
\list: { ~<dict>.keys.asArray.sort.do(_.postln) }
|
||||
);
|
||||
|
||||
// --- Env-direct wrappers (API utilisateur primaire) -------------
|
||||
~<dictPrefix><Key1> = { |arg1, arg2| ~<dict>[\<key1>].(arg1, arg2) };
|
||||
~<dictPrefix><Key2> = { |arg1| ~<dict>[\<key2>].(arg1) };
|
||||
~<dictPrefix>List = { ~<dict>[\list].() };
|
||||
|
||||
// --- Alias court (optionnel) -------------------------------------
|
||||
~<short> = ~<dictPrefix><Key1>; // ~mm = ~mShort, ~kk = ~kkTechno
|
||||
|
||||
"[OK] <dictPrefix> API ready".postln;
|
||||
)
|
||||
```
|
||||
|
||||
## Naming conventions
|
||||
|
||||
- **Dict** : `~<2-letter-name>` ou `~<short-word>` (ex: `~m`, `~kk`, `~ff`, `~ch`, `~p`)
|
||||
- **Wrapper prefix** : same letters + Capitalized key (ex: `~mShort`, `~kkTechno`, `~fxDrop`, `~chIntro`, `~pHat`)
|
||||
- **Short alias** : single 2-letter env var (ex: `~mm`, `~kk`, `~ff`, `~cc`)
|
||||
|
||||
## Mandatory invariants
|
||||
|
||||
| Rule | Why |
|
||||
| --- | --- |
|
||||
| Dict + env-direct wrappers (both) | Pseudo-method broken |
|
||||
| Dict keys avoid reserved names | Crashes silently otherwise |
|
||||
| Wrappers call `~dict[\key].()` not `~dict.key.()` | Same trap |
|
||||
| Print `[OK] <name> API ready` at end | User sees confirmation |
|
||||
| Wrapped in `(...)` single block | `.load` compatibility |
|
||||
| Comment in French at top | Project convention |
|
||||
|
||||
## Concrete example (extracted from `live/melodies.scd`)
|
||||
|
||||
```supercollider
|
||||
(
|
||||
~m = (
|
||||
\short: { |n| (~useMelody !? { ~useMelody.(("m"++n).asSymbol) }) ? nil },
|
||||
\long: { |n| (~useMelody !? { ~useMelody.(("ml"++n).asSymbol) }) ? nil },
|
||||
\rnd: { ~useMelodyRandom.value },
|
||||
\nx: { ~melodyNext.value },
|
||||
\pv: { ~melodyPrev.value }
|
||||
);
|
||||
~mShort = { |n| ~m[\short].(n) };
|
||||
~mLong = { |n| ~m[\long].(n) };
|
||||
~mRnd = { ~m[\rnd].() };
|
||||
~mNx = { ~m[\nx].() };
|
||||
~mPv = { ~m[\pv].() };
|
||||
~mm = ~mShort; // alias court
|
||||
"[OK] melody API ready".postln;
|
||||
)
|
||||
```
|
||||
|
||||
## After generation
|
||||
|
||||
1. Run `validating-scd-files` on the host file (P:0 B:0, TLB depends on file).
|
||||
2. Add an example block in `01_live.scd` so users can discover the API.
|
||||
3. Document the 5-namespace mapping at top of `live/CLAUDE.md` if a new
|
||||
namespace is introduced.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- **Dict only, no env-direct wrappers** : forces users into bracket notation,
|
||||
breaks the `01_live.scd` cheat-sheet pattern.
|
||||
- **Wrapper using `~dict.key.()`** : same bug it was meant to fix.
|
||||
- **Reserved-name keys** : `.set`, `.send`, `.tap`, `.value`, `.s`, `.l`, ...
|
||||
- **No `.list` key** : users can't discover available keys.
|
||||
- **No `[OK] ... ready` log** : user can't tell if SETUP succeeded.
|
||||
- **Wrapper that mutates global state without `~reload.value`** : Pdef stale.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
name: registering-jump-section
|
||||
description: Use when the user asks to "register a section", "add a jump target", "make section X jumpable", or after `scaffolding-track` finishes. Adds `~sections[\<LETTER>][\<slug>] = { ... }` to `control/jump.scd` so `~jumpTo.(\<LETTER>, \<slug>)` works during live play. The slug must match the timestamp log line in the track Routine. Without this skill, sections written in tracks are NOT jumpable from `01_live.scd` block [8].
|
||||
---
|
||||
|
||||
# Registering a jump section
|
||||
|
||||
## Why this skill exists
|
||||
|
||||
`control/jump.scd` is a 2225-line append-only file that mirrors every section
|
||||
of every track A-W. Each section is registered as a closure :
|
||||
|
||||
```supercollider
|
||||
~sections[\A] = (
|
||||
\minimal_kick_t5_sub_melody_pad: {
|
||||
~bpm = 124; ~kickFreq = 42; ~melodyInst = \pad;
|
||||
~melodyNotes = [60,0,0,0, ...];
|
||||
},
|
||||
\acid_rave_kick_t1_melody_lead_variations: {
|
||||
~bpm = 132; ~melodyInst = \lead; ~acidCutoff = 800;
|
||||
// ...
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
`~jumpTo.(\A, \acid_rave_kick_t1_melody_lead_variations)` then :
|
||||
|
||||
1. Stops `~track` and any pending Routines (`~filterSweep`, `~melodyEvolve`, ...)
|
||||
2. Calls the closure (mutates `~xxx` vars)
|
||||
3. Calls `~reload.value`
|
||||
4. Replays the 8 standard Pdef
|
||||
|
||||
## Inputs to gather
|
||||
|
||||
1. **Track letter** : `\A` to `\W`.
|
||||
2. **Section slug** : derived from the track's `.postln` log. Convert `"[A 2:00] acid rave kick t1 melody lead variations..."` to `\acid_rave_kick_t1_melody_lead_variations` (lowercase, underscores, no leading article).
|
||||
3. **Mutation block** : the body of the section in the track Routine, **without** `TempoClock.default.tempo`, `~reload.value`, `Pdef.play` (the `~jumpTo` helper does those).
|
||||
|
||||
## Slug derivation rules
|
||||
|
||||
- Take the description after `[<L> M:SS] ` and before `...`.
|
||||
- Lowercase everything.
|
||||
- Replace spaces and punctuation with `_`.
|
||||
- Strip leading articles ("the ", "le ", "la ").
|
||||
- Collapse multiple underscores.
|
||||
|
||||
Examples :
|
||||
|
||||
| Log line | Slug |
|
||||
| --- | --- |
|
||||
| `[A 0:00] minimal -- kick T5 sub + melody PAD...` | `\minimal_kick_t5_sub_melody_pad` |
|
||||
| `[E 3:30] DROP 1 -- growl dubstep + sub kick...` | `\drop_1_growl_dubstep_sub_kick` |
|
||||
| `[F 2:00] uplifter 138 BPM...` | `\uplifter_138_bpm` |
|
||||
|
||||
## Insertion
|
||||
|
||||
Append to the existing `~sections[\<L>]` entry in `control/jump.scd`. If
|
||||
`~sections[\<L>]` doesn't exist yet, create it (alphabetical order with
|
||||
existing tracks).
|
||||
|
||||
```supercollider
|
||||
~sections[\<L>][\<slug>] = {
|
||||
~bpm = <N>;
|
||||
// ... mutations from the track section, sans TempoClock/Pdef/reload
|
||||
};
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
After insertion :
|
||||
|
||||
1. Run `validating-scd-files` skill on `control/jump.scd` (P:0 B:0, TLB:1).
|
||||
2. Test in SC : `~jumpTo.(\<L>, \<slug>)` should print `[JUMP] [<L> <slug>]`
|
||||
and audibly switch the section.
|
||||
3. Add a check in `tests/e2e_07_jump.scd` if the section is critical.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- **Slug mismatch with track log** : silent jump lookup failure (just prints
|
||||
`!! [<L> <slug>] inexistante`).
|
||||
- **Including `~reload.value` in the closure** : called twice = potential
|
||||
Pdef glitch.
|
||||
- **Including `Pdef(...).play` in the closure** : `~jumpTo` already does it.
|
||||
- **Calling `TempoClock.default.tempo` in the closure** : `~jumpTo` derives
|
||||
it from `~bpm` if you set `~bpm`.
|
||||
- **Forgetting to stop a custom Routine** : add it to `~jumpTo`'s stop list
|
||||
if your section spawns its own (`~filterSweep`, `~melodyEvolve`, etc.).
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: scaffolding-track
|
||||
description: Use when the user asks to "create a new track", "ajouter une track", "scaffolder une track X", or names a new track letter (A-W are taken, so X/Y/Z or beyond, OR overwriting an existing letter). Generates `tracks/<LETTER>_<slug>.scd` following the strict 23-track convention used in sound_algo: header banner, `~track !? { ~track.stop }` guard, `Routine` with timed sections, `~bpm`/`~kickFreq`/`~melodyInst`/`~melodyNotes` mutations, `TempoClock.default.tempo = ~bpm/60`, `~reload.value`, Pdef list `[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]`, section logs `[L M:SS] description`, and `.wait` between sections. Forgetting any of these breaks live performance — this skill enforces them.
|
||||
---
|
||||
|
||||
# Scaffolding a new track
|
||||
|
||||
## Inputs to gather
|
||||
|
||||
Ask the user (or infer from context):
|
||||
|
||||
1. **Letter** : single uppercase letter. A-W are taken; default to next free letter (X, Y, ...).
|
||||
2. **Slug** : short snake_case name (`acid_journey`, `dub_techno`, `phonk`).
|
||||
3. **Sections** : list of `(timestamp, name, BPM, vibe)` tuples. Minimum 3 sections (intro, drop, outro).
|
||||
4. **Total duration** : sum of section waits. Typical track = 5-10 minutes.
|
||||
5. **Style** : melody instrument (\pad/\lead/\saw3/\rhodes/\koto/...), kick timbre, scale.
|
||||
|
||||
## Template
|
||||
|
||||
```supercollider
|
||||
// =====================================================================
|
||||
// <LETTER>_<slug>.scd
|
||||
// Track autonome -- Cmd+Entree sur le bloc (...) pour la lancer.
|
||||
// PREREQUIS : engine.scd evalue (les SynthDef + helpers doivent exister).
|
||||
// =====================================================================
|
||||
|
||||
// --- TRACK <LETTER> : "<TITLE>" <DURATION> minutes -------------------
|
||||
// 0:00 <s1> -> M:SS <s2> -> M:SS <s3> -> ... -> M:SS outro
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[<LETTER> 0:00] <section 1 description>...".postln;
|
||||
~bpm = <BPM1>;
|
||||
~kickFreq = 42; ~kickPitchAmt = 2.0; ~kickDecay = 0.5;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.08; ~melodyAmp = 0.14;
|
||||
~melodyInst = \<inst1>;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 1500;
|
||||
~melodyNotes = [60,0,0,0, 0,0,0,0, 67,0,0,0, 0,0,0,0,
|
||||
60,0,0,0, 0,0,0,0, 65,0,0,0, 0,0,0,0];
|
||||
TempoClock.default.tempo = ~bpm/60;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
<WAIT1>.wait;
|
||||
|
||||
"[<LETTER> M:SS] <section 2 description>...".postln;
|
||||
~bpm = <BPM2>;
|
||||
// ...mutations...
|
||||
TempoClock.default.tempo = ~bpm/60;
|
||||
~reload.value;
|
||||
<WAIT2>.wait;
|
||||
|
||||
// ... more sections ...
|
||||
|
||||
"[<LETTER> END] outro".postln;
|
||||
~masterFadeOut.(8);
|
||||
}).play;
|
||||
)
|
||||
```
|
||||
|
||||
## Mandatory invariants
|
||||
|
||||
- `~track !? { ~track.stop }` BEFORE creating the new Routine. Without this, multiple Routines stack up.
|
||||
- `~reload.value` after **every** mutation of `~xxx` parameters that feed Pdef.
|
||||
- `TempoClock.default.tempo = ~bpm/60` whenever `~bpm` changes.
|
||||
- One `.postln` log per section, format `"[<L> M:SS] <description>..."` -- this is parsed by tooling.
|
||||
- `.wait` after each section (in seconds) -- sum should match total duration.
|
||||
- Final `~masterFadeOut.(N)` (or stop Pdef explicitly) to avoid hanging Pdef.
|
||||
|
||||
## Variations within a section
|
||||
|
||||
Standard pattern for live mutations every 2-4 seconds inside a section :
|
||||
|
||||
```supercollider
|
||||
30.do { |k|
|
||||
if (0.25.coin) { ~acidCutoff = rrand(600, 1400); ~reload.value };
|
||||
if (0.20.coin) {
|
||||
~melodyNotes = ~genMelody.(0.55,
|
||||
[~scaleMinorPent, ~scaleDorian].choose);
|
||||
~reload.value;
|
||||
};
|
||||
4.wait; // 30 * 4 = 120s = 2 minutes
|
||||
};
|
||||
```
|
||||
|
||||
## After scaffolding
|
||||
|
||||
1. Run `validating-scd-files` skill on the new file (P:0 B:0, TLB:N OK for tracks).
|
||||
2. Optionally use `registering-jump-section` skill to expose sections via `~jumpTo.(\<L>, \<slug>)`.
|
||||
3. Add the track to `tests/e2e_09_tracks.scd` parse list.
|
||||
|
||||
## Anti-patterns to avoid
|
||||
|
||||
- **Hardcoded path** : never write absolute paths, use `~base`.
|
||||
- **Section without log** : silent debug nightmare during live.
|
||||
- **Total duration > 10 min without transition** : auditory fatigue.
|
||||
- **Mutations without `~reload.value`** : Pdef stays stale, audible disconnect.
|
||||
- **Reusing an A-W letter** : will overwrite an existing track.
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: validating-scd-files
|
||||
description: Use when editing or creating any `.scd` file in the sound_algo project. Verifies that parentheses and square brackets are balanced (the project hard-requires P:0 B:0) and, for files loaded via `.load` (00_load.scd, live/_load.scd, palette/*/index.scd, engine.scd, palette/scales.scd), that there is exactly one top-level `(...)` block (TLB:1). The CLAUDE.md mandates this check after every modification — sclang gives parse errors at runtime that are far harder to diagnose than a quick awk balance.
|
||||
---
|
||||
|
||||
# Validating `.scd` files
|
||||
|
||||
## When to run
|
||||
|
||||
Run after every edit to a `.scd` file. Mandatory before claiming a task is done.
|
||||
|
||||
## Quick check (one file)
|
||||
|
||||
```bash
|
||||
awk '
|
||||
{
|
||||
for (i = 1; i <= length($0); i++) {
|
||||
c = substr($0, i, 1)
|
||||
if (c == "(") p++; else if (c == ")") p--
|
||||
if (c == "[") b++; else if (c == "]") b--
|
||||
# detect top-level "(" at column 1
|
||||
if (i == 1 && c == "(") tlb++
|
||||
}
|
||||
}
|
||||
END { printf "P:%d B:%d TLB:%d\n", p, b, tlb }
|
||||
' path/to/file.scd
|
||||
```
|
||||
|
||||
Acceptance :
|
||||
|
||||
- `P:0 B:0` for **all** `.scd` files
|
||||
- `TLB:1` **only for files loaded via `.load`** (entry-point files). Multi-block files (tracks/*.scd, examples/*.scd, 01_live.scd) are IDE-only and `TLB:N` is fine there.
|
||||
|
||||
## Files that MUST have TLB:1
|
||||
|
||||
| File | Reason |
|
||||
| --- | --- |
|
||||
| `engine.scd` | Loaded via `00_load.scd` |
|
||||
| `palette/scales.scd` | Same |
|
||||
| `palette/melodies/index.scd` | Same |
|
||||
| `palette/harmonics/index.scd` | Same |
|
||||
| `palette/rhythm/fills.scd` | Same |
|
||||
| `live/_load.scd` | Loaded by `01_live.scd` block [0] |
|
||||
| Any other file referenced by `.load(...)` |
|
||||
|
||||
## Files where TLB:N is OK
|
||||
|
||||
- `tracks/*.scd` (Cmd+Entree per block during live play)
|
||||
- `examples/*.scd` (tutorials)
|
||||
- `01_live.scd` (live dashboard, blocks evaluated independently)
|
||||
- `live/*.scd` except `_load.scd` (SETUP + examples in same file)
|
||||
|
||||
## Whole-project sweep
|
||||
|
||||
```bash
|
||||
cd /Users/electron/Documents/Projets_Creatifs/sound_algo
|
||||
for f in $(find . -name '*.scd' -not -path './_archive/*'); do
|
||||
awk -v f="$f" '
|
||||
{ for (i=1;i<=length($0);i++) { c=substr($0,i,1)
|
||||
if (c=="(") p++; else if (c==")") p--
|
||||
if (c=="[") b++; else if (c=="]") b-- }}
|
||||
END { if (p!=0 || b!=0) printf "%s P:%d B:%d\n", f, p, b }
|
||||
' "$f"
|
||||
done
|
||||
```
|
||||
|
||||
Output should be empty. Any line printed = file with unbalanced parens/brackets.
|
||||
|
||||
## What this skill does NOT check
|
||||
|
||||
- Semantic correctness (does the code work?) → run `tests/run_all.sh`
|
||||
- SynthDef compilation → `e2e_04_synthdef_compile.scd`
|
||||
- Pdef behavior → `e2e_03_reload_guards.scd`
|
||||
- Notation pseudo-method `~dict.key.()` traps → see `live/CLAUDE.md`
|
||||
|
||||
This skill is **purely lexical**. Pass = parser will at least try to compile.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Archives historiques (exclues du repo)
|
||||
_archive/
|
||||
|
||||
# Caches
|
||||
.ruff_cache/
|
||||
.claude/cache/
|
||||
|
||||
# Logs de tests
|
||||
tests/.logs/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
._*
|
||||
|
||||
# Editeurs
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# SuperCollider artefacts
|
||||
*.scsyndef
|
||||
*.scd~
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
// =====================================================================
|
||||
// 00_load.scd -- Loader / index du projet
|
||||
//
|
||||
// STRUCTURE
|
||||
//
|
||||
// setup.scd Verification + init complete
|
||||
// (~check / ~setupAll / ~setupLive /
|
||||
// ~ensureLive / ~teardown)
|
||||
// engine.scd Moteur (SynthDef base + Pdef + sidechain bus)
|
||||
// synthdefs/
|
||||
// asia.scd Koto, erhu, pipa, gong, growl, reeseHard
|
||||
// extra.scd Lead/pad/bass/world (12 synths)
|
||||
// authentic.scd 14 instruments authentiques (gabber, reese, supersaw...)
|
||||
// palette/
|
||||
// scales.scd Scales (mineur/dorian/.../hijaz/vietnam) +
|
||||
// helpers genMelody/mutate/octavate/transpose/
|
||||
// retrograde/densify/sparsify/jitter/
|
||||
// genAcidNotes/Accents/Slides/genKickPattern/
|
||||
// randomTweak (SOURCE UNIQUE)
|
||||
// melodies/ MODULE melodies (loader = melodies/index.scd)
|
||||
// helpers.scd stretch/chain/mirror/sequenceUp/callResponse/...
|
||||
// short.scd ~m1..~m78 (32 pas)
|
||||
// long.scd ~ml1..~ml30 (64 pas)
|
||||
// xlong.scd ~mxl1..~mxl15(96 pas)
|
||||
// epic.scd ~mepic1..~mepic10 (128 pas)
|
||||
// bank.scd ~melodyBank par genre + selecteurs
|
||||
// tracks.scd multi-pistes melodiques (~melTrackAdd/On/...)
|
||||
// harmonics/ MODULE harmonie (loader = harmonics/index.scd)
|
||||
// helpers.scd genThirdHarmony / genFifthHarmony / genCounter / ...
|
||||
// presets.scd ~enableHarmony.(\preset) -- 10 presets (SOURCE UNIQUE)
|
||||
// rhythm/ MODULE rythmes / kicks / percussions
|
||||
// kicks.scd 25 patterns + 12 timbres kick (~kK1..~kK25)
|
||||
// percussions.scd ~25 patterns clap/perc + selecteur ~percInst
|
||||
// drum_kits.scd 21 kits complets
|
||||
// patterns_genre.scd 40 patterns rythmiques signature par genre
|
||||
// sequences.scd Macros de sequences (~seqIntro/Buildup/Drop...)
|
||||
// fills.scd Snare fill / tom fill
|
||||
// timbres.scd 26 timbres melodie (L1-L26)
|
||||
// styles.scd 5 styles complets (Acid Rave, Dub, Hard...)
|
||||
// chords_progressions.scd ~35 progressions d'accords (auto + ~progXxx)
|
||||
// fx.scd Riser/sweep/impact/crash/vinyl
|
||||
// fx_genre.scd Combos FX prets a l'emploi par genre
|
||||
// tweaks_template.scd Templates de tweaks par genre
|
||||
// live/
|
||||
// _load.scd Mini-loader API live (charge les 5 wrappers)
|
||||
// kicks.scd WRAPPER ~k / ~kk -- combos kick (pattern+timbre)
|
||||
// melodies.scd WRAPPER ~m / ~mm -- short/long/xlong/epic + harmonie
|
||||
// fx.scd WRAPPER ~fx / ~ff -- presets / drop / VCF / LFO
|
||||
// chains.scd WRAPPER ~ch / ~cc -- intro/drop/breakdown/loops
|
||||
// patterns.scd WRAPPER ~p -- kits + presets de genre rythmiques
|
||||
// live.scd Boite a outils live (LFO, VCF, drops, tricks)
|
||||
// mixer.scd Faders / mute / solo par voie + master
|
||||
// loops.scd Gestionnaire de boucles / pistes (live)
|
||||
// fx_bus.scd 9 bus FX reverb/delay/chorus/... + presets
|
||||
// live_fx_panel.scd PANNEAU FX LIVE tout-en-un (Cmd+Entree par bloc)
|
||||
// scenes.scd Save / recall etat global (snapshot)
|
||||
// tweaks.scd Tweaks live (cutoff, drive, mute, sidechain...)
|
||||
// control/
|
||||
// midi.scd Mapping controller MIDI (CC + notes)
|
||||
// playlist.scd 11 playlists prefefinies + auto-fade
|
||||
// jump.scd Lance n'importe quelle section de track directement
|
||||
// tracks/
|
||||
// A_acid_journey.scd ... W_dub_techno.scd (23 tracks A->W)
|
||||
// examples/ Mini-tutoriels Cmd+Entree pas-a-pas (16 fichiers)
|
||||
// 00_index.scd Catalogue + parcours recommande
|
||||
// 01_quickstart.scd Premier "Hello, sound_algo"
|
||||
// 02_first_track.scd Lancer une track autonome
|
||||
// ... voir examples/00_index.scd
|
||||
//
|
||||
// WORKFLOW
|
||||
// 1. Cmd+Entree sur "CHARGER TOUT" -> tout est charge automatiquement
|
||||
// (engine + synthdefs + scales + melodies + harmonics + setup
|
||||
// helpers + boot serveur + live/* + rhythm/fills + sequences +
|
||||
// jump). Le bloc affiche un ~check.() final pour voir l'etat.
|
||||
// 2. Lance une track (tracks/*.scd) ou les Pdef (PLAY VIDE / PLAY KICK
|
||||
// / PLAY DEFAULT plus bas dans ce fichier).
|
||||
// 3. Cmd+Entree sur ( ~check.() ) a tout moment pour voir l'etat.
|
||||
// 4. ( ~teardown.() ) pour stopper et liberer proprement.
|
||||
//
|
||||
// Pour decouvrir le projet : ouvre examples/00_index.scd et suis le
|
||||
// parcours pas-a-pas.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// --- BASE PATH (set ~base sans rien charger -- optionnel) ------------
|
||||
// Utile si tu veux juste set le chemin avant de Cmd+Entree sur un
|
||||
// autre bloc. CHARGER TOUT et CHARGER MINIMAL le font deja.
|
||||
(
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
"~base = ".post; ~base.postln;
|
||||
)
|
||||
|
||||
|
||||
// --- CHARGER TOUT (charge TOUT en un seul Cmd+Entree) ----------------
|
||||
// engine + synthdefs + scales + melodies + harmonics + setup helpers,
|
||||
// puis ~setupAll.() qui charge fx_bus + live + mixer + scenes + loops
|
||||
// + fills + sequences + jump apres boot serveur, puis ~check.() final.
|
||||
//
|
||||
// Ce bloc est AUTONOME : pas besoin d'evaluer BASE PATH avant.
|
||||
(
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
(~base ++ "engine.scd").load;
|
||||
(~base ++ "synthdefs/asia.scd").load;
|
||||
(~base ++ "synthdefs/extra.scd").load;
|
||||
(~base ++ "synthdefs/authentic.scd").load;
|
||||
(~base ++ "palette/scales.scd").load;
|
||||
(~base ++ "palette/melodies/index.scd").load;
|
||||
(~base ++ "palette/harmonics/index.scd").load;
|
||||
(~base ++ "setup.scd").load; // ~check / ~setupAll / ~setupLive / ~teardown
|
||||
~setupAll.(); // boot serveur + tous les SETUP modules + ~check
|
||||
(~base ++ "live/_load.scd").load; // wrappers API live : ~kk / ~mm / ~ff / ~cc / ~p
|
||||
)
|
||||
|
||||
|
||||
// --- CHARGER MINIMAL (engine + synthdefs + scales seulement) ---------
|
||||
// Pour debugger ou demarrer sans live/mixer/fx. Pas de boot serveur
|
||||
// automatique, pas de helpers ~check / ~setupAll.
|
||||
(
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
(~base ++ "engine.scd").load;
|
||||
(~base ++ "synthdefs/asia.scd").load;
|
||||
(~base ++ "synthdefs/extra.scd").load;
|
||||
(~base ++ "synthdefs/authentic.scd").load;
|
||||
(~base ++ "palette/scales.scd").load;
|
||||
)
|
||||
|
||||
|
||||
// --- CHARGER ENGINE SEUL (minimum vital) -----------------------------
|
||||
(
|
||||
(~base ++ "engine.scd").load;
|
||||
)
|
||||
|
||||
|
||||
// --- CHARGER PALETTE ASIA (koto/erhu/pipa/gong/growl/reeseHard) -----
|
||||
(
|
||||
(~base ++ "synthdefs/asia.scd").load;
|
||||
)
|
||||
|
||||
|
||||
// --- CHARGER PALETTE EXTRA (12 leads/pads/bass/world) ----------------
|
||||
(
|
||||
(~base ++ "synthdefs/extra.scd").load;
|
||||
)
|
||||
|
||||
|
||||
// --- CHARGER PALETTE AUTHENTIC (14 instruments authentiques) ---------
|
||||
(
|
||||
(~base ++ "synthdefs/authentic.scd").load;
|
||||
)
|
||||
|
||||
|
||||
// --- OUVRIR FICHIERS dans l'IDE -------------------------------------
|
||||
// Plusieurs blocs cibles : choisis celui dont tu as besoin (Cmd+Entree).
|
||||
// NB : les fichiers charges via CHARGER TOUT (engine, synthdefs, scales,
|
||||
// melodies/, harmonics/, rhythm/fills) ne sont PAS proposes ici --
|
||||
// leur contenu est interne et tu n'as pas a les editer en live.
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// --- OUVRIR ESSENTIEL LIVE (outils performance + entree examples) ----
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo" };
|
||||
[
|
||||
"setup.scd", // ~check / ~setupAll / ~teardown
|
||||
"live/tweaks.scd", // tweaks live (cutoff/drive/mute/SC)
|
||||
"live/live_fx_panel.scd", // PANNEAU FX tout-en-un
|
||||
"live/mixer.scd", // faders / mute / solo / master
|
||||
"live/scenes.scd", // save / recall snapshots
|
||||
"palette/rhythm/fills.scd", // ~snareFill / ~tomFill
|
||||
"control/jump.scd", // sauter dans une section
|
||||
"examples/00_index.scd", // catalogue tutoriels
|
||||
].do { |p| Document.open(root +/+ p) };
|
||||
)
|
||||
|
||||
|
||||
// --- OUVRIR OUTILS LIVE AVANCES (LFO/VCF/loops/FX bus/MIDI) ----------
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo" };
|
||||
[
|
||||
"live/live.scd", // LFO / VCF / drops / tricks
|
||||
"live/loops.scd", // gestionnaire de boucles
|
||||
"live/fx_bus.scd", // 9 bus FX + presets + tap tempo
|
||||
"control/midi.scd", // mapping MIDI controller
|
||||
"control/playlist.scd", // playlists auto-fade
|
||||
].do { |p| Document.open(root +/+ p) };
|
||||
)
|
||||
|
||||
|
||||
// --- OUVRIR PALETTES PRESETS (Cmd+Entree sur un preset) --------------
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo" };
|
||||
[
|
||||
"palette/styles.scd",
|
||||
"palette/timbres.scd",
|
||||
"palette/chords_progressions.scd",
|
||||
"palette/fx_genre.scd",
|
||||
"palette/tweaks_template.scd",
|
||||
"palette/rhythm/kicks.scd",
|
||||
"palette/rhythm/percussions.scd",
|
||||
"palette/rhythm/drum_kits.scd",
|
||||
"palette/rhythm/patterns_genre.scd",
|
||||
"palette/rhythm/sequences.scd",
|
||||
].do { |p| Document.open(root +/+ p) };
|
||||
)
|
||||
|
||||
|
||||
// --- OUVRIR TRACKS (23 tracks A->W) ----------------------------------
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo" };
|
||||
PathName(root +/+ "tracks").files
|
||||
.select { |f| f.extension == "scd" }
|
||||
.sort { |a, b| a.fileName < b.fileName }
|
||||
.do { |f| Document.open(f.fullPath) };
|
||||
)
|
||||
|
||||
|
||||
// --- OUVRIR EXAMPLES (16 tutoriels Cmd+Entree pas-a-pas) -------------
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo" };
|
||||
PathName(root +/+ "examples").files
|
||||
.select { |f| f.extension == "scd" }
|
||||
.sort { |a, b| a.fileName < b.fileName }
|
||||
.do { |f| Document.open(f.fullPath) };
|
||||
)
|
||||
|
||||
|
||||
// --- OUVRIR TOUT (ancien comportement -- ~60 onglets, lourd) ---------
|
||||
// A eviter au quotidien -- prefere les blocs cibles ci-dessus.
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo" };
|
||||
[
|
||||
"engine.scd",
|
||||
"synthdefs/asia.scd", "synthdefs/extra.scd", "synthdefs/authentic.scd",
|
||||
"palette/scales.scd",
|
||||
"palette/melodies/helpers.scd", "palette/melodies/short.scd",
|
||||
"palette/melodies/long.scd", "palette/melodies/xlong.scd",
|
||||
"palette/melodies/epic.scd", "palette/melodies/bank.scd",
|
||||
"palette/melodies/tracks.scd",
|
||||
"palette/harmonics/helpers.scd","palette/harmonics/presets.scd",
|
||||
"palette/rhythm/fills.scd", "palette/fx.scd",
|
||||
].do { |p| Document.open(root +/+ p) };
|
||||
)
|
||||
|
||||
|
||||
// --- PLAY VIDE -- demarre les sequencers en silence ------------------
|
||||
// Tous les patterns sont vides : tu construis au fur et a mesure.
|
||||
// Ex : ( ~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~reload.value; )
|
||||
(
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~kickSteps = (0 ! 16);
|
||||
~hatSteps = (0 ! 16);
|
||||
~snareSteps = (0 ! 16);
|
||||
~clapSteps = (0 ! 16);
|
||||
~percSteps = (0 ! 16);
|
||||
~acidNotes = (0 ! 16);
|
||||
~acidAccents = (0 ! 16);
|
||||
~acidSlides = (0 ! 16);
|
||||
~melodyNotes = (0 ! 32);
|
||||
~harmonyNotes = (0 ! 32);
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
"=== PLAY VIDE -- ajoute des steps puis ~reload.value ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- PLAY KICK -- demarre avec juste un kick 4/4 ---------------------
|
||||
// Ajoute hat/snare/melody en tweakant les ~xxxSteps puis ~reload.value
|
||||
(
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~hatSteps = (0 ! 16);
|
||||
~snareSteps = (0 ! 16);
|
||||
~clapSteps = (0 ! 16);
|
||||
~percSteps = (0 ! 16);
|
||||
~acidNotes = (0 ! 16);
|
||||
~acidAccents = (0 ! 16);
|
||||
~acidSlides = (0 ! 16);
|
||||
~melodyNotes = (0 ! 32);
|
||||
~harmonyNotes = (0 ! 32);
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
"=== PLAY KICK 4/4 ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- PLAY DEFAULT -- ancien comportement (kick + hat + snare + acid) -
|
||||
// Lance avec les patterns par defaut definis dans engine.scd
|
||||
(
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
"=== PLAY DEFAULT ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- STOP -- coupe les sequencers (garde le master limiter) ----------
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
~filterSweep !? { ~filterSweep.stop };
|
||||
~randomLoop !? { ~randomLoop.stop };
|
||||
~melodyEvolve !? { ~melodyEvolve.stop };
|
||||
~lRotate !? { ~lRotate.stop };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- ARRET TOTAL (libere bus + master) -------------------------------
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
~filterSweep !? { ~filterSweep.stop };
|
||||
~randomLoop !? { ~randomLoop.stop };
|
||||
~melodyEvolve !? { ~melodyEvolve.stop };
|
||||
~lRotate !? { ~lRotate.stop };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
~masterLim !? { ~masterLim.free; ~masterLim = nil };
|
||||
~scBus !? { ~scBus.free; ~scBus = nil };
|
||||
"=== ARRET TOTAL ===".postln;
|
||||
)
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
// =====================================================================
|
||||
// 01_live.scd -- TABLEAU DE BORD LIVE (Cmd+Entree par bloc)
|
||||
//
|
||||
// PREREQUIS :
|
||||
// 1. 00_load.scd > Cmd+Entree sur "CHARGER TOUT"
|
||||
// 2. Attends le boot serveur + ~check OK
|
||||
// 3. Reviens ici, Cmd+Entree sur n'importe quel bloc
|
||||
//
|
||||
// API LIVE (wrappers env directs ~xxx -- jamais ~dict.key.()) :
|
||||
// ~kk kicks ~kk.(\techno) ~kPat / ~kTim / ~kList
|
||||
// ~mm melodies ~mm.(50) ~mLong / ~mXlong / ~mEpic / ~mRnd / ~mGen
|
||||
// ~ff fx presets ~ff.(\dub) ~fxDrop / ~fxVcfOn / ~fxLfo / ~fxCut
|
||||
// ~cc chains ~chDrop.() ~chIntro / ~chBuildup / ~chIntro2drop
|
||||
// ~p patterns ~pKit.(\dub) ~pGenre.(\trance138) / ~pHat / ~pClap
|
||||
//
|
||||
// IMPORTANT : la notation `~dict.key.(args)` NE MARCHE PAS en SC --
|
||||
// SC passe l'event ~dict comme 1er arg et perd les vrais args (test
|
||||
// empirique sur SC 3.14.1, cf Dictionary.sc:549). De plus certaines
|
||||
// cles courtes ou collisionnant avec methodes Object/Server (s/t/p/e/l,
|
||||
// set/send/next/prev/tap...) plantent carrement.
|
||||
// Solutions : wrappers env directs (~kPat, ~mLong...) ou notation
|
||||
// indexee (~k[\pat].(\amen), ~m[\long].(15)).
|
||||
// Renommages internes : .p -> .pat, .t -> .tim, .s -> .short,
|
||||
// .l -> .long, .x -> .xlong, .e -> .epic, .r -> .rnd, .next -> .nx,
|
||||
// .prev -> .pv, .send -> .snd, .set -> .st, .tap -> .tp.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [0] CHARGEMENT COMPLET (1 seul Cmd+Entree -- engine + boot + live)
|
||||
// Auto-detecte ~base depuis le chemin de ce fichier.
|
||||
// =====================================================================
|
||||
(
|
||||
~base = if (thisProcess.nowExecutingPath.notNil) {
|
||||
thisProcess.nowExecutingPath.dirname ++ "/"
|
||||
} {
|
||||
"/Users/electron/Documents/Projets_Creatifs/sound_algo/"
|
||||
};
|
||||
(~base ++ "live/_load.scd").load;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [1] KICKS -- ~kk
|
||||
// =====================================================================
|
||||
( ~kk.(\techno); ) // 4/4 + rond
|
||||
( ~kk.(\gabber); ) // dense + distordu
|
||||
( ~kk.(\dub); ) // one-drop + sub
|
||||
( ~kk.(\dubstep); ) // half-time + 808
|
||||
( ~kk.(\trance); ) // 4/4 punchy
|
||||
( ~kk.(\hardstyle); ) // hardstyle distordu
|
||||
( ~kk.(\amen); ) // amen break
|
||||
( ~kk.(\dnb); ) // drum'n'bass
|
||||
( ~kk.(\jungle); ) // jungle rapid
|
||||
( ~kk.(\house); ) // house 4/4 + 909
|
||||
( ~kk.(\detroit); ) // detroit + 909
|
||||
( ~kk.(\phonk); ) // half-time + 808
|
||||
( ~kk.(\afro); ) // afrobeat
|
||||
( ~kk.(\garage); ) // 2-step
|
||||
( ~kk.(\triphop); ) // lazy boomy
|
||||
( ~kk.(\footwork); ) // 160 BPM triple
|
||||
( ~kk.(\minimal); ) // 1 kick / mesure
|
||||
( ~kk.(\electro); ) // electro syncope
|
||||
|
||||
// patterns / timbres seuls (variables env directes, pas ~k.pat !)
|
||||
( ~kPat.(\amen); )
|
||||
( ~kPat.(\dense); )
|
||||
( ~kPat.(\off); ) // silence kick
|
||||
( ~kTim.(\808); )
|
||||
( ~kTim.(\909); )
|
||||
( ~kTim.(\distorded); )
|
||||
( ~kList.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [2] MELODIES -- ~mm + wrappers env directs ~mXxx
|
||||
// =====================================================================
|
||||
// short (32 steps, 78 dispos)
|
||||
( ~mm.(1); ) // applique m1
|
||||
( ~mm.(50); ) // applique m50
|
||||
( ~mRnd.(); ) // random short
|
||||
|
||||
// long (64 steps, 30 dispos)
|
||||
( ~mLong.(1); )
|
||||
( ~mLong.(15); )
|
||||
( ~mRndLong.(); )
|
||||
|
||||
// xlong (96 steps, 15 dispos)
|
||||
( ~mXlong.(1); )
|
||||
( ~mRndXlong.(); )
|
||||
|
||||
// epic (128 steps, 10 dispos)
|
||||
( ~mEpic.(1); )
|
||||
( ~mRndEpic.(); )
|
||||
|
||||
// par genre
|
||||
( ~mGen.(\acid); )
|
||||
( ~mGen.(\trance); )
|
||||
( ~mGen.(\detroit); )
|
||||
( ~mGen.(\dnb); )
|
||||
( ~mGen.(\dub); )
|
||||
( ~mGen.(\oriental); )
|
||||
( ~mGen.(\synthwave); )
|
||||
( ~mGen.(\phonk); )
|
||||
|
||||
// navigation
|
||||
( ~mNx.(); ) // melodie suivante
|
||||
( ~mPv.(); ) // precedente
|
||||
|
||||
// instrument melody
|
||||
( ~mInst.(\warmPad); )
|
||||
( ~mInst.(\pluck); )
|
||||
( ~mInst.(\stab); )
|
||||
( ~mInst.(\saw3); )
|
||||
( ~mInst.(\fmBell); )
|
||||
( ~mInst.(\supersaw); )
|
||||
( ~mInst.(\rhodes); )
|
||||
( ~mInst.(\guzheng); )
|
||||
( ~mInst.(\koto); )
|
||||
( ~mInst.(\handpan); )
|
||||
|
||||
// harmonie
|
||||
( ~mHarm.(\third); ) // tierce automatique
|
||||
( ~mHarm.(\fifth); )
|
||||
( ~mHarm.(\counter); )
|
||||
( ~mHarm.(\bassline); )
|
||||
( ~mHarm.(\dubBass); )
|
||||
( ~mHarm.(\arp); )
|
||||
( ~mHarm.(\chord); )
|
||||
( ~mHarm.(\tranceLayer); )
|
||||
( ~mHarm.(\cinematic); )
|
||||
( ~mHarm.(\off); )
|
||||
|
||||
( ~mHarmInst.(\subBoom); )
|
||||
( ~mHarmInst.(\warmPad); )
|
||||
|
||||
// tweaks rapides
|
||||
( ~mAmp.(0.18); )
|
||||
( ~mCut.(2500); )
|
||||
( ~mCut.(8000); )
|
||||
( ~mDrive.(2.5); )
|
||||
( ~mOff.(); ) // melody muette
|
||||
( ~mList.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [3] FX -- ~ff + wrappers env directs ~fxXxx
|
||||
// =====================================================================
|
||||
// presets (10)
|
||||
( ~ff.(\dub); )
|
||||
( ~ff.(\space); )
|
||||
( ~ff.(\trance); )
|
||||
( ~ff.(\dubstep); )
|
||||
( ~ff.(\retro); )
|
||||
( ~ff.(\industrial); )
|
||||
( ~ff.(\dream); )
|
||||
( ~ff.(\cosmic); )
|
||||
( ~ff.(\drone); )
|
||||
( ~ff.(\dry); )
|
||||
|
||||
// sends individuels
|
||||
( ~fxSnd.(\rev, 0.4); )
|
||||
( ~fxSnd.(\dly, 0.3); )
|
||||
( ~fxSnd.(\shim, 0.5); )
|
||||
( ~fxSt.(\rev, \mix, 0.7); )
|
||||
( ~fxSt.(\dly, \delayTime, 0.5); )
|
||||
|
||||
// freeze reverb
|
||||
( ~fxFreeze.(1); )
|
||||
( ~fxFreeze.(0); )
|
||||
|
||||
// tricks scéniques
|
||||
( ~fxDrop.(); )
|
||||
( ~fxBreakdown.(8); )
|
||||
( ~fxBuildup.(8); )
|
||||
( ~fxGlitch.(2); )
|
||||
( ~fxStutter.(8, 1); )
|
||||
( ~fxFreezeR.(4); )
|
||||
( ~fxTapeStop.(2); )
|
||||
( ~fxTapeRev.(4); )
|
||||
( ~fxHandsUp.(); )
|
||||
( ~fxJumpCut.(0.5); )
|
||||
( ~fxBitCrush.(6, 6000, 1); )
|
||||
( ~fxRing.(200, 1); )
|
||||
( ~fxShift.(100, 1); )
|
||||
( ~fxGran.(2); )
|
||||
|
||||
// VCF master
|
||||
( ~fxVcfOn.(\moog, 800, 0.5); )
|
||||
( ~fxVcfOn.(\ladder, 1500, 0.7); )
|
||||
( ~fxVcfOn.(\formant, 1, 0.3); ) // voyelle 'a'
|
||||
( ~fxVcfFreq.(2000); )
|
||||
( ~fxVcfQ.(0.6); )
|
||||
( ~fxVcfSweep.(8000, 200, 8); )
|
||||
( ~fxVcfPreset.(\acid); )
|
||||
( ~fxVcfOff.(); )
|
||||
|
||||
// LFO
|
||||
( ~fxLfo.(\melodyCutoff, 0.5, 1500); )
|
||||
( ~fxLfo.(\acidAmp, 4, 0.4); )
|
||||
( ~fxLfo.(\kickAmp, 0.3, 0.3); )
|
||||
( ~fxLfoStop.(\melodyCutoff); )
|
||||
( ~fxLfoStopAll.(); )
|
||||
|
||||
// shortcuts cutoff/RQ/drive par voie
|
||||
( ~fxCut.(\mel, 5000); )
|
||||
( ~fxCut.(\acid, 1500); )
|
||||
( ~fxRq.(\mel, 0.4); )
|
||||
( ~fxDrive.(\mel, 2.0); )
|
||||
|
||||
// master comp / saturation
|
||||
( ~fxComp.(\glue); )
|
||||
( ~fxComp.(\punch); )
|
||||
( ~fxComp.(\pump); )
|
||||
( ~fxCompOff.(); )
|
||||
( ~fxSat.(\tanh, 1.5); )
|
||||
( ~fxSat.(\softclip, 1.2); )
|
||||
( ~fxSatOff.(); )
|
||||
|
||||
( ~fxList.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [4] CHAINS -- wrappers env directs ~chXxx (jamais ~cc.key.()!)
|
||||
// =====================================================================
|
||||
( ~chIntro.(); ) // sequence intro montante
|
||||
( ~chDrop.(); ) // drop sec
|
||||
( ~chBreakdown.(); )
|
||||
( ~chBuildup.(8); ) // crescendo trance 8 mesures
|
||||
( ~chOutro.(); )
|
||||
|
||||
// loops par genre
|
||||
( ~chTechno.(4); )
|
||||
( ~chAcid.(); )
|
||||
( ~chDubstep.(); )
|
||||
( ~chTrance.(); )
|
||||
( ~chDnb.(4); )
|
||||
( ~chHiphop.(8); )
|
||||
( ~chWorld.(); )
|
||||
|
||||
// combos prêts
|
||||
( ~chIntro2drop.(4, 4); ) // intro -> buildup -> drop
|
||||
( ~chDropToBreak.(8); ) // drop -> breakdown -> drop
|
||||
( ~chOutroFade.(12); ) // outro + masterFadeOut
|
||||
|
||||
// stop chain en cours
|
||||
( ~chStop.(); )
|
||||
( ~chList.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [5] PATTERNS rythmiques -- wrappers env directs ~pXxx
|
||||
// =====================================================================
|
||||
// kits complets (16 dispos)
|
||||
( ~pKit.(\techno); )
|
||||
( ~pKit.(\dubstep); )
|
||||
( ~pKit.(\dnb); )
|
||||
( ~pKit.(\trap); )
|
||||
( ~pKit.(\house); )
|
||||
( ~pKit.(\hardstyle); )
|
||||
( ~pKit.(\jungle); )
|
||||
( ~pKit.(\phonk); )
|
||||
( ~pKit.(\industrial); )
|
||||
( ~pKit.(\hardcore); )
|
||||
( ~pKit.(\detroitDeep); )
|
||||
( ~pKit.(\lofiHipHop); )
|
||||
( ~pKit.(\tribalWorld); )
|
||||
|
||||
// genres rythmiques (20 dispos)
|
||||
( ~pGenre.(\hardTechno); )
|
||||
( ~pGenre.(\acidHouse); )
|
||||
( ~pGenre.(\trance138); )
|
||||
( ~pGenre.(\psyTrance); )
|
||||
( ~pGenre.(\liquidDnB); )
|
||||
( ~pGenre.(\neurofunk); )
|
||||
( ~pGenre.(\jungle165); )
|
||||
( ~pGenre.(\futureBass); )
|
||||
( ~pGenre.(\deepHouse); )
|
||||
( ~pGenre.(\techHouse); )
|
||||
( ~pGenre.(\industrialV2); )
|
||||
( ~pGenre.(\breakcore); )
|
||||
( ~pGenre.(\footwork); )
|
||||
( ~pGenre.(\idm); )
|
||||
( ~pGenre.(\glitchHop); )
|
||||
|
||||
// elements isoles (noms reels : voir ~pList.())
|
||||
( ~pHat.(\off2); ) // offbeat 8th
|
||||
( ~pHat.(\eighth); )
|
||||
( ~pHat.(\sixteen); )
|
||||
( ~pHat.(\shuffle); )
|
||||
( ~pHat.(\off); )
|
||||
( ~pSnare.(\two4); )
|
||||
( ~pSnare.(\ghost); )
|
||||
( ~pSnare.(\roll); )
|
||||
( ~pSnare.(\off); )
|
||||
( ~pClap.(\two4); )
|
||||
( ~pClap.(\offbeat); )
|
||||
( ~pClap.(\trance); )
|
||||
( ~pClap.(\dub); )
|
||||
( ~pClap.(\off); )
|
||||
( ~pPerc.(\rim); )
|
||||
( ~pPerc.(\tom); )
|
||||
( ~pPerc.(\cowbell); )
|
||||
( ~pPerc.(\openHat); )
|
||||
( ~pPerc.(\off); )
|
||||
|
||||
( ~pList.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [6] MIXER -- ~setVol / ~mute / ~mixPreset
|
||||
// =====================================================================
|
||||
( ~setVol.(\kick, 1.0); )
|
||||
( ~setVol.(\acid, 0.7); )
|
||||
( ~setVol.(\melody, 0.5); )
|
||||
( ~masterVol.(0.5); ) // multiplicateur global
|
||||
( ~masterVol.(1.0); ) // retour normal
|
||||
( ~masterFade.(0.3, 4); ) // fade master vers 0.3 en 4s
|
||||
( ~masterFadeOut.(8); ) // fade out + stop Pdef
|
||||
|
||||
( ~mute.(\acid); )
|
||||
( ~unmute.(\acid); )
|
||||
( ~solo.(\melody); )
|
||||
( ~unsolo.(); )
|
||||
( ~mixReset.(); )
|
||||
|
||||
( ~mixPreset.(\drumsHeavy); )
|
||||
( ~mixPreset.(\melodicLead); )
|
||||
( ~mixPreset.(\acidFocus); )
|
||||
( ~mixPreset.(\breakdown); )
|
||||
( ~mixPreset.(\drop); )
|
||||
( ~mixPreset.(\dub); )
|
||||
( ~mixPreset.(\trance); )
|
||||
( ~mixPreset.(\hardcore); )
|
||||
|
||||
( ~saveMix.(\verseA); )
|
||||
( ~loadMix.(\verseA); )
|
||||
( ~mixShow.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [7] SCENES -- snapshot / recall
|
||||
// =====================================================================
|
||||
( ~saveScene.(\drop1); )
|
||||
( ~saveScene.(\verseA); )
|
||||
( ~saveScene.(\breakdown); )
|
||||
( ~loadScene.(\drop1); )
|
||||
( ~listScenes.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [8] JUMP -- ~jumpTo dans n'importe quelle section
|
||||
// =====================================================================
|
||||
( ~jumpTo.('A', 'minimal_kick_t5_sub_melody_pad'); )
|
||||
( ~jumpTo.('A', 'acid_rave_kick_t1_melody_lead_variations'); )
|
||||
( ~jumpTo.('B', 'kick_4_4_acid_ouvre_kick_t1_melody_pluck'); )
|
||||
( ~jumpTo.('E', 'drop_1_growl_dubstep'); )
|
||||
( ~jumpTo.('F', 'trance_uplifter_138_bpm'); )
|
||||
( ~jumpTo.('W', 'dub_techno_120_bpm'); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [9] STATUS / TEARDOWN
|
||||
// =====================================================================
|
||||
( ~check.(); ) // rapport detaille
|
||||
( ~teardown.(); ) // arret propre + free
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [10] PLAY -- demarrer les sequenceurs
|
||||
// =====================================================================
|
||||
(
|
||||
TempoClock.default.tempo = (~bpm ? 128) / 60;
|
||||
~kickSteps = (~kickSteps ? (1!16));
|
||||
~hatSteps = (~hatSteps ? (0!16));
|
||||
~snareSteps = (~snareSteps ? (0!16));
|
||||
~clapSteps = (~clapSteps ? (0!16));
|
||||
~percSteps = (~percSteps ? (0!16));
|
||||
~acidNotes = (~acidNotes ? (0!16));
|
||||
~melodyNotes = (~melodyNotes ? (0!32));
|
||||
~harmonyNotes = (~harmonyNotes ? (0!32));
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
"=== PLAY ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- STOP -- coupe les Pdef (garde l'engine) -------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
# sound_algo — Project Instructions
|
||||
|
||||
Live-coding SuperCollider system. Always communicate in French with the user.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Variables d'environnement `~xxx` minuscules (sinon SC parse comme CLASSNAME)
|
||||
- Fichiers `.load` doivent avoir UN SEUL bloc top-level `(...)`. Multi-blocs OK pour les fichiers ouverts manuellement dans l'IDE.
|
||||
- Code commenté en français
|
||||
- Pas d'emojis sauf demande explicite
|
||||
|
||||
## Architecture
|
||||
|
||||
Voir `README.md` pour l'arborescence et les helpers principaux.
|
||||
|
||||
## Validation
|
||||
|
||||
Après toute modification :
|
||||
|
||||
- `awk` balance des parens/brackets : doit être P:0 B:0
|
||||
- Pour les fichiers `.load`-compatibles : un seul bloc top-level (TLB:1)
|
||||
|
||||
## Live Performance Workflow
|
||||
|
||||
1. CHARGER TOUT (00_load.scd) ou bloc [0] de `01_live.scd`
|
||||
2. **Tableau de bord = `01_live.scd`** (Cmd+Entree par bloc, API ~kk/~mm/~ff/~cc/~p)
|
||||
3. Lancer une track (tracks/*.scd) ou les Pdef (bloc [10] PLAY)
|
||||
4. Tweak via `01_live.scd`, `live/tweaks.scd` ou `live/live_fx_panel.scd`
|
||||
5. Jump entre sections via `control/jump.scd`
|
||||
6. Sauvegarder l'état avec `~saveScene` (live/scenes.scd)
|
||||
|
||||
## Note sur `-> nil`
|
||||
|
||||
Chaque bloc `( ~xxx.(...); )` retourne nil (le `;` final supprime la valeur).
|
||||
Une cascade de `-> nil` = evaluation reussie de plusieurs blocs, pas un bug.
|
||||
|
||||
## Tests E2E
|
||||
|
||||
```bash
|
||||
cd tests && bash run_all.sh
|
||||
```
|
||||
@@ -0,0 +1,79 @@
|
||||
# sound_algo — SuperCollider Live Coding System
|
||||
|
||||
Generative techno/electronic live performance engine.
|
||||
90 SynthDefs, 23 playable tracks (A-W), 130+ melodies, 8-voice sequencer with sidechain, FX bus, LFO automation, mixer, loops manager.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Open `00_load.scd` in SuperCollider IDE
|
||||
2. Cmd+Enter on "CHARGER TOUT" block (boots server + loads engine)
|
||||
3. Open any `tracks/*.scd`, Cmd+Enter to launch
|
||||
4. Open `live/tweaks.scd` or `live/live_fx_panel.scd` for live tweaks
|
||||
|
||||
## Architecture
|
||||
|
||||
| Path | Contenu |
|
||||
|---|---|
|
||||
| `00_load.scd` | Loader + index (entry point) |
|
||||
| `engine.scd` | Core SynthDefs + Pdef sequencer + ~reload |
|
||||
| `synthdefs/` | Additional instruments (asia/extra/authentic) |
|
||||
| `palette/scales.scd` | Scales + melody generation helpers |
|
||||
| `palette/melodies/` | 130+ melody presets + multi-track |
|
||||
| `palette/harmonics/` | Harmony generators + ~enableHarmony |
|
||||
| `palette/rhythm/` | Kicks, percussions, drum kits, patterns, sequences, fills |
|
||||
| `palette/` | timbres, styles, fx_genre, chords_progressions, tweaks_template |
|
||||
| `live/` | live.scd, mixer.scd, loops.scd, fx_bus.scd, live_fx_panel.scd, scenes.scd, tweaks.scd |
|
||||
| `control/` | midi.scd, playlist.scd, jump.scd |
|
||||
| `tracks/` | 23 autonomous tracks (A-W) |
|
||||
| `examples/` | 16 step-by-step tutorials |
|
||||
| `tests/` | E2E test suite |
|
||||
|
||||
## Load Order
|
||||
|
||||
CHARGER TOUT charge automatiquement dans l'ordre :
|
||||
1. engine.scd
|
||||
2. synthdefs/*.scd (asia, extra, authentic)
|
||||
3. palette/scales.scd (scales + helpers melodiques)
|
||||
4. palette/melodies/index.scd (130+ melodies + multi-track)
|
||||
5. palette/harmonics/index.scd (~enableHarmony + helpers)
|
||||
6. palette/rhythm/fills.scd (snareFill, tomFill)
|
||||
|
||||
À évaluer manuellement (Cmd+Entrée bloc par bloc) :
|
||||
- live/live.scd SETUP (LFO, VCF, tricks)
|
||||
- live/mixer.scd SETUP (faders, mute, solo, master)
|
||||
- live/fx_bus.scd SETUP (FX bus, presets)
|
||||
- live/loops.scd SETUP (loops manager)
|
||||
- live/scenes.scd SETUP (snapshot/recall)
|
||||
- control/midi.scd INIT + MAPPING DEFAULT
|
||||
- control/jump.scd SETUP JUMP
|
||||
|
||||
## Key Helpers
|
||||
|
||||
| Helper | Fichier | Usage |
|
||||
|---|---|---|
|
||||
| `~reload.value` | engine.scd | Rebuild Pdef depuis ~xxx vars |
|
||||
| `~enableHarmony.(\preset)` | palette/harmonics/presets.scd | 10 presets harmonie |
|
||||
| `~genMelody.(density, scale, len)` | palette/scales.scd | Generateur melodie aleatoire |
|
||||
| `~lfoTo.(\param, rate, depth)` | live/live.scd | LFO assignable a toute var |
|
||||
| `~vcfOn.(\type, freq, q)` | live/live.scd | VCF master (8 types) |
|
||||
| `~drop`, `~breakdown`, `~buildup` | live/live.scd | Tricks sceniques |
|
||||
| `~send.(\voie, \fx, amount)` | live/fx_bus.scd | Routing audio vers FX |
|
||||
| `~fxPreset.(\preset)` | live/fx_bus.scd | 10 combos FX |
|
||||
| `~loopOn.(\name, source)` | live/loops.scd | Loop manager |
|
||||
| `~setVol/mute/solo` | live/mixer.scd | Mixer 8 voies |
|
||||
| `~useMelody.(\m50)` | palette/melodies/bank.scd | Charger melodie nommee |
|
||||
| `~melodyByGenre.(\acid)` | palette/melodies/bank.scd | Random melodie par genre |
|
||||
| `~jumpTo.(\letter, \slug)` | control/jump.scd | Saut direct dans une track |
|
||||
| `~playPlaylist.([...])` | control/playlist.scd | Playlist auto-fade |
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
cd tests && bash run_all.sh
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- SuperCollider 3.13+
|
||||
- macOS / Linux (testé sur Darwin)
|
||||
- Pas de Quarks externes requis (toute la synthèse est en UGens natifs)
|
||||
@@ -0,0 +1,55 @@
|
||||
# control/ — MIDI, jump, playlist
|
||||
|
||||
Outils de pilotage : controleur MIDI, saut direct dans une track,
|
||||
playlist auto-fade. SETUP manuel apres `00_load.scd`.
|
||||
|
||||
## Fichiers
|
||||
|
||||
| Fichier | Role |
|
||||
| --- | --- |
|
||||
| `midi.scd` | INIT MIDIClient + MAPPING DEFAULT (CC + Notes) |
|
||||
| `jump.scd` | `~jumpTo.(\X, \section_slug)` |
|
||||
| `playlist.scd` | `~playPlaylist.([...])` avec fades |
|
||||
|
||||
## Pattern SETUP
|
||||
|
||||
Chaque fichier expose un bloc SETUP (a evaluer 1x) puis des
|
||||
helpers `~xxx`. Bloc SETUP enrobe en `(...)` pour eval atomique.
|
||||
|
||||
```supercollider
|
||||
( // SETUP JUMP
|
||||
~sections = ();
|
||||
~jumpTo = { |trackLetter, sectionSlug| ... };
|
||||
"[OK] SETUP JUMP".postln;
|
||||
)
|
||||
```
|
||||
|
||||
## Jump : invariants
|
||||
|
||||
`~jumpTo` doit :
|
||||
1. Stopper toutes les Routines actives (`~track`, `~filterSweep`, ...)
|
||||
2. Appliquer la section (mute `~xxx` vars)
|
||||
3. `~reload.value` pour rebuild Pdef
|
||||
4. Relancer les Pdef principaux (`\kickSeq`, `\hatSeq`, ...)
|
||||
|
||||
Sections enregistrees par chaque track via :
|
||||
```supercollider
|
||||
~sections[\A] = (
|
||||
\intro: { ~bpm = 124; ~melodyInst = \pad; ... },
|
||||
\drop: { ~bpm = 132; ~melodyInst = \lead; ... }
|
||||
);
|
||||
```
|
||||
|
||||
## MIDI
|
||||
|
||||
- `MIDIClient.init` puis `MIDIIn.connectAll` une seule fois
|
||||
- `MIDIdef.cc(\name, { |val, num, chan, src| ... }, ccNum, chan)`
|
||||
- Toujours `MIDIdef.freeAll` avant un re-mapping pour eviter les doublons
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Ne pas evaluer SETUP plusieurs fois sans `MIDIdef.freeAll` -> CC empiles
|
||||
- Ne pas oublier de stopper les Routines dans `~jumpTo` -> superposition
|
||||
- Ne pas hardcoder un device MIDI (utiliser device index ou nom)
|
||||
- Ne pas mapper sur `~xxx` sans `~reload.value` derriere si Pdef-related
|
||||
- Ne pas appeler `~jumpTo` sur une section non enregistree (silencieux mais inutile)
|
||||
+2225
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
// =====================================================================
|
||||
// midi.scd -- Mapping MIDI controller (CC + Notes)
|
||||
//
|
||||
// Branche un controller (Launch Control, BCR2000, Midi Fighter, etc.)
|
||||
// et map les CC sur les parametres essentiels du moteur.
|
||||
//
|
||||
// USAGE :
|
||||
// 1. Cmd+Entree sur INIT MIDI (initialise + liste devices)
|
||||
// 2. Cmd+Entree sur MAPPING DEFAULT (ou copier-coller pour customiser)
|
||||
// 3. Tweak en temps reel via le controller MIDI
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- INIT MIDI -- liste les devices disponibles --------------------
|
||||
(
|
||||
MIDIClient.init;
|
||||
"=== MIDI sources disponibles ===".postln;
|
||||
MIDIClient.sources.do { |src, i|
|
||||
(" [" ++ i ++ "] " ++ src.device ++ " : " ++ src.name).postln;
|
||||
};
|
||||
"=== MIDI destinations ===".postln;
|
||||
MIDIClient.destinations.do { |dst, i|
|
||||
(" [" ++ i ++ "] " ++ dst.device ++ " : " ++ dst.name).postln;
|
||||
};
|
||||
MIDIIn.connectAll;
|
||||
"=== MIDIIn.connectAll OK ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- MAPPING DEFAULT (16 CC standard) ------------------------------
|
||||
// Adapte les numeros CC selon ton controller (ici : Launch Control XL like)
|
||||
(
|
||||
~midiFuncs !? { ~midiFuncs.do { |f| f.free } };
|
||||
~midiFuncs = List.new;
|
||||
|
||||
// Debounce ~reload pour eviter le spam (~reload reconstruit 8 Pdef !)
|
||||
~reloadPending = ~reloadPending ?? false;
|
||||
~debouncedReload = {
|
||||
if (~reloadPending.not) {
|
||||
~reloadPending = true;
|
||||
AppClock.sched(0.05, { ~reloadPending = false; ~reload.value; nil });
|
||||
};
|
||||
};
|
||||
|
||||
// CC 13-20 = potards rangée 1 (volumes par voix)
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~kickAmp = val.linlin(0,127, 0,1); ~debouncedReload.() }, 13));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~hatAmp = val.linlin(0,127, 0,0.4); ~debouncedReload.() }, 14));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~snareAmp = val.linlin(0,127, 0,0.8); ~debouncedReload.() }, 15));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~clapAmp = val.linlin(0,127, 0,0.6); ~debouncedReload.() }, 16));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~percAmp = val.linlin(0,127, 0,0.5); ~debouncedReload.() }, 17));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~acidAmp = val.linlin(0,127, 0,0.5); ~debouncedReload.() }, 18));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyAmp = val.linlin(0,127, 0,0.4); ~debouncedReload.() }, 19));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~harmonyAmp = val.linlin(0,127, 0,0.4); ~debouncedReload.() }, 20));
|
||||
|
||||
// CC 29-36 = potards rangée 2 (cutoffs / filtres)
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyCutoff = val.linexp(0,127, 100,12000); ~debouncedReload.() }, 29));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyRq = val.linlin(0,127, 0.05,0.8); ~debouncedReload.() }, 30));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~acidCutoff = val.linexp(0,127, 100,8000); ~debouncedReload.() }, 31));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~acidRq = val.linlin(0,127, 0.05,0.5); ~debouncedReload.() }, 32));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyDrive = val.linlin(0,127, 0.5,5.0); ~debouncedReload.() }, 33));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~acidDrive = val.linlin(0,127, 0.5,5.0); ~debouncedReload.() }, 34));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyBoost = val.linlin(0,127, 0.5,3.0); ~debouncedReload.() }, 35));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| TempoClock.default.tempo = val.linlin(0,127, 60,200) / 60 }, 36));
|
||||
|
||||
// CC 49-56 = potards rangée 3 (wobble / sidechain)
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyWobbleRate = val.linexp(0,127, 0.5,32); ~debouncedReload.() }, 49));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodyWobbleDepth = val.linlin(0,127, 0,4500); ~debouncedReload.() }, 50));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~melodySubAmt = val.linlin(0,127, 0,1.5); ~debouncedReload.() }, 51));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~acidScAmt = val.linlin(0,127, 0,1); ~debouncedReload.() }, 52));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~leadScAmt = val.linlin(0,127, 0,1); ~debouncedReload.() }, 53));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val| ~kickScShape = val.linlin(0,127, 0.05,0.5); ~debouncedReload.() }, 54));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val|
|
||||
~fxFx !? { ~fxFx[\rev] !? { |s| s.set(\mix, val.linlin(0,127, 0,1)) } };
|
||||
}, 55));
|
||||
~midiFuncs.add(MIDIFunc.cc({ |val|
|
||||
~fxFx !? { ~fxFx[\dly] !? { |s| s.set(\feedback, val.linlin(0,127, 0,0.95)) } };
|
||||
}, 56));
|
||||
|
||||
// NOTES MIDI : 36-51 = pads de declenchement FX / fills
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ Synth(\impact, [\freq, 40, \decay, 2, \amp, 0.6]) }, 36));
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ Synth(\riser, [\dur, 4, \startCutoff, 400, \endCutoff, 11000, \amp, 0.3]) }, 37));
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ Synth(\sweep, [\dur, 4, \startCutoff, 8000, \endCutoff, 200, \amp, 0.3]) }, 38));
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ Synth(\crash, [\decay, 3, \amp, 0.4]) }, 39));
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ Synth(\gong, [\freq, 50, \decay, 8, \amp, 0.5]) }, 40));
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ ~snareFill !? { ~snareFill.value } }, 41));
|
||||
~midiFuncs.add(MIDIFunc.noteOn({ ~tomFill !? { ~tomFill.value } }, 42));
|
||||
|
||||
// NOTES 48-59 = recall scenes (si scenes definies)
|
||||
12.do { |i|
|
||||
var name = ("scene_" ++ (i + 1)).asSymbol;
|
||||
~midiFuncs.add(MIDIFunc.noteOn({
|
||||
~loadScene !? { ~loadScene.(name) };
|
||||
}, 48 + i));
|
||||
};
|
||||
|
||||
"=== MIDI MAPPING ACTIF ===".postln;
|
||||
" CC 13-20 : volumes par voix".postln;
|
||||
" CC 29-36 : cutoffs / drive / bpm".postln;
|
||||
" CC 49-56 : wobble / sidechain / FX".postln;
|
||||
" Notes 36-42 : FX oneshot (impact/riser/sweep/crash/gong/fills)".postln;
|
||||
" Notes 48-59 : recall scene_1 a scene_12".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- DEBUG -- print tous les MIDI in entrants ----------------------
|
||||
(
|
||||
~midiDebug = MIDIFunc.cc({ |val, num, chan|
|
||||
("[CC] " ++ num ++ " = " ++ val ++ " ch" ++ chan).postln;
|
||||
});
|
||||
)
|
||||
( ~midiDebug !? { ~midiDebug.free; ~midiDebug = nil }; "MIDI debug OFF".postln; )
|
||||
|
||||
|
||||
// --- STOP MIDI (libere tous les mappings) --------------------------
|
||||
(
|
||||
~midiFuncs !? { ~midiFuncs.do { |f| f.free }; ~midiFuncs = nil };
|
||||
~midiDebug !? { ~midiDebug.free; ~midiDebug = nil };
|
||||
"=== MIDI STOPPED ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,279 @@
|
||||
// =====================================================================
|
||||
// playlist.scd -- Lance les tracks les unes apres les autres
|
||||
//
|
||||
// PREREQUIS : engine + synthdefs (charger d'abord 00_load.scd)
|
||||
// USAGE : Cmd+Entree sur une playlist (au choix), elle s'enchaine
|
||||
// automatiquement.
|
||||
// Pour stopper : evaluer le bloc STOP PLAYLIST
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- HELPER ~playPlaylist -------------------------------------------
|
||||
// trackList = [[ "filename.scd", duration_seconds ], ...]
|
||||
(
|
||||
~playPlaylist = { |trackList, fadeOut = 4|
|
||||
~playlist !? { ~playlist.stop };
|
||||
~playlist = Routine({
|
||||
var total = trackList.collect { |item| item[1] }.sum;
|
||||
("=== PLAYLIST -- " ++ trackList.size ++ " tracks, " ++
|
||||
(total / 60).round(0.1) ++ " min total ===").postln;
|
||||
trackList.do { |item, idx|
|
||||
var path = item[0]; var dur = item[1];
|
||||
("[" ++ (idx + 1) ++ "/" ++ trackList.size ++ "] " ++ path ++
|
||||
" (" ++ (dur/60).round(0.1) ++ " min)").postln;
|
||||
~fading = false;
|
||||
(~base ++ "tracks/" ++ path).load;
|
||||
(dur - fadeOut).wait;
|
||||
// FIX RACE : stopper la Routine track AVANT le fade pour qu'elle
|
||||
// n'ecrase pas les amps qu'on baisse
|
||||
~track !? { ~track.stop };
|
||||
~fading = true;
|
||||
("[fade out " ++ fadeOut ++ "s]").postln;
|
||||
(fadeOut * 4).do { |k|
|
||||
~melodyAmp = ~melodyAmp * 0.92;
|
||||
~harmonyAmp = ~harmonyAmp * 0.92;
|
||||
~kickAmp = ~kickAmp * 0.92;
|
||||
~hatAmp = ~hatAmp * 0.92;
|
||||
~snareAmp = ~snareAmp * 0.92;
|
||||
~clapAmp = ~clapAmp * 0.92;
|
||||
~percAmp = ~percAmp * 0.92;
|
||||
~acidAmp = ~acidAmp * 0.92; // FIX : acid line absente du fade
|
||||
~reload.value;
|
||||
0.25.wait;
|
||||
};
|
||||
~fading = false;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
2.wait;
|
||||
};
|
||||
"=== PLAYLIST TERMINEE ===".postln;
|
||||
}).play;
|
||||
};
|
||||
"=== ~playPlaylist pret ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- STOP PLAYLIST ---------------------------------------------------
|
||||
(
|
||||
~playlist !? { ~playlist.stop; ~playlist = nil };
|
||||
~track !? { ~track.stop; ~track = nil };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== PLAYLIST ARRETEE ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// PLAYLISTS PREDEFINIES (Cmd+Entree sur celle qu'on veut)
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- PLAYLIST FULL : toutes les 23 tracks (~3h12) ---------------------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["A_acid_journey.scd", 420], // 7 min
|
||||
["B_deep_to_hard.scd", 480], // 8 min
|
||||
["C_hypnotic_loop.scd", 600], // 10 min
|
||||
["D_wobble_drop.scd", 420], // 7 min
|
||||
["E_vietnam_hard.scd", 480], // 8 min
|
||||
["F_trance_uplifter.scd", 600], // 10 min
|
||||
["G_detroit_soulful.scd", 480], // 8 min
|
||||
["H_acid_trance.scd", 480], // 8 min
|
||||
["I_liquid_dnb.scd", 420], // 7 min
|
||||
["J_ambient_cinematic.scd",720], // 12 min
|
||||
["K_tribal_ethno.scd", 480], // 8 min
|
||||
["L_future_garage.scd", 420], // 7 min
|
||||
["M_chiptune_madness.scd", 360], // 6 min
|
||||
["N_phonk.scd", 300], // 5 min
|
||||
["O_asian_cinematic.scd", 600], // 10 min
|
||||
["P_industrial.scd", 480], // 8 min
|
||||
["Q_neurofunk_dnb.scd", 420], // 7 min
|
||||
["R_synthwave.scd", 480], // 8 min
|
||||
["S_drone_doom.scd", 900], // 15 min
|
||||
["T_hardcore_gabber.scd", 360], // 6 min
|
||||
["U_vocal_trance.scd", 600], // 10 min
|
||||
["V_glitch_idm.scd", 480], // 8 min
|
||||
["W_dub_techno.scd", 600], // 10 min
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST DANCE FLOOR : tracks dansantes (~1h30) ------------------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["A_acid_journey.scd", 420],
|
||||
["F_trance_uplifter.scd", 600],
|
||||
["G_detroit_soulful.scd", 480],
|
||||
["H_acid_trance.scd", 480],
|
||||
["I_liquid_dnb.scd", 420],
|
||||
["L_future_garage.scd", 420],
|
||||
["U_vocal_trance.scd", 600],
|
||||
["W_dub_techno.scd", 600],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST CHILL / AMBIENT : tracks calmes (~1h) ------------------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["J_ambient_cinematic.scd",720],
|
||||
["O_asian_cinematic.scd", 600],
|
||||
["K_tribal_ethno.scd", 480],
|
||||
["S_drone_doom.scd", 900],
|
||||
["W_dub_techno.scd", 600],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST BASS MUSIC : dubstep + dnb + bass-heavy (~1h) ----------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["D_wobble_drop.scd", 420],
|
||||
["E_vietnam_hard.scd", 480],
|
||||
["L_future_garage.scd", 420],
|
||||
["I_liquid_dnb.scd", 420],
|
||||
["Q_neurofunk_dnb.scd", 420],
|
||||
["N_phonk.scd", 300],
|
||||
["P_industrial.scd", 480],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST HARD : techno hard / hardcore / industrial (~50 min) ---
|
||||
(
|
||||
~playPlaylist.([
|
||||
["B_deep_to_hard.scd", 480],
|
||||
["P_industrial.scd", 480],
|
||||
["T_hardcore_gabber.scd", 360],
|
||||
["E_vietnam_hard.scd", 480],
|
||||
["Q_neurofunk_dnb.scd", 420],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST WORLD MUSIC : asia + tribal + cinematic (~50 min) ------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["O_asian_cinematic.scd", 600],
|
||||
["K_tribal_ethno.scd", 480],
|
||||
["E_vietnam_hard.scd", 480],
|
||||
["J_ambient_cinematic.scd",720],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST RETRO : synthwave + chiptune + house (~30 min) ---------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["R_synthwave.scd", 480],
|
||||
["M_chiptune_madness.scd", 360],
|
||||
["G_detroit_soulful.scd", 480],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST EXPERIMENTAL : glitch + drone + ambient (~38 min) ------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["V_glitch_idm.scd", 480],
|
||||
["S_drone_doom.scd", 900],
|
||||
["C_hypnotic_loop.scd", 600],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST SHORT (5 tracks, ~35 min) -------------------------------
|
||||
(
|
||||
~playPlaylist.([
|
||||
["A_acid_journey.scd", 420],
|
||||
["F_trance_uplifter.scd", 600],
|
||||
["I_liquid_dnb.scd", 420],
|
||||
["E_vietnam_hard.scd", 480],
|
||||
["W_dub_techno.scd", 600],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST DEMO (durees reduites a 90s par track, ~35 min) --------
|
||||
// Pour tester rapidement la palette sans attendre 3h
|
||||
(
|
||||
~playPlaylist.([
|
||||
["A_acid_journey.scd", 90], ["B_deep_to_hard.scd", 90],
|
||||
["C_hypnotic_loop.scd",90], ["D_wobble_drop.scd", 90],
|
||||
["E_vietnam_hard.scd", 90], ["F_trance_uplifter.scd",90],
|
||||
["G_detroit_soulful.scd",90],["H_acid_trance.scd",90],
|
||||
["I_liquid_dnb.scd", 90], ["J_ambient_cinematic.scd",90],
|
||||
["K_tribal_ethno.scd",90], ["L_future_garage.scd",90],
|
||||
["M_chiptune_madness.scd",90],["N_phonk.scd",90],
|
||||
["O_asian_cinematic.scd",90],["P_industrial.scd",90],
|
||||
["Q_neurofunk_dnb.scd",90], ["R_synthwave.scd",90],
|
||||
["S_drone_doom.scd", 90], ["T_hardcore_gabber.scd",90],
|
||||
["U_vocal_trance.scd",90], ["V_glitch_idm.scd",90],
|
||||
["W_dub_techno.scd", 90],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- PLAYLIST RANDOM (toutes les tracks dans un ordre aleatoire) -----
|
||||
(
|
||||
~playPlaylist.(
|
||||
[
|
||||
"A_acid_journey.scd", "B_deep_to_hard.scd", "C_hypnotic_loop.scd",
|
||||
"D_wobble_drop.scd", "E_vietnam_hard.scd", "F_trance_uplifter.scd",
|
||||
"G_detroit_soulful.scd", "H_acid_trance.scd", "I_liquid_dnb.scd",
|
||||
"J_ambient_cinematic.scd", "K_tribal_ethno.scd", "L_future_garage.scd",
|
||||
"M_chiptune_madness.scd", "N_phonk.scd", "O_asian_cinematic.scd",
|
||||
"P_industrial.scd", "Q_neurofunk_dnb.scd", "R_synthwave.scd",
|
||||
"S_drone_doom.scd", "T_hardcore_gabber.scd", "U_vocal_trance.scd",
|
||||
"V_glitch_idm.scd", "W_dub_techno.scd"
|
||||
].scramble.collect { |fn|
|
||||
var dur = (
|
||||
"A_acid_journey": 420, "B_deep_to_hard": 480, "C_hypnotic_loop": 600,
|
||||
"D_wobble_drop": 420, "E_vietnam_hard": 480, "F_trance_uplifter": 600,
|
||||
"G_detroit_soulful": 480, "H_acid_trance": 480, "I_liquid_dnb": 420,
|
||||
"J_ambient_cinematic": 720, "K_tribal_ethno": 480, "L_future_garage": 420,
|
||||
"M_chiptune_madness": 360, "N_phonk": 300, "O_asian_cinematic": 600,
|
||||
"P_industrial": 480, "Q_neurofunk_dnb": 420, "R_synthwave": 480,
|
||||
"S_drone_doom": 900, "T_hardcore_gabber": 360, "U_vocal_trance": 600,
|
||||
"V_glitch_idm": 480, "W_dub_techno": 600
|
||||
)[fn.replace(".scd","").asSymbol] ?? 420;
|
||||
[fn, dur];
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// PLAYLIST CUSTOM -- copier ce template et editer la liste
|
||||
// =====================================================================
|
||||
(
|
||||
~playPlaylist.([
|
||||
// [filename, duree_secondes],
|
||||
["F_trance_uplifter.scd", 300], // 5 min seulement
|
||||
["U_vocal_trance.scd", 300],
|
||||
["H_acid_trance.scd", 300],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// CONTROLES PENDANT LA PLAYLIST
|
||||
// =====================================================================
|
||||
|
||||
// --- SKIP TRACK (passe a la suivante immediatement) ------------------
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[SKIP] passage a la track suivante".postln;
|
||||
)
|
||||
|
||||
// --- PAUSE / RESUME (toggle mute global via master limiter) ---------
|
||||
( ~masterLim !? { ~masterLim.run(false) }; "[PAUSE]".postln; )
|
||||
( ~masterLim !? { ~masterLim.run(true) }; "[RESUME]".postln; )
|
||||
|
||||
// --- INFO -- track en cours ------------------------------------------
|
||||
( ("synths actifs: " ++ s.numSynths ++ " | CPU: " ++ s.avgCPU.round(0.1) ++ "%").postln; )
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
// =====================================================================
|
||||
// engine.scd -- Moteur (SynthDef + helpers + Pdef + master limiter)
|
||||
//
|
||||
// USAGE
|
||||
// 1. Cmd+Entree sur le bloc SETUP (une fois par session)
|
||||
// 2. Cmd+Entree sur le bloc PLAY pour lancer le beat
|
||||
// 3. Charger separement : presets.scd, tweaks.scd, tracks/*.scd
|
||||
// 4. Cmd+Entree sur STOP en bas pour couper
|
||||
// =====================================================================
|
||||
|
||||
// 1. SETUP -- evalue UNE FOIS au demarrage de la session
|
||||
// =====================================================================
|
||||
(
|
||||
s.waitForBoot {
|
||||
|
||||
// ----- Acid 303 -----
|
||||
// Env ADSR sur l'amp avec doneAction:2 -- garanti pas de fuite
|
||||
// memoire meme si on l'utilise dans un Pbind classique. Avec
|
||||
// PmonoArtic legato<1, le release (50ms) ne finit jamais avant
|
||||
// le retrigger -> le synth reste vivant et le slide fonctionne.
|
||||
SynthDef(\acid, {
|
||||
arg freq = 110, gate = 1, accent = 0, slideTime = 0.005,
|
||||
cutoff = 800, cutoffEnv = 3500, rq = 0.15,
|
||||
envDecay = 0.35, ampDecay = 0.28,
|
||||
drive = 2.5, amp = 0.32, pan = 0,
|
||||
scBus = 0, scAmt = 0.7;
|
||||
var f, sig, ampEnv, fEnv, fc, duck;
|
||||
f = Lag.kr(freq, slideTime);
|
||||
sig = Saw.ar(f);
|
||||
fEnv = EnvGen.kr(Env.perc(0.001, envDecay * (1 - (accent * 0.4))),
|
||||
gate, doneAction: 0);
|
||||
fc = (cutoff + (fEnv * cutoffEnv * (1 + accent))).clip(60, 14000);
|
||||
sig = RLPF.ar(sig, fc, rq);
|
||||
// ADSR avec sustain=0 : la note "perc" naturelle, mais le
|
||||
// release de 50ms permet le retrigger PmonoArtic sans free.
|
||||
// doneAction:2 libere le Synth quand release atteint 0 -> safe.
|
||||
ampEnv = EnvGen.kr(
|
||||
Env.adsr(0.003, ampDecay, 0, 0.05, curve: -3),
|
||||
gate, doneAction: 2
|
||||
);
|
||||
sig = (sig * drive * (1 + (accent * 0.6))).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = sig * ampEnv * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Kick (rond, sub-charge, click discret + sidechain out) -----
|
||||
SynthDef(\kick, {
|
||||
arg freq = 55, pitchAmt = 3.0, pitchTime = 0.035,
|
||||
decay = 0.32, drive = 1.3, click = 0.2,
|
||||
amp = 0.5, pan = 0,
|
||||
scBus = 0, scShape = 0.18; // sidechain : bus de sortie + duree decay
|
||||
var pEnv, body, sub, clickSig, ampEnv, sig, scEnv;
|
||||
// pitch drop expo court
|
||||
pEnv = EnvGen.kr(Env([freq * pitchAmt, freq], [pitchTime], -3));
|
||||
body = SinOsc.ar(pEnv);
|
||||
// sub-bass en parallele (octave en dessous, fixe)
|
||||
sub = SinOsc.ar(freq * 0.5);
|
||||
// click haute frequence, court
|
||||
clickSig = HPF.ar(WhiteNoise.ar, 3000) *
|
||||
EnvGen.kr(Env.perc(0.0005, 0.004));
|
||||
sig = body + (sub * 0.3) + (clickSig * click);
|
||||
ampEnv = EnvGen.kr(Env.perc(0.002, decay, curve: -3), doneAction: 2);
|
||||
// tanh AVANT ampEnv : sature la forme d'onde brute, garde le
|
||||
// transitoire intact dans l'enveloppe (corrige M3 du critic)
|
||||
sig = (sig * drive).tanh;
|
||||
sig = sig * ampEnv;
|
||||
sig = LeakDC.ar(sig) * amp;
|
||||
// Sidechain : enveloppe percussive plus longue que l'amp pour
|
||||
// ducker les autres voix le temps que l'oreille percoive le kick
|
||||
scEnv = EnvGen.kr(Env.perc(0.001, scShape, curve: -4));
|
||||
Out.kr(scBus, scEnv);
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Hi-hat -----
|
||||
SynthDef(\hat, {
|
||||
arg hpf = 9000, decay = 0.04, amp = 0.18, pan = 0;
|
||||
var sig, env;
|
||||
sig = HPF.ar(WhiteNoise.ar, hpf);
|
||||
sig = BPF.ar(sig, 10000, 0.4);
|
||||
env = EnvGen.kr(Env.perc(0.001, decay), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Lead melody (saw+pulse detunes + chorus stereo + LPF) -----
|
||||
SynthDef(\lead, {
|
||||
arg freq = 220, gate = 1, sawAmt = 0.6, pulseWidth = 0.4,
|
||||
cutoff = 2500, rq = 0.5,
|
||||
attack = 0.01, decay = 0.15, sustain = 0.4, release = 0.3,
|
||||
detune = 0.005, drive = 1.2, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var oscL, oscR, sig, ampEnv, duck;
|
||||
oscL = (Saw.ar(freq * (1 - detune)) * sawAmt) +
|
||||
(Pulse.ar(freq * (1 - detune), pulseWidth) * (1 - sawAmt));
|
||||
oscR = (Saw.ar(freq * (1 + detune)) * sawAmt) +
|
||||
(Pulse.ar(freq * (1 + detune), pulseWidth) * (1 - sawAmt));
|
||||
oscL = DelayC.ar(oscL, 0.02, SinOsc.kr(0.6, 0).range(0.001, 0.004));
|
||||
oscR = DelayC.ar(oscR, 0.02, SinOsc.kr(0.6, pi).range(0.001, 0.004));
|
||||
sig = RLPF.ar([oscL, oscR], cutoff, rq);
|
||||
ampEnv = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
sig = Balance2.ar(sig[0], sig[1], pan);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, sig * ampEnv * amp * duck);
|
||||
}).add;
|
||||
|
||||
// ----- Pad (super-saw 5 voix detunes + chorus + LPF) -----
|
||||
SynthDef(\pad, {
|
||||
arg freq = 220, gate = 1, detune = 0.012,
|
||||
cutoff = 1800, rq = 0.6,
|
||||
attack = 0.4, decay = 0.3, sustain = 0.7, release = 1.5,
|
||||
drive = 1.0, amp = 0.15, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck;
|
||||
sig = Mix.fill(5, { |i|
|
||||
Saw.ar(freq * (1 + ((i - 2) * detune)))
|
||||
}) * 0.22;
|
||||
sig = RLPF.ar(sig, cutoff, rq);
|
||||
sig = sig + DelayC.ar(sig, 0.04,
|
||||
SinOsc.kr(0.3, 0).range(0.01, 0.03));
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release),
|
||||
gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Pluck (Karplus-Strong, decay naturel) -----
|
||||
SynthDef(\pluck, {
|
||||
arg freq = 220, gate = 1,
|
||||
cutoff = 5000, rq = 0.5,
|
||||
attack = 0.001, decay = 0.05, sustain = 0.0, release = 0.5,
|
||||
drive = 1.0, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var sig, env, duck, exciter, ks;
|
||||
exciter = WhiteNoise.ar(0.5) * EnvGen.kr(Env.perc(0.0005, 0.005));
|
||||
ks = LeakDC.ar(CombC.ar(exciter, 0.05, freq.reciprocal, 2.5));
|
||||
sig = LPF.ar(ks, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release),
|
||||
gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- FM Bell DUBSTEP -- wobble + sub + detune + saturation -----
|
||||
// Inspire des growl/wobble dubstep : RLPF resonant module par LFTri
|
||||
// (wobble), 2 voix detunees, sub-bass parallele, distortion lourde.
|
||||
SynthDef(\fmBell, {
|
||||
arg freq = 220, gate = 1,
|
||||
modRatio = 1.41, modIndex = 3,
|
||||
cutoff = 400, // cutoff de base (bas pour dubstep)
|
||||
wobbleRate = 4, // Hz (4 = 1/8 a 120 BPM)
|
||||
wobbleDepth = 1800, // amplitude du wobble en Hz
|
||||
wobbleShape = 0, // 0 = LFTri (smooth), 1 = LFPulse (chop)
|
||||
rq = 0.25, // resonance forte (audible)
|
||||
subAmt = 0.45, // niveau du sub-bass octave -1
|
||||
detune = 0.006, // detune entre 2 voix L/R
|
||||
attack = 0.005, decay = 0.3, sustain = 0.4, release = 0.4,
|
||||
drive = 3.5, // saturation lourde
|
||||
amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var carL, carR, mod, wobble, sig, sub, env, duck, lfo;
|
||||
// LFO wobble (mix tri / pulse selon shape)
|
||||
lfo = SelectX.kr(wobbleShape, [
|
||||
LFTri.kr(wobbleRate),
|
||||
LFPulse.kr(wobbleRate, 0, 0.5, 2, -1)
|
||||
]);
|
||||
wobble = (cutoff + (lfo.range(0, 1) * wobbleDepth)).clip(80, 12000);
|
||||
// FM avec carrieres detunees L/R
|
||||
mod = SinOsc.ar(freq * modRatio) * freq * modIndex * 0.5;
|
||||
carL = SinOsc.ar(freq * (1 - detune) + mod);
|
||||
carR = SinOsc.ar(freq * (1 + detune) + mod);
|
||||
// Sub-bass : octave -1 + octave -2 + harmonique 3 (epaisseur)
|
||||
// sub massif typique dubstep : sub fonda + sub-sub + harmonique
|
||||
sub = (SinOsc.ar(freq * 0.5) * 0.7) +
|
||||
(SinOsc.ar(freq * 0.25) * 0.5) +
|
||||
(SinOsc.ar(freq * 0.5, pi * 0.5) * 0.2); // legere phase shift
|
||||
sub = sub * subAmt * 1.3; // boost interne
|
||||
sub = sub.tanh; // soft clip pour rester contenu
|
||||
sig = [carL + sub, carR + sub];
|
||||
// RLPF resonant module par le wobble
|
||||
sig = RLPF.ar(sig, wobble, rq);
|
||||
// Saturation lourde (le coeur du son dubstep)
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
// Compression "tape" pour faire rentrer le sub
|
||||
sig = (sig * 1.4).tanh;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release),
|
||||
gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = Balance2.ar(sig[0], sig[1], pan);
|
||||
Out.ar(0, sig * env * amp * duck);
|
||||
}).add;
|
||||
|
||||
// ----- Stab (court, saw + saturation pour Detroit) -----
|
||||
SynthDef(\stab, {
|
||||
arg freq = 220, gate = 1, sawAmt = 0.7,
|
||||
cutoff = 1500, rq = 0.3,
|
||||
attack = 0.001, decay = 0.04, sustain = 0.0, release = 0.06,
|
||||
drive = 2.8, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var sig, env, duck;
|
||||
sig = (Saw.ar(freq) * sawAmt) +
|
||||
(Pulse.ar(freq * 1.005, 0.3) * (1 - sawAmt));
|
||||
sig = RLPF.ar(sig, cutoff, rq);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release, curve: -3),
|
||||
gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Saw3 (3 saws empilees, octaves -1/0/+1) -----
|
||||
SynthDef(\saw3, {
|
||||
arg freq = 220, gate = 1,
|
||||
cutoff = 2200, rq = 0.4,
|
||||
attack = 0.005, decay = 0.12, sustain = 0.5, release = 0.25,
|
||||
drive = 1.4, amp = 0.16, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var sig, env, duck;
|
||||
sig = (Saw.ar(freq * 0.5) * 0.35) +
|
||||
(Saw.ar(freq) * 0.55) +
|
||||
(Saw.ar(freq * 2) * 0.25);
|
||||
sig = RLPF.ar(sig, cutoff, rq);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release),
|
||||
gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Snare (tone + bruit blanc filtre) -----
|
||||
SynthDef(\snare, {
|
||||
arg freq = 200, decay = 0.13, noiseAmt = 0.6, drive = 1.5,
|
||||
amp = 0.5, pan = 0;
|
||||
var tone, noise, env, sig, pitchEnv;
|
||||
pitchEnv = EnvGen.kr(Env([freq * 2, freq], [0.02], -2));
|
||||
tone = SinOsc.ar(pitchEnv) * EnvGen.kr(Env.perc(0.001, 0.05));
|
||||
noise = HPF.ar(WhiteNoise.ar, 1500);
|
||||
noise = BPF.ar(noise, 3000, 0.5);
|
||||
noise = noise * EnvGen.kr(Env.perc(0.001, decay));
|
||||
sig = (tone * (1 - noiseAmt)) + (noise * noiseAmt);
|
||||
env = EnvGen.kr(Env.perc(0.002, decay, curve: -3), doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
sig = LeakDC.ar(sig) * amp * env;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Clap (4 attaques rapides puis tail) -----
|
||||
SynthDef(\clap, {
|
||||
arg decay = 0.18, amp = 0.4, pan = 0;
|
||||
var noise, env, sig;
|
||||
noise = HPF.ar(WhiteNoise.ar, 800);
|
||||
noise = BPF.ar(noise, 1500, 0.5);
|
||||
env = EnvGen.kr(
|
||||
Env.new(
|
||||
[0, 1, 0.5, 1, 0.5, 1, 1, 0],
|
||||
[0.001, 0.008, 0.008, 0.008, 0.008, 0.005, decay],
|
||||
\exp
|
||||
),
|
||||
doneAction: 2
|
||||
);
|
||||
sig = noise * env * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Riser (bruit qui monte sur N secondes) -----
|
||||
// Courbe \sin (qui supporte zero) -- \exp + valeur 0 = NaN
|
||||
// qui silenciait tout le bus.
|
||||
SynthDef(\riser, {
|
||||
arg dur = 4, startCutoff = 300, endCutoff = 8000,
|
||||
amp = 0.3, pan = 0;
|
||||
var noise, cutoff, env, sig;
|
||||
cutoff = Line.kr(startCutoff, endCutoff, dur).clip(20, 18000);
|
||||
noise = (WhiteNoise.ar * 0.5) + (PinkNoise.ar * 0.3);
|
||||
sig = HPF.ar(noise, cutoff);
|
||||
sig = BPF.ar(sig, cutoff.min(15000), 0.4);
|
||||
env = EnvGen.kr(
|
||||
Env.new([0, 0.3, 1, 0], [dur * 0.5, dur * 0.45, dur * 0.05], \sin),
|
||||
doneAction: 2
|
||||
);
|
||||
sig = LeakDC.ar(sig * env * amp);
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Impact (boom + reverse hit, marque les drops) -----
|
||||
SynthDef(\impact, {
|
||||
arg freq = 45, decay = 1.5, amp = 0.7, pan = 0;
|
||||
var pitchEnv, body, noise, env, sig;
|
||||
pitchEnv = EnvGen.kr(Env([freq * 5, freq * 0.5], [0.12], \exp));
|
||||
body = SinOsc.ar(pitchEnv);
|
||||
noise = LPF.ar(WhiteNoise.ar, 800) *
|
||||
EnvGen.kr(Env.perc(0.001, 0.4));
|
||||
sig = body + (noise * 0.5);
|
||||
env = EnvGen.kr(Env.perc(0.002, decay, curve: -4), doneAction: 2);
|
||||
sig = sig * env;
|
||||
sig = (sig * 1.5).tanh;
|
||||
sig = LeakDC.ar(sig) * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Open hat (cymbale ouverte, decay long) -----
|
||||
SynthDef(\openHat, {
|
||||
arg hpf = 7000, decay = 0.4, amp = 0.18, pan = 0;
|
||||
var sig, env;
|
||||
sig = HPF.ar(WhiteNoise.ar, hpf);
|
||||
sig = BPF.ar(sig, 9000, 0.6);
|
||||
env = EnvGen.kr(Env.perc(0.001, decay, curve: -4), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Crash cymbal -----
|
||||
SynthDef(\crash, {
|
||||
arg hpf = 4000, decay = 1.5, amp = 0.3, pan = 0;
|
||||
var sig, env;
|
||||
sig = HPF.ar(WhiteNoise.ar + (PinkNoise.ar * 0.5), hpf);
|
||||
sig = BPF.ar(sig, 7000, 0.4) + (sig * 0.3);
|
||||
env = EnvGen.kr(Env.perc(0.002, decay, curve: -3), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Tom (drum tone melodique) -----
|
||||
SynthDef(\tom, {
|
||||
arg freq = 110, decay = 0.3, drive = 1.4, amp = 0.5, pan = 0;
|
||||
var pitchEnv, body, noise, sig, env;
|
||||
pitchEnv = EnvGen.kr(Env([freq * 1.8, freq], [0.04], -3));
|
||||
body = SinOsc.ar(pitchEnv) + (Saw.ar(pitchEnv) * 0.2);
|
||||
noise = HPF.ar(WhiteNoise.ar, 2000) * EnvGen.kr(Env.perc(0.001, 0.01));
|
||||
sig = body + (noise * 0.3);
|
||||
env = EnvGen.kr(Env.perc(0.003, decay, curve: -3), doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
sig = LeakDC.ar(sig) * env * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Rim shot (clic metallique court) -----
|
||||
SynthDef(\rim, {
|
||||
arg freq = 1500, decay = 0.04, amp = 0.3, pan = 0;
|
||||
var sig, env;
|
||||
sig = SinOsc.ar(freq) + (HPF.ar(WhiteNoise.ar, 4000) * 0.5);
|
||||
sig = BPF.ar(sig, freq * 1.5, 0.3);
|
||||
env = EnvGen.kr(Env.perc(0.001, decay, curve: -5), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Cowbell -----
|
||||
SynthDef(\cowbell, {
|
||||
arg freq = 800, decay = 0.2, amp = 0.3, pan = 0;
|
||||
var sig, env;
|
||||
sig = (Pulse.ar(freq, 0.5) * 0.5) + (Pulse.ar(freq * 1.501, 0.5) * 0.5);
|
||||
sig = BPF.ar(sig, freq * 1.3, 0.3) * 2;
|
||||
env = EnvGen.kr(Env.perc(0.001, decay, curve: -4), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Reese bass (2 saws detunes filtres -- DnB / dubstep) -----
|
||||
SynthDef(\reese, {
|
||||
arg freq = 55, gate = 1, detune = 0.012, cutoff = 800, rq = 0.4,
|
||||
attack = 0.005, decay = 0.1, sustain = 0.7, release = 0.2,
|
||||
drive = 2.5, amp = 0.35, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck;
|
||||
sig = (Saw.ar(freq * (1 - detune)) * 0.5) +
|
||||
(Saw.ar(freq * (1 + detune)) * 0.5) +
|
||||
(Saw.ar(freq * 0.5) * 0.3); // sub
|
||||
sig = RLPF.ar(sig, cutoff, rq);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- 808 bass (trap-style sub avec pitch glide) -----
|
||||
SynthDef(\bass808, {
|
||||
arg freq = 55, gate = 1, glide = 0.05,
|
||||
attack = 0.003, decay = 0.4, sustain = 0.8, release = 0.6,
|
||||
drive = 1.4, amp = 0.45, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var sig, env, duck, f;
|
||||
f = Lag.kr(freq, glide);
|
||||
sig = SinOsc.ar(f) + (SinOsc.ar(f * 0.5) * 0.5);
|
||||
sig = (sig * drive).tanh;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Sweep down (l'inverse du riser, descend) -----
|
||||
SynthDef(\sweep, {
|
||||
arg dur = 4, startCutoff = 8000, endCutoff = 200,
|
||||
amp = 0.25, pan = 0;
|
||||
var noise, cutoff, env, sig;
|
||||
cutoff = Line.kr(startCutoff, endCutoff, dur);
|
||||
noise = WhiteNoise.ar + (PinkNoise.ar * 0.5);
|
||||
sig = LPF.ar(noise, cutoff);
|
||||
sig = BPF.ar(sig, cutoff * 1.2, 0.5);
|
||||
env = EnvGen.kr(Env.linen(0.05, dur - 0.1, 0.05), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Vinyl noise (texture continue, ambiance) -----
|
||||
SynthDef(\vinyl, {
|
||||
arg amp = 0.05, pan = 0;
|
||||
var sig, crackles;
|
||||
sig = PinkNoise.ar(0.3);
|
||||
crackles = Dust.ar(50, 0.4) + Dust.ar(20, 0.5);
|
||||
sig = sig + crackles;
|
||||
sig = HPF.ar(sig, 80);
|
||||
Out.ar(0, Pan2.ar(sig * amp, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Master limiter -----
|
||||
SynthDef(\masterLim, {
|
||||
var sig = In.ar(0, 2);
|
||||
sig = LeakDC.ar(sig);
|
||||
sig = Limiter.ar(sig, 0.95, 0.005);
|
||||
ReplaceOut.ar(0, sig);
|
||||
}).add;
|
||||
|
||||
s.sync;
|
||||
|
||||
// ----- Bus de sidechain (control) ----------------------------
|
||||
// Le kick ecrit son enveloppe sur ce bus, acid + lead lisent et
|
||||
// duckent leur sortie -> mix techno qui pompe sur le kick.
|
||||
~scBus !? { ~scBus.free };
|
||||
~scBus = Bus.control(s, 1);
|
||||
|
||||
// ----- Master limiter en queue de groupe ---------------------
|
||||
~masterLim !? { ~masterLim.free };
|
||||
~masterLim = Synth.tail(s.defaultGroup, \masterLim);
|
||||
|
||||
// ----- Patterns par defaut -----------------------------------
|
||||
~bpm = 132;
|
||||
~acidNotes = [ 36, 36, 48, 36, 39, 36, 43, 39,
|
||||
36, 41, 36, 39, 43, 36, 36, 41 ];
|
||||
~acidAccents = [ 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1 ];
|
||||
~acidSlides = [ 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0 ];
|
||||
~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ];
|
||||
~hatSteps = [ 0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0 ];
|
||||
~snareSteps = (0 ! 16);
|
||||
~snareAmp = 0.45;
|
||||
~snareFreq = 200; ~snareNoiseAmt = 0.6; ~snareDecay = 0.13;
|
||||
// Percussions secondaires
|
||||
~clapSteps = (0 ! 16); ~clapAmp = 0.35;
|
||||
~percSteps = (0 ! 16); ~percAmp = 0.25; ~percInst = \rim; // \rim | \cowbell | \tom | \openHat
|
||||
~tomFreq = 110; ~cowbellFreq = 800;
|
||||
~melodyNotes = [
|
||||
60, 0, 67, 0, 70, 0, 67, 65,
|
||||
63, 0, 60, 0, 0, 67, 70, 72,
|
||||
75, 0, 72, 70, 67, 0, 0, 65,
|
||||
63, 60, 0, 67, 70, 0, 72, 0
|
||||
];
|
||||
|
||||
// ----- Parametres de timbre ----------------------------------
|
||||
~acidCutoff = 800; ~acidRq = 0.15; ~acidCutoffEnv = 3500;
|
||||
~acidDrive = 2.5; ~acidAmp = 0.32;
|
||||
~kickAmp = 0.5;
|
||||
~kickFreq = 55; // frequence fondamentale (45=sub, 55=normal, 70=punchy)
|
||||
~kickPitchAmt = 3.0; // ratio du drop initial (2=soft, 3=normal, 5=snappy)
|
||||
~kickDecay = 0.32; // duree (0.18=tight, 0.32=normal, 0.6=boomy)
|
||||
~kickDrive = 1.3; // saturation (1.0=clean, 1.5=normal, 3.0=distort)
|
||||
~kickClick = 0.2; // amplitude du click HF (0=rond, 0.4=claquant)
|
||||
~hatAmp = 0.18;
|
||||
~melodyInst = \lead; // \lead | \pad | \pluck | \fmBell | \stab | \saw3
|
||||
~melodyBoost = 1.6; // multiplicateur global du volume melodie
|
||||
~melodyCutoff = 2400; ~melodyRq = 0.5; ~melodyAmp = 0.16;
|
||||
~melodyDrive = 1.2; ~melodyAttack = 0.012; ~melodyRelease = 0.25;
|
||||
~melodySawAmt = 0.6; ~melodyDetune = 0.006;
|
||||
// Specifique fmBell dubstep
|
||||
~melodyWobbleRate = 4; // Hz (4=1/8 a 120BPM, 8=1/16, 2=1/4)
|
||||
~melodyWobbleDepth = 1800; // ouverture du wobble en Hz
|
||||
~melodyWobbleShape = 0; // 0 = LFTri smooth, 1 = LFPulse chop
|
||||
~melodySubAmt = 0.85; // sub fmBell (0.85 = MASSIF)
|
||||
|
||||
// ----- 2e voix melodique (harmony / counter-melody) ----------
|
||||
~harmonyInst = \pad; // synth pour la 2e voix
|
||||
~harmonyNotes = (0 ! 32); // muet par defaut
|
||||
~harmonyCutoff = 1800; ~harmonyRq = 0.6;
|
||||
~harmonyAttack = 0.05; ~harmonyDecay = 0.15;
|
||||
~harmonySustain = 0.6; ~harmonyRelease = 0.5;
|
||||
~harmonyDrive = 1.2; ~harmonyAmp = 0.14;
|
||||
~harmonyDur = 0.25; // 0.25 = 1/16 ; 0.5 = 1/8 ; 0.125 = 1/32
|
||||
~harmonyDetune = 0.006; ~harmonySawAmt = 0.6;
|
||||
|
||||
// Sidechain : amount par voix (0 = pas de duck, 1 = mute total sur kick)
|
||||
~acidScAmt = 0.7; // l'acid pompe fort sur le kick
|
||||
~leadScAmt = 0.5; // le lead pompe modere
|
||||
~kickScShape = 0.18; // duree de l'env sidechain (s)
|
||||
|
||||
// ----- Reload : reconstruit les 4 Pdef depuis les variables --
|
||||
~reload = {
|
||||
// Guards : les Pseq plantent si on leur passe nil/array vide.
|
||||
// On force une valeur par defaut pour chaque variable de pattern.
|
||||
if (~kickSteps.isNil or: { ~kickSteps.isEmpty }) { ~kickSteps = (0 ! 16) };
|
||||
if (~hatSteps.isNil or: { ~hatSteps.isEmpty }) { ~hatSteps = (0 ! 16) };
|
||||
if (~snareSteps.isNil or: { ~snareSteps.isEmpty }) { ~snareSteps = (0 ! 16) };
|
||||
if (~clapSteps.isNil or: { ~clapSteps.isEmpty }) { ~clapSteps = (0 ! 16) };
|
||||
if (~percSteps.isNil or: { ~percSteps.isEmpty }) { ~percSteps = (0 ! 16) };
|
||||
if (~acidNotes.isNil or: { ~acidNotes.isEmpty }) { ~acidNotes = [36] };
|
||||
if (~acidAccents.isNil or: { ~acidAccents.isEmpty }) { ~acidAccents = [0] };
|
||||
if (~acidSlides.isNil or: { ~acidSlides.isEmpty }) { ~acidSlides = [0] };
|
||||
if (~melodyNotes.isNil or: { ~melodyNotes.isEmpty }) { ~melodyNotes = (0 ! 32) };
|
||||
if (~harmonyNotes.isNil or: { ~harmonyNotes.isEmpty }) { ~harmonyNotes = (0 ! 32) };
|
||||
// Amps / params scalaires : default 0 evite NaN
|
||||
~kickAmp = ~kickAmp ? 0; ~hatAmp = ~hatAmp ? 0;
|
||||
~snareAmp = ~snareAmp ? 0; ~clapAmp = ~clapAmp ? 0;
|
||||
~percAmp = ~percAmp ? 0; ~acidAmp = ~acidAmp ? 0;
|
||||
~melodyAmp = ~melodyAmp ? 0; ~harmonyAmp = ~harmonyAmp ? 0;
|
||||
~melodyBoost = ~melodyBoost ? 1; ~harmonyDur = ~harmonyDur ? 0.25;
|
||||
Pdef(\kickSeq, Pbind(
|
||||
\instrument, \kick, \dur, 0.25,
|
||||
\amp, Pseq(~kickSteps.collect { |s| s * ~kickAmp }, inf),
|
||||
\freq, ~kickFreq, \pitchAmt, ~kickPitchAmt,
|
||||
\decay, ~kickDecay, \drive, ~kickDrive, \click, ~kickClick,
|
||||
\scBus, ~scBus.index, \scShape, ~kickScShape,
|
||||
));
|
||||
Pdef(\hatSeq, Pbind(
|
||||
\instrument, \hat, \dur, 0.25,
|
||||
\amp, Pseq(~hatSteps.collect { |s| s * ~hatAmp }, inf),
|
||||
));
|
||||
Pdef(\snareSeq, Pbind(
|
||||
\instrument, \snare, \dur, 0.25,
|
||||
\amp, Pseq(~snareSteps.collect { |s| s * ~snareAmp }, inf),
|
||||
\freq, ~snareFreq, \noiseAmt, ~snareNoiseAmt, \decay, ~snareDecay,
|
||||
));
|
||||
Pdef(\clapSeq, Pbind(
|
||||
\instrument, \clap, \dur, 0.25,
|
||||
\amp, Pseq(~clapSteps.collect { |s| s * ~clapAmp }, inf),
|
||||
));
|
||||
Pdef(\percSeq, Pbind(
|
||||
\instrument, ~percInst, \dur, 0.25,
|
||||
\amp, Pseq(~percSteps.collect { |s| s * ~percAmp }, inf),
|
||||
\freq, if (~percInst == \tom) { ~tomFreq } { ~cowbellFreq },
|
||||
));
|
||||
Pdef(\acidSeq, PmonoArtic(\acid,
|
||||
\dur, 0.25,
|
||||
\legato, 0.85,
|
||||
\midinote, Pseq(~acidNotes, inf),
|
||||
\accent, Pseq(~acidAccents, inf),
|
||||
\slideTime, Pseq(~acidSlides.collect { |s| if(s == 1) {0.12} {0.005} }, inf),
|
||||
\cutoff, ~acidCutoff,
|
||||
\cutoffEnv, ~acidCutoffEnv,
|
||||
\rq, ~acidRq,
|
||||
\drive, ~acidDrive,
|
||||
\amp, ~acidAmp,
|
||||
\scBus, ~scBus.index, // lit le sidechain
|
||||
\scAmt, ~acidScAmt,
|
||||
));
|
||||
Pdef(\melodySeq, Pbind(
|
||||
\instrument, ~melodyInst, \dur, 0.25,
|
||||
\legato, 0.9,
|
||||
\type, Pseq(~melodyNotes.collect { |n| if(n > 0) { \note } { \rest } }, inf),
|
||||
\midinote, Pseq(~melodyNotes.collect { |n| if(n > 0) { n } { 60 } }, inf),
|
||||
\cutoff, ~melodyCutoff,
|
||||
\rq, ~melodyRq,
|
||||
\attack, ~melodyAttack,
|
||||
\release, ~melodyRelease,
|
||||
\drive, ~melodyDrive,
|
||||
\sawAmt, ~melodySawAmt,
|
||||
\detune, ~melodyDetune,
|
||||
\wobbleRate, ~melodyWobbleRate, // pour fmBell
|
||||
\wobbleDepth, ~melodyWobbleDepth,
|
||||
\wobbleShape, ~melodyWobbleShape,
|
||||
\subAmt, ~melodySubAmt,
|
||||
\amp, ~melodyAmp * ~melodyBoost,
|
||||
\scBus, ~scBus.index,
|
||||
\scAmt, ~leadScAmt,
|
||||
));
|
||||
// 2e voix : peut tourner en parallele avec une duree differente
|
||||
// (32th, 16th, 8th) pour creer du contrepoint / phasing
|
||||
Pdef(\harmonySeq, Pbind(
|
||||
\instrument, ~harmonyInst, \dur, ~harmonyDur,
|
||||
\legato, 0.9,
|
||||
\type, Pseq(~harmonyNotes.collect { |n| if(n > 0) { \note } { \rest } }, inf),
|
||||
\midinote, Pseq(~harmonyNotes.collect { |n| if(n > 0) { n } { 60 } }, inf),
|
||||
\cutoff, ~harmonyCutoff,
|
||||
\rq, ~harmonyRq,
|
||||
\attack, ~harmonyAttack,
|
||||
\decay, ~harmonyDecay,
|
||||
\sustain, ~harmonySustain,
|
||||
\release, ~harmonyRelease,
|
||||
\drive, ~harmonyDrive,
|
||||
\detune, ~harmonyDetune,
|
||||
\sawAmt, ~harmonySawAmt,
|
||||
\amp, ~harmonyAmp * ~melodyBoost,
|
||||
\scBus, ~scBus.index,
|
||||
\scAmt, ~leadScAmt,
|
||||
));
|
||||
};
|
||||
|
||||
// ----- ~enableHarmony : voir palette/harmonics/presets.scd ---
|
||||
// ----- Scales + helpers : voir palette/scales.scd ------------
|
||||
// (charges automatiquement par 00_load.scd > CHARGER TOUT)
|
||||
|
||||
"=== setup OK -- lance le bloc PLAY ===".postln;
|
||||
};
|
||||
)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// =====================================================================
|
||||
// examples/00_index.scd -- Index des exemples de workflow
|
||||
//
|
||||
// CONVENTION
|
||||
// Chaque fichier de ce dossier est un mini-tutoriel a executer
|
||||
// bloc par bloc dans l'IDE SuperCollider (Cmd+Entree sur chaque
|
||||
// parenthese top-level). Il N'EST PAS charge via .load -- on
|
||||
// avance manuellement, en lisant les commentaires.
|
||||
//
|
||||
// PARCOURS RECOMMANDE pour decouvrir le projet
|
||||
// 01_quickstart.scd Premier "Hello world" sonore (debutant)
|
||||
// 02_first_track.scd Lancer une track autonome (debutant)
|
||||
// 04_filter_lfo_vcf.scd LFO + VCF -- la base du modular live
|
||||
// 06_drum_kits_sequences.scd Macros rapides pour kits + sequences
|
||||
// 07_loops_manager.scd Gestionnaire de boucles propre
|
||||
// 09_scenes_recall.scd Save / recall snapshots
|
||||
// 11_playlist_auto.scd Lancer une session sans rien faire
|
||||
//
|
||||
// CATALOGUE COMPLET
|
||||
// 01_quickstart.scd (debutant) Premier demarrage
|
||||
// 02_first_track.scd (debutant) Track autonome A
|
||||
// 03_multi_melody_tracks.scd (intermediaire) Multi-pistes melodiques
|
||||
// 04_filter_lfo_vcf.scd (intermediaire) LFO + VCF master
|
||||
// 05_drops_breakdowns_buildups (intermediaire) Tricks scéniques
|
||||
// 06_drum_kits_sequences.scd (debutant) Drum kits + sequences pretes
|
||||
// 07_loops_manager.scd (intermediaire) loops.scd workflow
|
||||
// 08_jump_sections.scd (intermediaire) Naviguer dans les tracks
|
||||
// 09_scenes_recall.scd (intermediaire) Snapshot / recall
|
||||
// 10_midi_controller.scd (avance) Setup controller MIDI
|
||||
// 11_playlist_auto.scd (debutant) Playlist auto + controles
|
||||
// 12_chord_progressions.scd (intermediaire) ~progXxx + chordsToMelody
|
||||
// 13_world_ethno.scd (intermediaire) Workflow oriental/asia
|
||||
// 14_fx_chains_dynamic.scd (avance) FX bus + LFO sur params FX
|
||||
// 15_full_live_set.scd (avance) Set live 30 minutes complet
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- Ouvrir tous les exemples dans l'IDE -----------------------------
|
||||
(
|
||||
var root = if (thisProcess.nowExecutingPath.notNil) { thisProcess.nowExecutingPath.dirname } { "/Users/electron/Documents/Projets_Creatifs/sound_algo/examples" };
|
||||
[
|
||||
"01_quickstart.scd",
|
||||
"02_first_track.scd",
|
||||
"03_multi_melody_tracks.scd",
|
||||
"04_filter_lfo_vcf.scd",
|
||||
"05_drops_breakdowns_buildups.scd",
|
||||
"06_drum_kits_sequences.scd",
|
||||
"07_loops_manager.scd",
|
||||
"08_jump_sections.scd",
|
||||
"09_scenes_recall.scd",
|
||||
"10_midi_controller.scd",
|
||||
"11_playlist_auto.scd",
|
||||
"12_chord_progressions.scd",
|
||||
"13_world_ethno.scd",
|
||||
"14_fx_chains_dynamic.scd",
|
||||
"15_full_live_set.scd",
|
||||
].do { |path|
|
||||
Document.open(root +/+ path);
|
||||
};
|
||||
)
|
||||
@@ -0,0 +1,93 @@
|
||||
// =====================================================================
|
||||
// examples/01_quickstart.scd -- Premier demarrage
|
||||
//
|
||||
// TITRE : Hello, sound_algo
|
||||
// DUREE : ~2 minutes
|
||||
// NIVEAU : debutant
|
||||
// PREREQUIS : aucun (on charge tout depuis ce fichier)
|
||||
//
|
||||
// BUT
|
||||
// - Lancer le moteur complet (engine + synthdefs + helpers + live/*)
|
||||
// - Demarrer un beat techno minimal (kick + hat + acid)
|
||||
// - Modifier 2-3 parametres en live
|
||||
// - Stopper proprement
|
||||
//
|
||||
// Chaque parenthese (...) ci-dessous est un bloc independant. Pose
|
||||
// ton curseur dedans, Cmd+Entree pour evaluer. Avance bloc par bloc.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 1] CHARGER TOUT (~5s, attend que le serveur boote) ------
|
||||
// Reproduit exactement le bloc CHARGER TOUT de 00_load.scd : charge
|
||||
// engine + synthdefs + scales + melodies + harmonics + setup, puis
|
||||
// appelle ~setupAll.() qui boote le serveur et charge fx_bus + live
|
||||
// + mixer + scenes + loops + fills + sequences + jump. Termine par
|
||||
// un ~check.() qui rapporte l'etat de chaque module.
|
||||
(
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
(~base ++ "engine.scd").load;
|
||||
(~base ++ "synthdefs/asia.scd").load;
|
||||
(~base ++ "synthdefs/extra.scd").load;
|
||||
(~base ++ "synthdefs/authentic.scd").load;
|
||||
(~base ++ "palette/scales.scd").load;
|
||||
(~base ++ "palette/melodies/index.scd").load;
|
||||
(~base ++ "palette/harmonics/index.scd").load;
|
||||
(~base ++ "setup.scd").load;
|
||||
~setupAll.();
|
||||
"=== CHARGEMENT EN COURS -- attendre la fin du boot et le ~check final ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] PLAY -- lance les 8 sequenceurs Pdef -------------------
|
||||
// Reproduit le bloc PLAY DEFAULT de 00_load.scd.
|
||||
// Attendre que le bloc precedent ait fini son boot (3-5s) et que tu
|
||||
// voies "=== setupAll DONE ===" dans le post window.
|
||||
(
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
"=== PLAY ===".postln;
|
||||
)
|
||||
// >> Tu dois entendre kick + hat + acid 303. Laisse tourner 30s.
|
||||
|
||||
|
||||
// --- [etape 3] TWEAK 1 : monter le volume du kick --------------------
|
||||
// ~kickAmp est une variable globale. Apres modif, ~reload.value
|
||||
// reconstruit les Pdef avec la nouvelle valeur.
|
||||
(
|
||||
~kickAmp = 0.7; // defaut 0.5
|
||||
~reload.value;
|
||||
("kickAmp = " ++ ~kickAmp).postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 4] TWEAK 2 : ouvrir le filtre de la melodie -------------
|
||||
// ~melodyCutoff = frequence de coupure du LPF de la voix melody.
|
||||
(
|
||||
~melodyCutoff = 5000; // defaut 2400, plus haut = plus brillant
|
||||
~reload.value;
|
||||
("melodyCutoff = " ++ ~melodyCutoff).postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 5] TWEAK 3 : changer le BPM -------------------------------
|
||||
(
|
||||
~bpm = 140;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
("bpm = " ++ ~bpm).postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 6] STOP -- coupe les sequenceurs --------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] ARRET TOTAL (libere tout proprement) -------------------
|
||||
// ~teardown.() vient de setup.scd : stop tous les Pdef/routines/LFO,
|
||||
// libere ~masterLim + ~scBus + bus FX. A faire quand tu veux quitter.
|
||||
( ~teardown.(); )
|
||||
@@ -0,0 +1,76 @@
|
||||
// =====================================================================
|
||||
// examples/02_first_track.scd -- Lancer ta premiere track
|
||||
//
|
||||
// TITRE : Track A "Acid Journey" en autopilot
|
||||
// DUREE : ~7 minutes (la duree complete de la track)
|
||||
// NIVEAU : debutant
|
||||
// PREREQUIS : evaluer CHARGER TOUT dans 00_load.scd
|
||||
//
|
||||
// BUT
|
||||
// - Charger une track autonome (tracks/A_acid_journey.scd)
|
||||
// - La lancer via le bloc principal de la track
|
||||
// - Tweaker quelques params pendant qu'elle joue
|
||||
// - Stop avec ~track.stop
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 1] Verifier que le moteur est charge --------------------
|
||||
// Si tu vois "engine pas charge", retourne dans 00_load.scd et
|
||||
// evalue CHARGER TOUT.
|
||||
(
|
||||
if (~reload.isNil) {
|
||||
"!!! engine pas charge -- evalue CHARGER TOUT dans 00_load.scd".postln;
|
||||
} {
|
||||
"engine OK -- pret a lancer la track".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Charger le fichier de la track -----------------------
|
||||
// .load ne fait QUE definir ~track (Routine), il ne lance rien.
|
||||
// Ouvre tracks/A_acid_journey.scd dans l'IDE pour voir le code.
|
||||
(
|
||||
(~base ++ "tracks/A_acid_journey.scd").load;
|
||||
)
|
||||
// -- attendre le post "[A 0:00]" : il indique que la track a demarre.
|
||||
// ATTENTION : load() execute le contenu, donc la Routine .play est
|
||||
// declenche. La track joue maintenant.
|
||||
|
||||
|
||||
// --- [etape 3] (optionnel) Si tu prefere demarrer manuellement ------
|
||||
// Ouvre tracks/A_acid_journey.scd, place ton curseur dans le bloc
|
||||
// commencant par "( ~track !? { ~track.stop }; ~track = Routine({"
|
||||
// et fais Cmd+Entree. C'est exactement ce que .load fait.
|
||||
|
||||
|
||||
// --- [etape 4] TWEAK pendant que la track joue -----------------------
|
||||
// La track a sa propre logique, mais tu peux toujours surcharger
|
||||
// les variables globales. Ton override tient jusqu'au prochain
|
||||
// "passage" interne de la track qui les reecrit.
|
||||
|
||||
// Boost le volume kick pendant la section acid rave
|
||||
( ~kickAmp = 0.75; ~reload.value; "kickAmp boost".postln; )
|
||||
|
||||
// Casser la melodie : nouveau pattern aleatoire dans une scale
|
||||
( ~melodyNotes = ~genMelody.(0.6, ~scaleMinorPent); ~reload.value; )
|
||||
|
||||
// Ajouter une harmonie a la tierce par-dessus
|
||||
( ~enableHarmony.(\third); )
|
||||
|
||||
// Acidifier le filtre acid (resonance up)
|
||||
( ~acidRq = 0.08; ~acidCutoffEnv = 5500; ~reload.value; )
|
||||
|
||||
|
||||
// --- [etape 5] STOP de la track --------------------------------------
|
||||
// ~track.stop arrete la Routine ; les Pdef continuent de jouer
|
||||
// le dernier etat. Pour TOUT couper, voir [etape 6].
|
||||
( ~track !? { ~track.stop; "track stoppee".postln }; )
|
||||
|
||||
|
||||
// --- [etape 6] STOP complet (sequenceurs + track) -------------------
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP COMPLET ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,102 @@
|
||||
// =====================================================================
|
||||
// examples/03_multi_melody_tracks.scd -- Multi-pistes melodiques
|
||||
//
|
||||
// TITRE : Plusieurs voix melodiques en parallele
|
||||
// DUREE : ~5 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT dans 00_load.scd (charge melodies/index.scd
|
||||
// qui charge tracks.scd avec ses 3 pistes par defaut)
|
||||
//
|
||||
// BUT
|
||||
// Le moteur a UNE voix melody (\melodySeq). Ce systeme s'AJOUTE
|
||||
// en parallele : chaque piste \m1, \m2, \m3 a son propre Pdef
|
||||
// independant + Event de parametres dans ~mel[\name].
|
||||
//
|
||||
// Helpers : ~melTrackOn / Off / Set / Solo / Harm / List
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 1] Setup de base -- demarrer la rythmique --------------
|
||||
// On garde le kick + hat du moteur, on coupe la melodie LEGACY (\melodySeq)
|
||||
// pour que les nouvelles pistes soient seules a faire de la melodie.
|
||||
(
|
||||
~kickAmp = 0.55; ~hatAmp = 0.18;
|
||||
~melodyAmp = 0; // mute la melodie legacy
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq].do { |k| Pdef(k).play };
|
||||
"rythmique en place -- prochaine etape : ~melTrackOn".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Lancer la piste m1 (lead pad par defaut) -------------
|
||||
// m1 est preconfigure avec ~m1 (32 notes, scale minor pent).
|
||||
( ~melTrackOn.(\m1); )
|
||||
|
||||
|
||||
// --- [etape 3] Changer l'instrument de m1 -- warmPad ---------------
|
||||
// ~melTrackSet rebuild le Pdef automatiquement.
|
||||
( ~melTrackSet.(\m1, \inst, \warmPad); )
|
||||
|
||||
|
||||
// --- [etape 4] Changer la melodie de m1 -- on prend ml5 (64 pas) ---
|
||||
// ml5 est une melodie longue de 64 pas (palette/melodies/long.scd).
|
||||
// .copy car on ne veut pas que les futures mutations modifient ~ml5.
|
||||
( ~melTrackSet.(\m1, \notes, ~ml5.copy); )
|
||||
|
||||
|
||||
// --- [etape 5] Lancer la piste m2 (counter pluck) -------------------
|
||||
// m2 est preconfiguree pluck pan -0.3 (cote gauche).
|
||||
( ~melTrackOn.(\m2); )
|
||||
|
||||
|
||||
// --- [etape 6] Changer m2 en pluck rapide --------------------------
|
||||
// On peut empiler les ~melTrackSet.
|
||||
(
|
||||
~melTrackSet.(\m2, \inst, \pluck);
|
||||
~melTrackSet.(\m2, \dur, 0.125); // 1/32 (rapide)
|
||||
~melTrackSet.(\m2, \pan, -0.5);
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] Generer une harmonie automatique sur m1 -------------
|
||||
// ~melTrackHarm.(source, dest, preset) cree une nouvelle piste
|
||||
// "harm1" derivee de m1, harmonisee a la tierce.
|
||||
// Presets : \third \fifth \counter \arp \chord \tranceLayer ...
|
||||
( ~melTrackHarm.(\m1, \harm1, \third); )
|
||||
|
||||
// (variante) harmonie a la quinte au lieu de la tierce
|
||||
// ( ~melTrackHarm.(\m1, \harm1, \fifth); )
|
||||
|
||||
|
||||
// --- [etape 8] Solo / Unsolo (mute toutes sauf une) -----------------
|
||||
( ~melTrackSolo.(\m1); ) // seule m1 est audible
|
||||
// -- attendre 8 secondes
|
||||
( ~melTrackUnsolo.(); )
|
||||
|
||||
|
||||
// --- [etape 9] Lister toutes les pistes actives ---------------------
|
||||
( ~melTrackList.(); )
|
||||
|
||||
|
||||
// --- [etape 10] Tirer une melodie aleatoire par genre --------------
|
||||
// Exemple : trance pour m1, oriental pour m2.
|
||||
( ~melTrackByGenre.(\m1, \trance); )
|
||||
( ~melTrackByGenre.(\m2, \oriental); )
|
||||
|
||||
|
||||
// --- [etape 11] Stop des pistes melodiques --------------------------
|
||||
(
|
||||
~melTrackOff.(\m1);
|
||||
~melTrackOff.(\m2);
|
||||
~melTrackOff.(\harm1);
|
||||
"melodic tracks OFF".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 12] STOP complet (rythmique aussi) ---------------------
|
||||
(
|
||||
~melTrackChoke.(); // stop TOUTES les pistes melodiques
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP COMPLET ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,117 @@
|
||||
// =====================================================================
|
||||
// examples/04_filter_lfo_vcf.scd -- Filtres et modulations
|
||||
//
|
||||
// TITRE : LFO sur variables + VCF master en chaine
|
||||
// DUREE : ~5 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd) PUIS evaluer le SETUP
|
||||
// de live.scd (premier bloc top-level "(...)" du fichier)
|
||||
//
|
||||
// CONCEPTS
|
||||
// - ~lfoTo modulation par LFO d'une variable d'environnement
|
||||
// (rebuild les Pdef en boucle)
|
||||
// - VCF master : un Synth qui filtre tout le bus 0 avant le
|
||||
// master limiter. Reproduit un SH-101, MS-20, Moog, formant...
|
||||
//
|
||||
// Si tu vois "~lfoTo is not defined", c'est que live.scd n'a pas
|
||||
// ete charge -- ouvre live.scd et evalue son SETUP.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~lfoTo.isNil) {
|
||||
"!!! live.scd pas charge -- ouvre live.scd et evalue son SETUP".postln;
|
||||
} {
|
||||
"live.scd OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] Demarrer un beat techno minimal ---------------------
|
||||
(
|
||||
~kickAmp = 0.55; ~hatAmp = 0.18; ~acidAmp = 0.32; ~melodyAmp = 0.16;
|
||||
~melodyInst = \saw3;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \acidSeq, \melodySeq].do { |k| Pdef(k).play };
|
||||
"beat lance -- pret pour les LFO".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] LFO sin sur le cutoff de la melodie ------------------
|
||||
// ~lfoTo.(\param, rateHz, depth, shape, center)
|
||||
// param = nom de variable d'environnement (sans tilde)
|
||||
// rate = Hz (0.5 = lent, 4 = rapide)
|
||||
// depth = amplitude de modulation (additionnee a center)
|
||||
// shape = \sin \tri \saw \sqr \rand \smoothRand \drunk \noise
|
||||
// center = valeur centrale (autour de laquelle le LFO oscille)
|
||||
( ~lfoTo.(\melodyCutoff, 0.5, 1500, \sin, 2500); )
|
||||
// -- la melodie respire (cutoff oscille entre 1000 et 4000 Hz).
|
||||
// Laisser tourner 30s.
|
||||
|
||||
|
||||
// --- [etape 3] LFO sqr sur l'ampli acid (gate rythmique) ------------
|
||||
// shape \sqr cree un gate on/off rapide => effet trance gate.
|
||||
( ~lfoTo.(\acidAmp, 4, 0.4, \sqr, 0.5); )
|
||||
|
||||
|
||||
// --- [etape 4] LFO drunk sur le BPM (subtile derive) ----------------
|
||||
// shape \drunk fait un random walk lent (jamais de saut brutal).
|
||||
( ~lfoTo.(\bpm, 0.1, 8, \drunk, 132); )
|
||||
// -- BPM oscille entre 124 et 140 lentement.
|
||||
|
||||
|
||||
// --- [etape 5] STOP les LFO un par un ------------------------------
|
||||
( ~lfoStopVar.(\melodyCutoff); )
|
||||
( ~lfoStopVar.(\acidAmp); )
|
||||
( ~lfoStopVar.(\bpm); )
|
||||
// ou TOUT couper d'un coup :
|
||||
// ( ~lfoStopAllVars.(); )
|
||||
|
||||
|
||||
// --- [etape 6] VCF master Moog -- filtre tout le mix ----------------
|
||||
// ~vcfOn.(\type, freq, q)
|
||||
// types : \moog \ms20 \ladder \formant \comb \hpf \bpf \notch
|
||||
( ~vcfOn.(\moog, 800, 0.4); )
|
||||
// -- on entend une coupure douce ; tout le mix est plus sombre.
|
||||
|
||||
|
||||
// --- [etape 7] Sweep automatique du cutoff (8s) --------------------
|
||||
// ~vcfSweep.(fromHz, toHz, dur, curve)
|
||||
( ~vcfSweep.(8000, 200, 8); )
|
||||
// -- fait une descente filtre 8000 -> 200 Hz sur 8s. Effet "filter close".
|
||||
|
||||
|
||||
// --- [etape 8] Couper le VCF (signal redevient brillant) ------------
|
||||
( ~vcfOff.(); )
|
||||
|
||||
|
||||
// --- [etape 9] VCF formant -- voyelle 'a' --------------------------
|
||||
// Pour le formant, freq = INDICE de voyelle (0=a 1=e 2=i 3=o 4=u),
|
||||
// q = resonance (0.05 a 1).
|
||||
( ~vcfOn.(\formant, 0, 0.3); ) // 'a' large
|
||||
|
||||
// changer en voyelle 'i' (plus aigue)
|
||||
( ~vcfSet.(\vowel, 2); )
|
||||
|
||||
// arreter
|
||||
( ~vcfOff.(); )
|
||||
|
||||
|
||||
// --- [etape 10] Preset VCF acid (Moog 600Hz, q tres haute) ---------
|
||||
( ~vcfPreset.(\acid); )
|
||||
|
||||
// preset deep, dub, bright, dark, formantA-U
|
||||
( ~vcfPreset.(\dub); )
|
||||
( ~vcfPreset.(\bright); )
|
||||
( ~vcfOff.(); )
|
||||
|
||||
|
||||
// --- [etape 11] STOP global -----------------------------------------
|
||||
(
|
||||
~lfoStopAllVars.();
|
||||
~vcfOff.();
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,132 @@
|
||||
// =====================================================================
|
||||
// examples/05_drops_breakdowns_buildups.scd -- Tricks scéniques
|
||||
//
|
||||
// TITRE : Les "tricks" classiques d'une perf live
|
||||
// DUREE : ~10 minutes (en testant tout)
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd) + SETUP de live.scd
|
||||
//
|
||||
// BUT
|
||||
// Helpers ergonomiques de live.scd pour les transitions :
|
||||
// drop, breakdown, buildup, tape stop, freeze, glitch, stutter...
|
||||
//
|
||||
// Tous ces helpers sont des Routines : ils tournent jusqu'a la
|
||||
// fin de la duree donnee, puis restaurent l'etat precedent
|
||||
// automatiquement.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~drop.isNil) {
|
||||
"!!! live.scd pas charge -- ouvre live.scd et evalue son SETUP".postln;
|
||||
} {
|
||||
"live.scd OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] Demarrer un beat de base ----------------------------
|
||||
(
|
||||
~kickAmp = 0.55; ~hatAmp = 0.18; ~melodyAmp = 0.18; ~acidAmp = 0.3;
|
||||
~melodyInst = \lead;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \acidSeq, \melodySeq].do { |k| Pdef(k).play };
|
||||
"beat lance -- pret pour les tricks".postln;
|
||||
)
|
||||
// -- laisse tourner 16-32 beats avant de tenter un drop.
|
||||
|
||||
|
||||
// --- [etape 2] DROP -- silence sec puis blast (4s de buildup) -------
|
||||
// ~drop.(buildDur)
|
||||
// Coupe tout, monte un riser, puis re-explose la rythmique a fond.
|
||||
( ~drop.(4); )
|
||||
// -- attendre 8s, le drop fait son cycle complet.
|
||||
|
||||
|
||||
// --- [etape 3] BREAKDOWN -- mute drums, garde melodie + reverb ------
|
||||
// ~breakdown.(dur)
|
||||
// Coupe kick + hat, ajoute reverb sur la melodie, restaure apres dur.
|
||||
( ~breakdown.(8); )
|
||||
// -- attendre 8s.
|
||||
|
||||
|
||||
// --- [etape 4] BUILDUP -- crescendo qui monte sur dur secondes ------
|
||||
// ~buildup.(dur)
|
||||
// Snare roll + filtre qui s'ouvre + amp qui monte.
|
||||
( ~buildup.(8); )
|
||||
|
||||
|
||||
// --- [etape 5] HANDS UP -- cut sub + boost lead --------------------
|
||||
// Effet typique festival : on enleve le bas + clap et on pousse le lead.
|
||||
( ~handsUp.(); )
|
||||
// -- attendre 4s.
|
||||
|
||||
|
||||
// --- [etape 6] TAPE STOP -- ralentissement du tempo (2s) -----------
|
||||
// ~tapeStop.(dur)
|
||||
// Tempo descend a 0 sur dur secondes ; effet bande magnetique.
|
||||
( ~tapeStop.(2); )
|
||||
|
||||
|
||||
// --- [etape 7] FREEZE -- gel tout en reverb (4s) -------------------
|
||||
// Reverb saturee + master mute = effet "vide aspirant" puis retour.
|
||||
( ~freeze.(4); )
|
||||
|
||||
|
||||
// --- [etape 8] GLITCH -- bitcrush + rate variations sur 2s ----------
|
||||
( ~glitch.(2); )
|
||||
|
||||
|
||||
// --- [etape 9] STUTTER -- repete tres vite a 8Hz pendant 1s --------
|
||||
// ~stutter.(rateHz, dur)
|
||||
( ~stutter.(8, 1); )
|
||||
// -- on entend un effet "bbbbbbbb" tres serre.
|
||||
|
||||
|
||||
// --- [etape 10] JUMP CUT -- silence sec de 0.5s --------------------
|
||||
// Effet "pause" tres courte, comme une coupe au montage video.
|
||||
( ~jumpCut.(0.5); )
|
||||
|
||||
|
||||
// --- [etape 11] REVERB TAIL -- queue de reverb 4s ------------------
|
||||
// Mute la rythmique, garde uniquement la queue de reverb.
|
||||
( ~reverbTail.(4); )
|
||||
|
||||
|
||||
// --- [etape 12] BIT CRUSH NOW -- bitcrush sur 1s ------------------
|
||||
// ~bitCrushNow.(bits, sr, dur)
|
||||
( ~bitCrushNow.(6, 6000, 1); )
|
||||
|
||||
|
||||
// --- [etape 13] RING MOD -- mod en anneau a 200Hz pendant 1s ------
|
||||
( ~ringMod.(200, 1); )
|
||||
|
||||
|
||||
// --- [etape 14] TAPE REVERSE -- inverse la lecture 2s -------------
|
||||
( ~tapeReverse.(2); )
|
||||
|
||||
|
||||
// --- [etape 15] COMBO classique : breakdown -> buildup -> drop -----
|
||||
// Chaine 3 helpers en sequence (separes par .wait).
|
||||
// Ce bloc est un Routine asynchrone qui dure ~24 secondes au total.
|
||||
(
|
||||
Routine({
|
||||
"[combo] BREAKDOWN".postln;
|
||||
~breakdown.(8);
|
||||
8.wait;
|
||||
"[combo] BUILDUP".postln;
|
||||
~buildup.(8);
|
||||
8.wait;
|
||||
"[combo] DROP".postln;
|
||||
~drop.(4);
|
||||
}).play;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 16] STOP global ----------------------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,128 @@
|
||||
// =====================================================================
|
||||
// examples/06_drum_kits_sequences.scd -- Kits + sequences
|
||||
//
|
||||
// TITRE : Macros pour swap de kit + sequences scenaristiques
|
||||
// DUREE : ~6 minutes
|
||||
// NIVEAU : debutant
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
//
|
||||
// BUT
|
||||
// palette/rhythm/drum_kits.scd : 21 kits complets (Techno, DnB, Phonk, ...)
|
||||
// -- chaque kit est un bloc qui set ~kickSteps + ~hatSteps + ...
|
||||
// et appelle ~reload.value
|
||||
// palette/rhythm/sequences.scd : macros de sequences pretes a l'emploi
|
||||
// -- chaque seq est une Routine qui orchestre transitions + tempo
|
||||
//
|
||||
// Avant de pouvoir utiliser les ~seqXxx, il faut charger sequences.scd.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 1] Charger drum_kits + sequences -----------------------
|
||||
(
|
||||
(~base ++ "palette/rhythm/drum_kits.scd").load;
|
||||
(~base ++ "palette/rhythm/sequences.scd").load;
|
||||
"drum_kits + sequences charges".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Lancer le moteur -----------------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
"PLAY".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 3] KIT TECHNO -- 4/4 classique -------------------------
|
||||
// Le kit set kickSteps + hatSteps + amp, puis ~reload.value.
|
||||
// On entend tout de suite la diff.
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.32;
|
||||
~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~snareSteps = (0 ! 16); ~clapSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT TECHNO ===".postln;
|
||||
)
|
||||
// -- ecouter 16 beats puis passer au kit suivant.
|
||||
|
||||
|
||||
// --- [etape 4] KIT DUBSTEP -- kick lourd + snare backbeat ----------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 48; ~kickPitchAmt = 3.5; ~kickDecay = 0.5;
|
||||
~kickDrive = 1.5; ~kickClick = 0.15;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5;
|
||||
~snareFreq = 220; ~snareNoiseAmt = 0.65; ~snareDecay = 0.16;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT DUBSTEP ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 5] KIT PHONK -- cowbell + 808 + pitched snare ----------
|
||||
// Ce kit existe dans drum_kits.scd ; on peut aussi recharger
|
||||
// directement le fichier et evaluer le bloc dedie.
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 1,0,0,0, 0,0,1,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 42; ~kickPitchAmt = 2.5; ~kickDecay = 0.6;
|
||||
~kickDrive = 1.2; ~kickClick = 0.05; // 808 boomy
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~snareAmp = 0.5;
|
||||
~snareFreq = 280; ~snareNoiseAmt = 0.4; ~snareDecay = 0.08;
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~hatAmp = 0.12;
|
||||
~percInst = \cowbell;
|
||||
~percSteps = [0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,1,0]; ~percAmp = 0.2;
|
||||
~clapSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT PHONK ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 6] Couper le moteur avant de tester les sequences -----
|
||||
// Les ~seqXxx prennent le controle ; on coupe les Pdef pour eviter
|
||||
// les conflits avec leur orchestration interne.
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"sequenceurs stoppes -- pret pour ~seqXxx".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] ~seqIntro -- montee progressive (~30s) --------------
|
||||
( ~seqIntro.(); )
|
||||
// -- la sequence dure ~30 secondes ; attendre la fin.
|
||||
|
||||
|
||||
// --- [etape 8] ~seqBuildup.(bars) -- crescendo trance --------------
|
||||
// .(8) = 8 mesures. Snare roll + filtre qui s'ouvre + amp up.
|
||||
( ~seqBuildup.(8); )
|
||||
|
||||
|
||||
// --- [etape 9] ~seqDrop -- drop techno (silence sec + blast) -------
|
||||
( ~seqDrop.(); )
|
||||
|
||||
|
||||
// --- [etape 10] ~seqTechnoLoop.(repeats) -- N pattern techno -------
|
||||
( ~seqTechnoLoop.(4); )
|
||||
// -- joue 4 iterations d'un pattern techno classique.
|
||||
|
||||
|
||||
// --- [etape 11] ~seqDubstepDrop -- drop dubstep ---------------------
|
||||
( ~seqDubstepDrop.(); )
|
||||
|
||||
|
||||
// --- [etape 12] ~seqAcidEvolve -- acid qui mute progressivement ----
|
||||
// Genere ~30s d'acid avec mutations toutes les 4 mesures.
|
||||
( ~seqAcidEvolve.(); )
|
||||
|
||||
|
||||
// --- [etape 13] STOP la sequence en cours --------------------------
|
||||
( ~seqStop.(); )
|
||||
|
||||
|
||||
// --- [etape 14] STOP global ----------------------------------------
|
||||
(
|
||||
~seqStop.();
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,118 @@
|
||||
// =====================================================================
|
||||
// examples/07_loops_manager.scd -- Gestionnaire de boucles
|
||||
//
|
||||
// TITRE : Demarrer/stopper des Pdef en boucles propres
|
||||
// DUREE : ~6 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + ouvrir loops.scd et evaluer son SETUP (1er bloc top-level)
|
||||
//
|
||||
// CONCEPTS
|
||||
// Le moteur expose 8 Pdef (~kickSeq ... ~harmonySeq) que l'on lance
|
||||
// classiquement avec Pdef(\xxx).play. loops.scd est une sur-couche
|
||||
// qui te permet de :
|
||||
// - Nommer chaque boucle (\kick1, \hat1, \verse, \drop ...)
|
||||
// - Limiter la duree (en beats / bars / repetitions)
|
||||
// - Chainer / parall des boucles
|
||||
// - Snapshot l'etat des params au moment du lancement
|
||||
// - Fade in / out + countdown
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~loopOn.isNil) {
|
||||
"!!! loops.scd pas charge -- ouvre loops.scd et evalue son SETUP".postln;
|
||||
} {
|
||||
"loops.scd OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] Demarrer kick + hat en boucle ----------------------
|
||||
// ~loopOn.(name, source) ; source = symbol Pdef ou Function
|
||||
(
|
||||
~kickAmp = 0.55; ~hatAmp = 0.18; ~reload.value;
|
||||
~loopOn.(\kick1, \kickSeq);
|
||||
~loopOn.(\hat1, \hatSeq);
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Lister les boucles actives --------------------------
|
||||
( ~loopList.(); )
|
||||
|
||||
|
||||
// --- [etape 3] Repeat snare 4 fois sur 4 secondes chacune ----------
|
||||
// ~loopRepeat.(name, source, n, dur)
|
||||
// Demarre snareSeq, joue 4 cycles de 4s, puis stop auto.
|
||||
(
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5;
|
||||
~reload.value;
|
||||
~loopRepeat.(\snare1, \snareSeq, 4, 4);
|
||||
)
|
||||
// -- attendre 16s. Apres, le snare s'arrete tout seul.
|
||||
|
||||
|
||||
// --- [etape 4] Acid sur 32 beats puis stop --------------------------
|
||||
// ~loopBeats.(name, source, beats)
|
||||
( ~loopBeats.(\acid1, \acidSeq, 32); )
|
||||
// -- 32 beats = 8 mesures 4/4. Stop automatique.
|
||||
|
||||
|
||||
// --- [etape 5] Lancer m1 avec un countdown 4 beats -----------------
|
||||
// ~loopWithCountdown.(name, source, beats, max)
|
||||
// Affiche "4...3...2...1..." dans la console puis lance le Pdef.
|
||||
// max = inf -> boucle infinie apres le countdown.
|
||||
( ~loopWithCountdown.(\m1main, \melodySeq, 4, inf); )
|
||||
|
||||
|
||||
// --- [etape 6] Fade-out de la kick sur 4 secondes ------------------
|
||||
( ~loopFade.(\kick1, 4); )
|
||||
// -- la kick descend lineairement vers 0 et se libere.
|
||||
|
||||
|
||||
// --- [etape 7] Chainer 3 boucles dans l'ordre ----------------------
|
||||
// ~loopChain.([[name, source, beats], ...])
|
||||
// -- chaque entry joue beats puis declenche la suivante.
|
||||
// Avant : on coupe ce qui tourne pour avoir un demarrage propre.
|
||||
( ~loopOffAll.(); )
|
||||
(
|
||||
~loopChain.([
|
||||
[\a, \kickSeq, 8], // 8 beats kick seul
|
||||
[\b, \melodySeq, 16], // 16 beats melodie
|
||||
[\c, \hatSeq, 8], // 8 beats hat
|
||||
]);
|
||||
)
|
||||
// -- duree totale = 32 beats. Suivre dans la console.
|
||||
|
||||
|
||||
// --- [etape 8] Boucles paralleles (toutes en meme temps) ----------
|
||||
( ~loopOffAll.(); )
|
||||
(
|
||||
~loopParallel.([
|
||||
[\k, \kickSeq],
|
||||
[\h, \hatSeq],
|
||||
[\m, \melodySeq],
|
||||
]);
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 9] Voir la progression en temps reel -------------------
|
||||
// Utile quand tu as des ~loopBeats / ~loopRepeat en cours.
|
||||
( ~loopProgress.(); )
|
||||
|
||||
|
||||
// --- [etape 10] ~allOn / ~allOff -- les 8 voies du moteur ----------
|
||||
( ~loopOffAll.(); )
|
||||
( ~allOn.(); ) // les 8 Pdef du moteur en boucle
|
||||
// -- attendre 8s
|
||||
( ~allOff.(); ) // les 8 stop
|
||||
|
||||
|
||||
// --- [etape 11] STOP global ----------------------------------------
|
||||
(
|
||||
~loopOffAll.();
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,96 @@
|
||||
// =====================================================================
|
||||
// examples/08_jump_sections.scd -- Naviguer dans les tracks
|
||||
//
|
||||
// TITRE : ~jumpTo -- aller direct a une section de track
|
||||
// DUREE : ~5 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + ouvrir jump.scd, evaluer SETUP JUMP (1er bloc) et
|
||||
// evaluer le bloc ~sections['A'] = (...) pour A
|
||||
//
|
||||
// CONCEPTS
|
||||
// jump.scd indexe ~sections[trackLetter][slug] -> { ...code... }
|
||||
// pour chaque section de chaque track. Utile pour :
|
||||
// - Tester rapidement le drop d'une track sans attendre 4 minutes
|
||||
// - Faire un medley en alternant les sections de plusieurs tracks
|
||||
// - Skip-mode pendant une perf live
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~jumpTo.isNil) {
|
||||
"!!! jump.scd pas charge -- ouvre jump.scd et evalue SETUP JUMP".postln;
|
||||
} {
|
||||
if (~sections['A'].isNil) {
|
||||
"!!! ~sections['A'] vide -- evalue le bloc 'TRACK A' de jump.scd".postln;
|
||||
} {
|
||||
"jump.scd + sections A OK".postln;
|
||||
};
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] Saut direct sur l'intro de A ------------------------
|
||||
// ~jumpTo.(letter, slug) -- letter = 'A' (string char) ou \A
|
||||
// Le slug doit correspondre a une cle de ~sections['A'].
|
||||
( ~jumpTo.('A', 'minimal_kick_t5_sub_melody_pad'); )
|
||||
// -- on entend immediatement le 1er moment de A (intro pad lent).
|
||||
// Laisser tourner ~30s.
|
||||
|
||||
|
||||
// --- [etape 2] Saut direct sur l'acid rave (drop de A) -------------
|
||||
( ~jumpTo.('A', 'acid_rave_kick_t1_melody_lead_variations'); )
|
||||
// -- le drop arrive instantanement, sans attendre les 2 minutes
|
||||
// d'intro normale.
|
||||
|
||||
|
||||
// --- [etape 3] Detroit stabs (3e section) --------------------------
|
||||
( ~jumpTo.('A', 'detroit_stabs_kick_t2_melody_stab'); )
|
||||
|
||||
|
||||
// --- [etape 4] Hard push (4e section) ------------------------------
|
||||
( ~jumpTo.('A', 'hard_push_kick_t4_distordu'); )
|
||||
|
||||
|
||||
// --- [etape 5] Outro -----------------------------------------------
|
||||
( ~jumpTo.('A', 'outro_melody_pad_qui_s_efface'); )
|
||||
|
||||
|
||||
// --- [etape 6] MEDLEY -- comparer des sections rapidement ----------
|
||||
// On joue 4 sections, ~10s chacune, dans une Routine.
|
||||
// Utile pour audition rapide.
|
||||
(
|
||||
Routine({
|
||||
"[medley] intro".postln;
|
||||
~jumpTo.('A', 'minimal_kick_t5_sub_melody_pad');
|
||||
10.wait;
|
||||
"[medley] acid rave".postln;
|
||||
~jumpTo.('A', 'acid_rave_kick_t1_melody_lead_variations');
|
||||
10.wait;
|
||||
"[medley] detroit".postln;
|
||||
~jumpTo.('A', 'detroit_stabs_kick_t2_melody_stab');
|
||||
10.wait;
|
||||
"[medley] hard push".postln;
|
||||
~jumpTo.('A', 'hard_push_kick_t4_distordu');
|
||||
10.wait;
|
||||
"[medley] OUTRO".postln;
|
||||
~jumpTo.('A', 'outro_melody_pad_qui_s_efface');
|
||||
}).play;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] (bonus) Comparer la meme section de plusieurs tracks
|
||||
// Ouvre jump.scd, evalue le bloc ~sections['B'] et ~sections['F'].
|
||||
// Puis :
|
||||
// ( ~jumpTo.('B', 'dub_start_kick_t3_boomy_melody_pad'); )
|
||||
// ( ~jumpTo.('F', '...'); )
|
||||
// (les slugs disponibles sont commentes en bas de chaque bloc de jump.scd)
|
||||
|
||||
|
||||
// --- [etape 8] STOP ------------------------------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
// =====================================================================
|
||||
// examples/09_scenes_recall.scd -- Save / recall scenes
|
||||
//
|
||||
// TITRE : Snapshot / restore de l'etat global
|
||||
// DUREE : ~5 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + ouvrir scenes.scd, evaluer son SETUP (1er bloc)
|
||||
//
|
||||
// CONCEPTS
|
||||
// Une "scene" est un snapshot de TOUTES les variables d'environnement
|
||||
// listees dans ~sceneKeys (kickAmp, melodyNotes, melodyCutoff...).
|
||||
// Tu peux la sauvegarder avec ~saveScene.(\nom), la rappeler avec
|
||||
// ~loadScene.(\nom), et persister le tout sur disque.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~saveScene.isNil) {
|
||||
"!!! scenes.scd pas charge -- ouvre scenes.scd et evalue son SETUP".postln;
|
||||
} {
|
||||
"scenes.scd OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] Lancer une track A pour avoir un point de depart ----
|
||||
// Charge tracks/A_acid_journey.scd qui set tous les params ET
|
||||
// demarre les Pdef. La track passe en "minimal" pour les ~30 1eres s.
|
||||
(
|
||||
(~base ++ "tracks/A_acid_journey.scd").load;
|
||||
)
|
||||
// -- attendre 5s que les params soient stables.
|
||||
|
||||
|
||||
// --- [etape 2] SAVE l'etat actuel comme \verseA --------------------
|
||||
( ~saveScene.(\verseA); )
|
||||
|
||||
|
||||
// --- [etape 3] Modifier les params (kick + cutoff + melodie) -------
|
||||
(
|
||||
~kickAmp = 0.8;
|
||||
~melodyCutoff = 6500;
|
||||
~melodyNotes = ~genMelody.(0.7, ~scaleMinor);
|
||||
~reload.value;
|
||||
"params modifies".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 4] SAVE cet etat comme \verseAvariant ------------------
|
||||
( ~saveScene.(\verseAvariant); )
|
||||
|
||||
|
||||
// --- [etape 5] LOAD \verseA -- on revient a l'etat initial ---------
|
||||
( ~loadScene.(\verseA); )
|
||||
// -- on entend les params revenir : kick 0.5, cutoff 1500, etc.
|
||||
|
||||
|
||||
// --- [etape 6] LOAD \verseAvariant -- retour a la variante --------
|
||||
( ~loadScene.(\verseAvariant); )
|
||||
|
||||
|
||||
// --- [etape 7] Lister les scenes sauvegardees ----------------------
|
||||
( ~listScenes.value; )
|
||||
|
||||
|
||||
// --- [etape 8] Supprimer une scene ---------------------------------
|
||||
( ~deleteScene.(\verseAvariant); )
|
||||
( ~listScenes.value; )
|
||||
|
||||
|
||||
// --- [etape 9] Persistence sur disque ------------------------------
|
||||
// ~saveScenesToDisk ecrit dans scenes_saved.scd a la racine du projet.
|
||||
// ~loadScenesFromDisk recharge depuis ce fichier.
|
||||
( ~saveScenesToDisk.value; )
|
||||
// -- on peut quitter SuperCollider, relancer la session, recharger
|
||||
// CHARGER TOUT + scenes.scd, puis :
|
||||
( ~loadScenesFromDisk.value; )
|
||||
|
||||
|
||||
// --- [etape 10] STOP -----------------------------------------------
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,95 @@
|
||||
// =====================================================================
|
||||
// examples/10_midi_controller.scd -- Setup MIDI
|
||||
//
|
||||
// TITRE : Mapper un controller MIDI sur les variables
|
||||
// DUREE : ~3 minutes
|
||||
// NIVEAU : avance
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + un controller MIDI USB branche
|
||||
//
|
||||
// CONCEPTS
|
||||
// midi.scd cree des MIDIFunc.cc(...) qui :
|
||||
// 1. Recoivent un CC du controller
|
||||
// 2. Mappent la valeur 0-127 sur une plage utile (linlin / linexp)
|
||||
// 3. Set la variable d'environnement (~kickAmp, ~melodyCutoff, ...)
|
||||
// 4. Appellent ~debouncedReload (50ms debounce -> evite le spam)
|
||||
//
|
||||
// Le mapping de defaut cible un Launch Control XL (8 fad + 8 pots),
|
||||
// adapte les numeros CC selon ton controller.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~reload.isNil) {
|
||||
"!!! engine pas charge -- evalue CHARGER TOUT dans 00_load.scd".postln;
|
||||
} {
|
||||
"engine OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] INIT MIDI -- lister les devices --------------------
|
||||
// Reproduit le 1er bloc de control/midi.scd. La console affiche les sources
|
||||
// et destinations. Si tu vois ton controller, c'est OK.
|
||||
(
|
||||
MIDIClient.init;
|
||||
"=== MIDI sources disponibles ===".postln;
|
||||
MIDIClient.sources.do { |src, i|
|
||||
(" [" ++ i ++ "] " ++ src.device ++ " : " ++ src.name).postln;
|
||||
};
|
||||
"=== MIDI destinations ===".postln;
|
||||
MIDIClient.destinations.do { |dst, i|
|
||||
(" [" ++ i ++ "] " ++ dst.device ++ " : " ++ dst.name).postln;
|
||||
};
|
||||
MIDIIn.connectAll;
|
||||
"=== MIDIIn.connectAll OK ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] MAPPING DEFAULT -- charger control/midi.scd --------
|
||||
// .load execute le 2e bloc de control/midi.scd qui cree ~midiFuncs
|
||||
// avec les 16 mappings standards (CC 13-20 = volumes, CC 29-36 =
|
||||
// filtres, CC 49-56 = wobble/sidechain, notes 36-42 = oneshot FX).
|
||||
(
|
||||
(~base ++ "control/midi.scd").load;
|
||||
)
|
||||
// -- la console doit afficher "=== MIDI MAPPING ACTIF ===".
|
||||
|
||||
|
||||
// --- [etape 3] Demarrer un beat pour entendre les changements -----
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
)
|
||||
// -- bouge tes potards : CC 13 = kickAmp, CC 29 = melodyCutoff, etc.
|
||||
|
||||
|
||||
// --- [etape 4] DEBUG -- afficher tous les CC recus ----------------
|
||||
// Utile pour decouvrir les numeros CC envoyes par TON controller.
|
||||
(
|
||||
~midiDebug = MIDIFunc.cc({ |val, num, chan|
|
||||
("[CC] " ++ num ++ " = " ++ val ++ " ch" ++ chan).postln;
|
||||
});
|
||||
"MIDI debug ON -- bouge un potard".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 5] Couper le debug -------------------------------------
|
||||
( ~midiDebug !? { ~midiDebug.free; ~midiDebug = nil }; "MIDI debug OFF".postln; )
|
||||
|
||||
|
||||
// --- [etape 6] STOP MIDI -- libere tous les MIDIFunc --------------
|
||||
(
|
||||
~midiFuncs !? { ~midiFuncs.do { |f| f.free }; ~midiFuncs = nil };
|
||||
~midiDebug !? { ~midiDebug.free; ~midiDebug = nil };
|
||||
"=== MIDI STOPPED ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] STOP global ----------------------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,87 @@
|
||||
// =====================================================================
|
||||
// examples/11_playlist_auto.scd -- Session auto playlist
|
||||
//
|
||||
// TITRE : Lancer plusieurs tracks d'affilee sans rien faire
|
||||
// DUREE : variable (selon la playlist choisie)
|
||||
// NIVEAU : debutant
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + ouvrir playlist.scd, evaluer son SETUP (1er bloc)
|
||||
//
|
||||
// CONCEPTS
|
||||
// ~playPlaylist.([[file, dur], ...]) joue chaque track pendant
|
||||
// "dur" secondes, puis crossfade vers la suivante.
|
||||
// Pendant que ca tourne, tu peux SKIP, PAUSE, RESUME.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~playPlaylist.isNil) {
|
||||
"!!! playlist.scd pas charge -- ouvre playlist.scd et evalue son SETUP".postln;
|
||||
} {
|
||||
"playlist.scd OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] PLAYLIST DEMO -- 4 tracks de 90s chacune (6 min) ----
|
||||
// Custom playlist courte pour tester. Pour les playlists 1h+ voir
|
||||
// playlist.scd (PLAYLIST INTEGRALE, DANCE FLOOR, CHILL, ...).
|
||||
(
|
||||
~playPlaylist.([
|
||||
["A_acid_journey.scd", 90],
|
||||
["F_trance_uplifter.scd", 90],
|
||||
["G_detroit_soulful.scd", 90],
|
||||
["W_dub_techno.scd", 90],
|
||||
]);
|
||||
)
|
||||
// -- la 1ere track demarre. Toutes les 90s, on enchaine la suivante
|
||||
// avec un crossfade.
|
||||
|
||||
|
||||
// --- [etape 2] INFO -- combien de synths actifs / CPU --------------
|
||||
// A relancer ponctuellement pendant la playlist.
|
||||
( ("synths actifs: " ++ s.numSynths ++ " | CPU: " ++ s.avgCPU.round(0.1) ++ "%").postln; )
|
||||
|
||||
|
||||
// --- [etape 3] PAUSE -- mute le master limiter ---------------------
|
||||
// Pratique pour repondre a un appel sans tout couper.
|
||||
( ~masterLim !? { ~masterLim.run(false) }; "[PAUSE]".postln; )
|
||||
|
||||
|
||||
// --- [etape 4] RESUME ---------------------------------------------
|
||||
( ~masterLim !? { ~masterLim.run(true) }; "[RESUME]".postln; )
|
||||
|
||||
|
||||
// --- [etape 5] SKIP TRACK -- passe a la suivante immediatement -----
|
||||
// Stop la track + tous les Pdef ; la playlist reprend le controle
|
||||
// et lance la track suivante au prochain tick.
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[SKIP] passage a la track suivante".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 6] STOP PLAYLIST ---------------------------------------
|
||||
// Stoppe la playlist, la track en cours, et les Pdef.
|
||||
(
|
||||
~playlist !? { ~playlist.stop; ~playlist = nil };
|
||||
~track !? { ~track.stop; ~track = nil };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== PLAYLIST STOPPED ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] (variantes) Lancer une playlist deja definie -------
|
||||
// Ouvre playlist.scd et evalue le bloc qui te plait :
|
||||
// - PLAYLIST INTEGRALE (~1h30 de tout)
|
||||
// - PLAYLIST DANCE FLOOR (~1h30 dansant)
|
||||
// - PLAYLIST CHILL (~1h ambient)
|
||||
// - PLAYLIST BASS MUSIC (~1h dubstep + dnb)
|
||||
// - PLAYLIST HARD (~50 min hardcore)
|
||||
// - PLAYLIST WORLD (~50 min asia + tribal)
|
||||
// - PLAYLIST RETRO (~30 min synthwave)
|
||||
// - PLAYLIST EXPERIMENTAL (~38 min glitch + drone)
|
||||
@@ -0,0 +1,126 @@
|
||||
// =====================================================================
|
||||
// examples/12_chord_progressions.scd -- Progressions d'accords
|
||||
//
|
||||
// TITRE : Generer melodie/harmonie depuis ~progXxx
|
||||
// DUREE : ~5 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd) -- charge automatiquement
|
||||
// palette/chords_progressions.scd via melodies/index.scd ?
|
||||
// NON -- il faut le charger separement :
|
||||
(
|
||||
(~base ++ "palette/chords_progressions.scd").load;
|
||||
)
|
||||
//
|
||||
// CONCEPTS
|
||||
// ~progXxx = [[c1n1, c1n2, c1n3], [c2n1, c2n2, c2n3], ...]
|
||||
// -- tableau d'accords, chaque accord = liste de notes MIDI
|
||||
// ~chordsToMelody.(prog, stepsPerChord) deroule la prog en melodie
|
||||
// ~chordsToHarmony.(prog, stepsPerChord) deroule la prog en harmony
|
||||
//
|
||||
// PROGRESSIONS DISPO : ~progIIVI ~progPop ~progSadPop ~progEpicMin
|
||||
// ~progAndalou ~progFlamenco ~progPhrygien ~progLydien ~progDorien
|
||||
// ~progHungar ~progHijaz ~progVietnam ~progHirajoshi ~progDetroit
|
||||
// ~progTrance ~progDnB ~progDubstep ~progSynthwave ~progAmbient
|
||||
// (voir palette/chords_progressions.scd pour la liste complete)
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 1] Demarrer un beat de base -------------------------
|
||||
(
|
||||
~kickAmp = 0.55; ~hatAmp = 0.18; ~melodyAmp = 0.18;
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Detroit prog -- soulful Cm-Eb-Ab-Bb -----------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progDetroit);
|
||||
~reload.value;
|
||||
"=== prog DETROIT ===".postln;
|
||||
)
|
||||
// -- on entend la melodie deroulee depuis la prog. Laisser 16-32 beats.
|
||||
|
||||
|
||||
// --- [etape 3] Trance prog (i-VII-VI-VII) --------------------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progTrance);
|
||||
~reload.value;
|
||||
"=== prog TRANCE ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 4] Pop prog (axis of awesome : I-V-vi-IV) -------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progPop);
|
||||
~reload.value;
|
||||
"=== prog POP ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 5] Andalouse prog (i-VI-III-VII en Am) -----------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progAndalou);
|
||||
~reload.value;
|
||||
"=== prog ANDALOU ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 6] Hijaz prog (gamme arabe) ----------------------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progHijaz);
|
||||
~reload.value;
|
||||
"=== prog HIJAZ ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] Synthwave prog (Am-F-G-Am 80s) ----------------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progSynthwave);
|
||||
~reload.value;
|
||||
"=== prog SYNTHWAVE ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 8] DnB prog (Em melodique) -----------------------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progDnB);
|
||||
~reload.value;
|
||||
"=== prog DnB ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 9] Empiler une harmonie en plus (depuis la meme prog) --
|
||||
// ~chordsToHarmony empile toutes les notes de chaque accord =>
|
||||
// genere des "stabs" d'accords joues a 1/4, par dessus la melodie.
|
||||
(
|
||||
~harmonyInst = \pad;
|
||||
~harmonyAmp = 0.16;
|
||||
~harmonyDur = 1.0; // 1 noir = 1 stab par beat
|
||||
~harmonyNotes = ~chordsToHarmony.(~progSynthwave);
|
||||
~reload.value;
|
||||
"=== harmony SYNTHWAVE empilee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 10] Trance + Trance harmony (full layered) -------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progTrance);
|
||||
~harmonyNotes = ~chordsToHarmony.(~progTrance);
|
||||
~reload.value;
|
||||
"=== prog TRANCE full layered ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 11] Couper l'harmonie ----------------------------------
|
||||
( ~harmonyAmp = 0; ~reload.value; "harmony OFF".postln; )
|
||||
|
||||
|
||||
// --- [etape 12] STOP global -----------------------------------------
|
||||
(
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,128 @@
|
||||
// =====================================================================
|
||||
// examples/13_world_ethno.scd -- Workflow oriental / world / asia
|
||||
//
|
||||
// TITRE : Construire un morceau ethnique
|
||||
// DUREE : ~6 minutes
|
||||
// NIVEAU : intermediaire
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd) charge synthdefs/asia.scd
|
||||
// + synthdefs/authentic.scd (taiko, didgeridoo, guzheng,
|
||||
// shakuhachi, tabla)
|
||||
// + palette/chords_progressions.scd pour ~progHijaz +
|
||||
// ~progVietnam (a charger separement) :
|
||||
(
|
||||
(~base ++ "palette/chords_progressions.scd").load;
|
||||
(~base ++ "palette/rhythm/sequences.scd").load;
|
||||
)
|
||||
//
|
||||
// PALETTE
|
||||
// asia : \koto \erhu \pipa \gong \growl \reeseHard
|
||||
// authentic : \didgeridoo \guzheng \shakuhachi \taiko \tabla
|
||||
// progressions : ~progHijaz ~progVietnam ~progHirajoshi
|
||||
// melodies : ~melodyByGenre.(\oriental | \asian | \tribal)
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 1] Demarrer un beat tribal de base --------------------
|
||||
// Kick lent + tabla sur les contre-temps.
|
||||
(
|
||||
~bpm = 92;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~kickAmp = 0.45; ~hatAmp = 0.0;
|
||||
~kickFreq = 50; ~kickDecay = 0.5;
|
||||
~percInst = \tabla; // tabla en lieu de rim/cowbell
|
||||
~percSteps = [0,0,1,0, 1,0,1,0, 0,1,0,1, 1,0,0,1]; ~percAmp = 0.4;
|
||||
~melodyAmp = 0.18;
|
||||
~reload.value;
|
||||
[\kickSeq, \percSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
"beat tribal en place".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Melodie au koto + scale orientale ------------------
|
||||
// ~m17 est une melodie asian dans palette/melodies/short.scd.
|
||||
(
|
||||
~melodyInst = \koto;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4;
|
||||
~melodyCutoff = 5500; ~melodyAmp = 0.2;
|
||||
~melodyNotes = ~m17.copy;
|
||||
~reload.value;
|
||||
"=== melodie KOTO -- ~m17 ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 3] Tirer une melodie aleatoire dans le bank \oriental --
|
||||
// ~melodyByGenre.(\oriental) lit ~melodyBank[\oriental] (10 melodies)
|
||||
// et applique une au hasard.
|
||||
( ~melodyByGenre.(\oriental); )
|
||||
// -- relancer plusieurs fois pour decouvrir d'autres melodies.
|
||||
|
||||
|
||||
// --- [etape 4] Couche basse au didgeridoo (drone bourdonnant) -----
|
||||
// On utilise la voix harmony : pose un drone profond sur la fond.
|
||||
(
|
||||
~harmonyInst = \didgeridoo;
|
||||
~harmonyAttack = 0.05; ~harmonyRelease = 1.5;
|
||||
~harmonyAmp = 0.22;
|
||||
~harmonyDur = 1.0;
|
||||
~enableHarmony.(\bassline); // genere une bassline depuis melody
|
||||
~reload.value;
|
||||
"=== didgeridoo bassline ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 5] Reemplacer perc par taiko -------------------------
|
||||
// Le taiko sonne plus martial, parfait pour buildup.
|
||||
(
|
||||
~percInst = \taiko;
|
||||
~percSteps = [1,0,0,1, 0,0,1,0, 1,0,0,1, 0,1,0,0]; ~percAmp = 0.5;
|
||||
~reload.value;
|
||||
"=== taiko perc ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 6] Melodie depuis prog Hijaz (gamme arabe) ------------
|
||||
// chordsToMelody deroule les notes des accords sur 32 pas.
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progHijaz);
|
||||
~melodyInst = \shakuhachi; // flute japonaise
|
||||
~reload.value;
|
||||
"=== shakuhachi -- prog HIJAZ ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 7] Melodie depuis prog Vietnam ------------------------
|
||||
(
|
||||
~melodyNotes = ~chordsToMelody.(~progVietnam);
|
||||
~melodyInst = \erhu; // violon chinois
|
||||
~melodyAttack = 0.2; ~melodyRelease = 0.6;
|
||||
~reload.value;
|
||||
"=== erhu -- prog VIETNAM ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 8] ~seqWorldEvolve -- sequence world toute prete ------
|
||||
// Avant : on coupe la rythmique, la sequence prend le controle.
|
||||
(
|
||||
[\kickSeq, \percSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
~seqWorldEvolve.();
|
||||
"=== seqWorldEvolve ===".postln;
|
||||
)
|
||||
// -- Routine de ~30s qui fait evoluer le mix world.
|
||||
|
||||
|
||||
// --- [etape 9] VCF formant -- voyelles pour le coté incantatoire --
|
||||
// live.scd doit avoir ete setup avant cette etape (sinon ~vcfOn nil).
|
||||
( ~vcfOn !? { ~vcfOn.(\formant, 0, 0.2) }; ) // 'a' large
|
||||
// -- changer de voyelle avec ~vcfSet
|
||||
( ~vcfSet !? { ~vcfSet.(\vowel, 2) }; ) // 'i' aigue
|
||||
( ~vcfSet !? { ~vcfSet.(\vowel, 3) }; ) // 'o' rond
|
||||
( ~vcfOff !? { ~vcfOff.() }; )
|
||||
|
||||
|
||||
// --- [etape 10] STOP global ----------------------------------------
|
||||
(
|
||||
~seqStop !? { ~seqStop.() };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,114 @@
|
||||
// =====================================================================
|
||||
// examples/14_fx_chains_dynamic.scd -- FX bus dynamique
|
||||
//
|
||||
// TITRE : Bus FX en send + LFO sur params FX + presets
|
||||
// DUREE : ~6 minutes
|
||||
// NIVEAU : avance
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + ouvrir fx_bus.scd, evaluer son SETUP (3 blocs en haut)
|
||||
//
|
||||
// ATTENTION
|
||||
// fx_bus.scd a une signature different de live.scd :
|
||||
// ~send.(fxName, amount) -- envoie LE BUS 0 ENTIER vers le FX
|
||||
// (donc tout le mix passe dedans)
|
||||
// ~setFx.(fxName, key, val) -- modifie un parametre du FX
|
||||
// ~lfo.(fxName, key, rate, lo, hi, shape) -- LFO sur un param FX
|
||||
//
|
||||
// FX dispos : \rev \dly \chr \phs \flg \crsh \tape \shim \dist
|
||||
// Presets : \dub \space \trance \dubstep \retro \industrial
|
||||
// \dream \cosmic \drone \dry
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] Verification ----------------------------------------
|
||||
(
|
||||
if (~send.isNil or: { ~fxFx.isNil }) {
|
||||
"!!! fx_bus.scd pas charge -- ouvre fx_bus.scd et evalue ses 3 SETUP".postln;
|
||||
} {
|
||||
"fx_bus.scd OK".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 1] Demarrer un beat de base ----------------------------
|
||||
(
|
||||
~kickAmp = 0.55; ~hatAmp = 0.18; ~melodyAmp = 0.18; ~acidAmp = 0.32;
|
||||
~melodyInst = \lead;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \acidSeq, \melodySeq].do { |k| Pdef(k).play };
|
||||
"beat lance".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 2] Preset DUB -- reverb hall + delay long + tape ------
|
||||
( ~fxPreset.(\dub); )
|
||||
// -- on entend tout le mix prendre une couleur dub. Laisser 16 beats.
|
||||
|
||||
|
||||
// --- [etape 3] Reverb seule a 40% ---------------------------------
|
||||
// ~send.(fxName, amount) avec amount = 0.4 -> 40% du mix part dans
|
||||
// le bus reverb (reste 100% en dry).
|
||||
( ~send.(\rev, 0.4); )
|
||||
|
||||
// Couper le delay du preset DUB (pour ne garder que la reverb)
|
||||
( ~send.(\dly, 0); )
|
||||
( ~send.(\tape, 0); )
|
||||
|
||||
|
||||
// --- [etape 4] Delay 1/8 (375ms) avec feedback 50% ---------------
|
||||
(
|
||||
~send.(\dly, 0.3);
|
||||
~setFx.(\dly, \delayTime, 0.375); // 1/8 a 120 BPM
|
||||
~setFx.(\dly, \feedback, 0.5);
|
||||
"delay 1/8 fb 50%".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [etape 5] LFO sur le feedback du delay -----------------------
|
||||
// ~lfo.(fxName, param, rateHz, lo, hi, shape)
|
||||
// Le feedback oscille entre 30% et 80% a 0.2Hz (cycle 5s).
|
||||
( ~lfo.(\dly, \feedback, 0.2, 0.3, 0.8, \sin); )
|
||||
// -- on entend le delay grossir/decroitre. Laisser tourner 30s.
|
||||
|
||||
|
||||
// --- [etape 6] Stop le LFO sur ce param ---------------------------
|
||||
( ~lfoStop.(\dly, \feedback); )
|
||||
|
||||
|
||||
// --- [etape 7] Reverb FREEZE -- nappe figee infinie ---------------
|
||||
( ~setFx.(\rev, \freeze, 1); "REV FREEZE ON".postln; )
|
||||
|
||||
// ... ecoute la nappe, joue avec d'autres params
|
||||
|
||||
( ~setFx.(\rev, \freeze, 0); "REV FREEZE OFF".postln; )
|
||||
|
||||
|
||||
// --- [etape 8] Tap tempo -- ajuste le delay au tempo qu'on tape ---
|
||||
// Tape ~tap au moins 3 fois pour calibrer ; il calcule la moyenne
|
||||
// des intervalles et ajuste ~setFx.(\dly, \delayTime, ...).
|
||||
( ~tap.(); )
|
||||
( ~tap.(); )
|
||||
( ~tap.(); )
|
||||
( ~tap.(); )
|
||||
|
||||
|
||||
// --- [etape 9] Preset SPACE -- shimmer + reverb + chorus ----------
|
||||
( ~fxPreset.(\space); )
|
||||
|
||||
|
||||
// --- [etape 10] Preset INDUSTRIAL -- distortion + flanger -------
|
||||
( ~fxPreset.(\industrial); )
|
||||
|
||||
|
||||
// --- [etape 11] Preset DRY -- mute tous les sends -----------------
|
||||
( ~fxPreset.(\dry); )
|
||||
|
||||
|
||||
// --- [etape 12] STOP global ----------------------------------------
|
||||
(
|
||||
~lfoStopAll !? { ~lfoStopAll.() };
|
||||
~fxPreset.(\dry);
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"=== STOP ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,274 @@
|
||||
// =====================================================================
|
||||
// examples/15_full_live_set.scd -- Set live complet 30 minutes
|
||||
//
|
||||
// TITRE : Performance live structuree avec tous les outils
|
||||
// DUREE : ~30 minutes
|
||||
// NIVEAU : avance
|
||||
// PREREQUIS : CHARGER TOUT (00_load.scd)
|
||||
// + SETUP de live.scd (~drop ~breakdown ~vcfOn ...)
|
||||
// + SETUP de fx_bus.scd (~send ~fxPreset)
|
||||
// + SETUP de mixer.scd (~mixPreset ~setVol ~mute)
|
||||
// + SETUP de scenes.scd (~saveScene ~loadScene)
|
||||
//
|
||||
// STRUCTURE DU SET (timeline en minutes)
|
||||
// 00:00 INTRO drone + ambient + buildup (4 min)
|
||||
// 04:00 DROP 1 techno minimal (6 min) avec mute/solo/tweaks
|
||||
// 10:00 ACID multi-mel + LFO cutoff + drop (6 min)
|
||||
// 16:00 BREAKDOWN chord prog + reverb tail (4 min)
|
||||
// 20:00 DROP 2 hard kit + bitcrush + glitch (4 min)
|
||||
// 24:00 TRANCE seqBuildup + seqDrop final (3 min)
|
||||
// 27:00 OUTRO masterFadeOut 4 min
|
||||
//
|
||||
// CONVENTION
|
||||
// Tu evalues UN BLOC a chaque transition (les tags [00:00] etc.
|
||||
// indiquent le temps suggere). Entre les blocs, tu fais des tweaks
|
||||
// libres (changer ~melodyCutoff, lancer un ~drop, etc.).
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- [etape 0] VERIFICATIONS ---------------------------------------
|
||||
(
|
||||
var ok = true;
|
||||
if (~reload.isNil) { "!!! engine pas charge".postln; ok = false };
|
||||
if (~drop.isNil) { "!!! live.scd SETUP manquant".postln; ok = false };
|
||||
if (~send.isNil) { "!!! fx_bus.scd SETUP manquant".postln; ok = false };
|
||||
if (~mixPreset.isNil) { "!!! mixer.scd SETUP manquant".postln; ok = false };
|
||||
if (~saveScene.isNil) { "!!! scenes.scd SETUP manquant".postln; ok = false };
|
||||
if (ok) { "=== TOUS LES MODULES SONT PRETS ===".postln };
|
||||
)
|
||||
|
||||
|
||||
// --- [00:00] INTRO -- drone + ambient + buildup -------------------
|
||||
// On part d'un mix vide, on monte progressivement.
|
||||
// masterVol bas + reverb saturee = ambiance ouverture.
|
||||
(
|
||||
~bpm = 124; TempoClock.default.tempo = ~bpm / 60;
|
||||
~kickAmp = 0; ~hatAmp = 0; ~snareAmp = 0; ~clapAmp = 0; ~percAmp = 0;
|
||||
~acidAmp = 0; ~melodyAmp = 0; ~harmonyAmp = 0;
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.8; ~melodyRelease = 2.0; ~melodyCutoff = 1500;
|
||||
~harmonyInst = \drone;
|
||||
~harmonyAttack = 1.0; ~harmonyRelease = 3.0; ~harmonyAmp = 0.0;
|
||||
~harmonyNotes = [36,0,0,0,0,0,0,0, 36,0,0,0,0,0,0,0,
|
||||
36,0,0,0,0,0,0,0, 36,0,0,0,0,0,0,0];
|
||||
~melodyNotes = ~m33.copy; // melodie ambient
|
||||
~reload.value;
|
||||
[\melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~fxPreset.(\space); // shimmer + reverb + chorus
|
||||
"=== [00:00] INTRO -- drone + ambient ===".postln;
|
||||
)
|
||||
// -- monter doucement ~melodyAmp et ~harmonyAmp en quelques etapes :
|
||||
// attendre 30s avant le bloc suivant.
|
||||
|
||||
( ~melodyAmp = 0.10; ~harmonyAmp = 0.18; ~reload.value; ) // [00:30]
|
||||
( ~melodyAmp = 0.16; ~harmonyAmp = 0.22; ~reload.value; ) // [01:30]
|
||||
|
||||
|
||||
// --- [03:30] BUILDUP vers le drop techno -- 30s ------------------
|
||||
// Snare roll + filtre qui s'ouvre + masterFadeIn.
|
||||
(
|
||||
~buildup.(30); // helper de live.scd : snare roll + open filter
|
||||
~saveScene.(\preDrop1); // au cas ou
|
||||
"=== [03:30] BUILDUP -- 30s ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [04:00] DROP 1 -- TECHNO MINIMAL -----------------------------
|
||||
// Kit techno pur 4/4, melody en lead, ~mixPreset \drop.
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 55; ~kickDecay = 0.32; ~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~snareSteps = (0 ! 16); ~clapSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~melodyInst = \lead;
|
||||
~melodyAttack = 0.012; ~melodyRelease = 0.25; ~melodyCutoff = 2400;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = ~m1.copy;
|
||||
~harmonyAmp = 0.10;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~fxPreset.(\trance); // rev + delay 1/8 + chorus
|
||||
~mixPreset.(\drop);
|
||||
~saveScene.(\drop1);
|
||||
"=== [04:00] DROP 1 -- TECHNO MINIMAL ===".postln;
|
||||
)
|
||||
// -- laisser tourner 1 minute, puis tweaks libres :
|
||||
// ( ~mute.(\hat); ) ;; couper le hat 16 beats
|
||||
// ( ~unmute.(\hat); )
|
||||
// ( ~setVol.(\acid, 1.4); ) ;; pousser l'acid
|
||||
// ( ~drop.(4); ) ;; mini-drop interne
|
||||
|
||||
|
||||
// --- [07:00] VARIATIONS DROP 1 -- mute / solo --------------------
|
||||
( ~mute.(\hat); ) // hat coupee
|
||||
// -- 8 beats
|
||||
( ~unmute.(\hat); )
|
||||
( ~focus.(\melody, 0.4); ) // melodie en avant, autres a 40%
|
||||
// -- 16 beats
|
||||
( ~unfocus.(); )
|
||||
|
||||
|
||||
// --- [08:00] LFO sur le cutoff de la melodie ---------------------
|
||||
( ~lfoTo.(\melodyCutoff, 0.25, 2000, \sin, 3500); )
|
||||
// -- la melodie respire lentement (cycle 4s).
|
||||
|
||||
|
||||
// --- [09:30] mini drop interne avant la transition ACID ----------
|
||||
( ~drop.(4); )
|
||||
|
||||
|
||||
// --- [10:00] TRANSITION VERS ACID --------------------------------
|
||||
// On stoppe le LFO, on bascule sur \saw3 + acid, on enclenche
|
||||
// le systeme multi-pistes melodiques.
|
||||
(
|
||||
~lfoStopVar.(\melodyCutoff);
|
||||
~melodyInst = \saw3; ~melodyAmp = 0.18;
|
||||
~acidAmp = 0.32;
|
||||
~acidNotes = [36,36,48,36,39,36,43,39, 36,41,36,39,43,36,36,41];
|
||||
~acidSlides = [0,0,1,0,0,0,0,1, 0,0,0,1,0,0,0,0];
|
||||
~melodyNotes = ~m29.copy; // melodie acid
|
||||
~reload.value;
|
||||
Pdef(\acidSeq).play;
|
||||
~mixPreset.(\acidFocus);
|
||||
"=== [10:00] ACID JOURNEY ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [11:00] Multi-piste : ajouter m2 en pluck contrer la mel ----
|
||||
// m2 est preconfiguree dans melodies/tracks.scd ; on la lance et
|
||||
// on lui colle une counter-melody.
|
||||
(
|
||||
~melTrackSet.(\m2, \inst, \pluck);
|
||||
~melTrackSet.(\m2, \notes, ~m25.copy);
|
||||
~melTrackSet.(\m2, \pan, -0.4);
|
||||
~melTrackOn.(\m2);
|
||||
"=== m2 counter pluck ON ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [12:00] LFO drunk sur le BPM -- subtile derive --------------
|
||||
( ~lfoTo.(\bpm, 0.05, 6, \drunk, 132); )
|
||||
|
||||
|
||||
// --- [14:00] Drop interne (acid section) -------------------------
|
||||
( ~drop.(4); )
|
||||
|
||||
|
||||
// --- [15:30] BREAKDOWN -- chord prog + reverb tail ---------------
|
||||
// On stoppe le LFO + acid + m2, on fait un breakdown.
|
||||
(
|
||||
~lfoStopVar.(\bpm);
|
||||
TempoClock.default.tempo = 124 / 60; ~bpm = 124;
|
||||
~melTrackOff.(\m2);
|
||||
Pdef(\acidSeq).stop;
|
||||
Pdef(\hatSeq).stop;
|
||||
~breakdown.(8);
|
||||
"=== [15:30] BREAKDOWN ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [16:00] CHORDS PROGRESSION -- Synthwave + harmony ----------
|
||||
// chordsToMelody + chordsToHarmony pour empiler une nappe.
|
||||
(
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 3500;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = ~chordsToMelody.(~progSynthwave);
|
||||
~harmonyInst = \strings;
|
||||
~harmonyAttack = 0.5; ~harmonyRelease = 2.0; ~harmonyAmp = 0.16;
|
||||
~harmonyDur = 1.0;
|
||||
~harmonyNotes = ~chordsToHarmony.(~progSynthwave);
|
||||
~kickAmp = 0; // pas de kick pendant le breakdown
|
||||
~reload.value;
|
||||
~fxPreset.(\dream);
|
||||
~mixPreset.(\breakdown);
|
||||
"=== [16:00] CHORDS SYNTHWAVE ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [18:00] REVERB TAIL puis BUILDUP final --------------------
|
||||
( ~reverbTail.(8); ) // [18:00] tail 8s
|
||||
( ~buildup.(30); ~saveScene.(\preDrop2); ) // [18:30] buildup 30s
|
||||
|
||||
|
||||
// --- [20:00] DROP 2 -- HARD kit + bitcrush -----------------------
|
||||
// Kit hardcore + bitcrush en send + masterSat.
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.7;
|
||||
~kickFreq = 60; ~kickDecay = 0.25; ~kickDrive = 3.0; ~kickClick = 0.3;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.4;
|
||||
~melodyInst = \hardLead; ~melodyAmp = 0.22; ~melodyDrive = 3.0;
|
||||
~melodyNotes = ~m67.copy; // melodie hardcore
|
||||
~harmonyAmp = 0.0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \clapSeq, \melodySeq].do { |k| Pdef(k).play };
|
||||
~fxPreset.(\industrial);
|
||||
~satOn !? { ~satOn.(0.4) }; // master saturation legere
|
||||
~mixPreset.(\hardcore);
|
||||
~saveScene.(\drop2);
|
||||
"=== [20:00] DROP 2 -- HARD ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [22:00] GLITCH + bitcrush moments ---------------------------
|
||||
( ~glitch.(2); )
|
||||
// -- 8 beats
|
||||
( ~bitCrushNow.(6, 8000, 1); )
|
||||
// -- 8 beats
|
||||
( ~stutter.(8, 1); )
|
||||
// -- 8 beats
|
||||
( ~freeze.(4); )
|
||||
|
||||
|
||||
// --- [24:00] TRANSITION TRANCE -- seqBuildup + seqDrop -----------
|
||||
// On stoppe les Pdef pour laisser ~seqXxx prendre le controle.
|
||||
(
|
||||
~satOff !? { ~satOff.() };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
~bpm = 138; TempoClock.default.tempo = ~bpm / 60;
|
||||
~melodyInst = \supersaw;
|
||||
~melodyNotes = ~chordsToMelody.(~progTrance);
|
||||
~reload.value;
|
||||
~fxPreset.(\trance);
|
||||
"=== [24:00] TRANCE -- seqBuildup ===".postln;
|
||||
)
|
||||
( ~seqBuildup.(16); ) // 16 mesures crescendo
|
||||
|
||||
|
||||
// --- [26:00] DROP TRANCE FINAL -----------------------------------
|
||||
( ~seqDrop.(); )
|
||||
// -- attendre la fin de la sequence puis relancer un beat.
|
||||
(
|
||||
[\kickSeq, \hatSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~mixPreset.(\trance);
|
||||
~saveScene.(\dropFinal);
|
||||
"=== [26:00] TRANCE FINAL ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- [27:00] OUTRO -- masterFadeOut 4 minutes -------------------
|
||||
// ~masterFadeOut diminue masterVol vers 0 sur dur secondes.
|
||||
// On laisse les Pdef tourner ; le silence vient progressivement.
|
||||
(
|
||||
~masterFadeOut.(240);
|
||||
"=== [27:00] OUTRO -- fade-out 4 min ===".postln;
|
||||
)
|
||||
// -- patience : 4 minutes pour atteindre 0. Tu peux profiter.
|
||||
|
||||
|
||||
// --- [31:00] STOP TOTAL -----------------------------------------
|
||||
// Apres le fade, libere tout proprement.
|
||||
(
|
||||
~lfoStopAllVars !? { ~lfoStopAllVars.() };
|
||||
~lfoStopAll !? { ~lfoStopAll.() };
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~melTrackChoke !? { ~melTrackChoke.() };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
~track !? { ~track.stop };
|
||||
~masterLim !? { ~masterLim.free; ~masterLim = nil };
|
||||
~scBus !? { ~scBus.free; ~scBus = nil };
|
||||
"=== SET TERMINE -- merci ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,63 @@
|
||||
# live/ — API live performance
|
||||
|
||||
Helpers pour mixer, FX, scenes, loops, tweaks, melodies live.
|
||||
Charges via `00_load.scd` puis SETUP bloc par bloc.
|
||||
|
||||
## Notation d'appel (CRITIQUE)
|
||||
|
||||
SuperCollider Event pseudo-method ne passe PAS les args :
|
||||
|
||||
```supercollider
|
||||
~m.short.(50) // FAUX : ~m est passe comme 1er arg, 50 perdu
|
||||
~m[\short].(50) // OK : notation indexee
|
||||
~mShort.(50) // OK : variable env directe (alias prefere)
|
||||
~mm.(50) // OK : alias court
|
||||
```
|
||||
|
||||
Toute API exposee via `~xxx` doit avoir un wrapper env direct,
|
||||
pas seulement une cle dans un dict.
|
||||
|
||||
## Patterns
|
||||
|
||||
- Chaque module expose un dict catalogue (`~m`, `~fx`, `~ch`, ...)
|
||||
ET des wrappers env directs (`~mShort`, `~fxRev`, ...).
|
||||
- SETUP en commentaire en haut du fichier, exemples en bas.
|
||||
- VCF/FX inserent via `ReplaceOut.ar(busIn, ...)` (chain in-place).
|
||||
- Sidechain : duck = `1 - (In.kr(scBus, 1) * scAmt)`.
|
||||
|
||||
## 5 namespaces (cf `01_live.scd`)
|
||||
|
||||
| Dict | Wrappers directs | Domaine |
|
||||
| --- | --- | --- |
|
||||
| `~kk.(\genre)` | `~kPat`, `~kTim`, `~kList` | Kicks (techno/gabber/dub/...) |
|
||||
| `~mm.(N)` | `~mLong`, `~mXlong`, `~mEpic`, `~mRnd`, `~mGen`, `~mNx`, `~mPv`, `~mInst`, `~mHarm`, `~mAmp`, `~mCut`, `~mDrive`, `~mOff` | Melodies |
|
||||
| `~ff.(\preset)` | `~fxSnd`, `~fxSt`, `~fxFreeze`, `~fxDrop`, `~fxBreakdown`, `~fxBuildup`, `~fxGlitch`, `~fxStutter`, `~fxVcfOn`, `~fxLfo`, `~fxCut`, `~fxRq`, `~fxDrive`, `~fxComp`, `~fxSat` | FX presets + tricks |
|
||||
| `~cc` | `~chIntro`, `~chDrop`, `~chBreakdown`, `~chBuildup`, `~chTechno`, `~chDnb`, `~chOutroFade`, `~chStop` | Chains/sequences |
|
||||
| `~p` | `~pKit`, `~pGenre`, `~pHat`, `~pSnare`, `~pClap`, `~pPerc`, `~pList` | Patterns rythmiques |
|
||||
|
||||
Mixer : `~setVol`, `~mute`, `~solo`, `~mixPreset`, `~saveMix`, `~masterVol`, `~masterFade`.
|
||||
LFO/VCF : `~lfoTo`, `~vcfOn`. Loops : `~loopOn`. Scenes : `~saveScene`, `~loadScene`.
|
||||
|
||||
## Convention de renommage (clefs courtes = collisions Object/Server)
|
||||
|
||||
Noms reserves SC (`s`=Server, `next`/`prev`/`set`/`send`/`tap`/`p`/`t`/`e`/`l`)
|
||||
plantent comme cles d'Event. Renommages internes :
|
||||
|
||||
| Ancien | Nouveau |
|
||||
| --- | --- |
|
||||
| `.p` | `.pat` |
|
||||
| `.t` | `.tim` |
|
||||
| `.s` | `.short` |
|
||||
| `.l` | `.long` |
|
||||
| `.x` | `.xlong` |
|
||||
| `.e` | `.epic` |
|
||||
| `.r` | `.rnd` |
|
||||
| `.next` / `.prev` | `.nx` / `.pv` |
|
||||
| `.send` / `.set` / `.tap` | `.snd` / `.st` / `.tp` |
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Ne pas appeler `~dict.key.(args)` -- les args sont avales
|
||||
- Ne pas oublier le wrapper env direct (`~mShort`) en plus de la cle
|
||||
- Ne pas charger live/*.scd avant `engine.scd` + `fx_bus.scd`
|
||||
- Ne pas mute un `~xxx` sans `~reload.value` si lie a un Pdef
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
// =====================================================================
|
||||
// live/_load.scd -- CHARGEMENT COMPLET LIVE en un Cmd+Entree
|
||||
//
|
||||
// IDEMPOTENT : detecte si le bootstrap a deja tourne (via ~setupAll_done)
|
||||
// et ne refait pas le travail inutilement.
|
||||
//
|
||||
// Fait :
|
||||
// 1. Set ~base si nil
|
||||
// 2. Si pas deja boote : charge engine + synthdefs + scales + melodies
|
||||
// + harmonics + setup.scd, puis ~setupAll.()
|
||||
// (~setupAll charge fx_bus / live / mixer / scenes / loops / fills /
|
||||
// sequences / jump + les 5 wrappers ~kk/~mm/~ff/~cc/~p)
|
||||
// 3. Polling sur ~kk (defini en DERNIER par liveSetup async) pour
|
||||
// confirmer que tout est charge
|
||||
// 4. Ouvre les fichiers essentiels dans l'editeur SC
|
||||
// 5. Affiche "=== LIVE READY ==="
|
||||
//
|
||||
// Utilisation :
|
||||
// (~base ++ "live/_load.scd").load;
|
||||
// OU
|
||||
// "/Users/electron/Documents/Projets_Creatifs/sound_algo/live/_load.scd".load;
|
||||
// =====================================================================
|
||||
(
|
||||
~base = ~base ?? { "/Users/electron/Documents/Projets_Creatifs/sound_algo/" };
|
||||
|
||||
Routine({
|
||||
var maxWait = 30, waited = 0;
|
||||
|
||||
if (~setupAll_done == true and: { ~kk.notNil }) {
|
||||
"[live/_load] bootstrap deja fait, skip".postln;
|
||||
} {
|
||||
// --- 1. Modules .load-compatibles -------------------------------
|
||||
"[live/_load] engine + synthdefs + palette ...".postln;
|
||||
(~base ++ "engine.scd").load;
|
||||
(~base ++ "synthdefs/asia.scd").load;
|
||||
(~base ++ "synthdefs/extra.scd").load;
|
||||
(~base ++ "synthdefs/authentic.scd").load;
|
||||
(~base ++ "palette/scales.scd").load;
|
||||
(~base ++ "palette/melodies/index.scd").load;
|
||||
(~base ++ "palette/harmonics/index.scd").load;
|
||||
|
||||
// --- 2. setup.scd : definit ~check / ~setupAll / ~teardown -----
|
||||
"[live/_load] setup.scd ...".postln;
|
||||
(~base ++ "setup.scd").load;
|
||||
|
||||
// --- 3. ~setupAll : boot serveur + charge tous modules live + --
|
||||
// les 5 wrappers (~kk / ~mm / ~ff / ~cc / ~p)
|
||||
// liveSetup tourne dans s.waitForBoot{}, donc async.
|
||||
"[live/_load] ~setupAll (boot + modules live + wrappers) ...".postln;
|
||||
~setupAll.();
|
||||
|
||||
// --- 4. Polling : ~kk est defini en DERNIER par liveSetup ------
|
||||
// (apres tous les autres modules + apres ~loadFirstBlock kicks).
|
||||
// Quand ~kk est non-nil, liveSetup a TOUT charge.
|
||||
while { ~kk.isNil and: { waited < maxWait } } {
|
||||
0.2.wait;
|
||||
waited = waited + 0.2;
|
||||
};
|
||||
if (~kk.isNil) {
|
||||
("[live/_load] !! timeout " ++ maxWait
|
||||
++ "s sur ~kk. liveSetup a peut-etre echoue.").postln;
|
||||
} {
|
||||
~setupAll_done = true;
|
||||
};
|
||||
};
|
||||
|
||||
if (s.serverRunning) { s.sync };
|
||||
|
||||
// --- 5. Ouvrir les fichiers essentiels dans l'editeur SC ------------
|
||||
// Document.open est IDE-only (ScIDE classique). En sclang CLI ou
|
||||
// dans certaines extensions VSCode, la classe Document n'existe
|
||||
// pas -> on skip silencieusement avec try{}.
|
||||
// Ouvrir les fichiers essentiels dans l'editeur SC -- si Document
|
||||
// est dispo. La classe Document n'existe pas en sclang CLI ni dans
|
||||
// certaines extensions VSCode (pas de Qt charge) -> on skip.
|
||||
{
|
||||
var docClass = \Document.asClass;
|
||||
if (docClass.notNil) {
|
||||
"[live/_load] ouverture des fichiers essentiels dans l'IDE ...".postln;
|
||||
[
|
||||
"01_live.scd", // tableau de bord live
|
||||
"live/kicks.scd", // ~kk
|
||||
"live/melodies.scd", // ~mm
|
||||
"live/fx.scd", // ~ff
|
||||
"live/chains.scd", // ~cc
|
||||
"live/patterns.scd", // ~p
|
||||
"live/live_fx_panel.scd", // panneau FX exhaustif
|
||||
"live/mixer.scd", // ~setVol / ~mixPreset
|
||||
"live/scenes.scd", // ~saveScene / ~loadScene
|
||||
"live/tweaks.scd", // tweaks Cmd+Entree par bloc
|
||||
"control/jump.scd", // ~jumpTo
|
||||
"palette/rhythm/fills.scd", // ~snareFill / ~tomFill
|
||||
].do { |path|
|
||||
var full = ~base ++ path;
|
||||
if (File.exists(full)) {
|
||||
try { docClass.perform(\open, full) } { |err|
|
||||
(" [skip Document.open] " ++ path).postln;
|
||||
};
|
||||
} { (" [skip] " ++ path ++ " inexistant").postln };
|
||||
};
|
||||
} {
|
||||
"[live/_load] Document indisponible (sclang CLI ou VSCode sans IDE) -- skip ouverture".postln;
|
||||
};
|
||||
}.value;
|
||||
|
||||
"".postln;
|
||||
"=== LIVE READY ===".postln;
|
||||
" Wrappers : ~kk(kicks) ~mm(melodies) ~ff(fx) ~cc(chains) ~p(patterns)".postln;
|
||||
" Mixer : ~setVol ~mute ~solo ~mixPreset ~masterVol".postln;
|
||||
" Live : ~lfoTo ~vcfOn ~drop ~breakdown ~buildup".postln;
|
||||
" Scenes : ~saveScene ~loadScene ~listScenes".postln;
|
||||
" Jump : ~jumpTo.(\\X, \\section_slug)".postln;
|
||||
" Status : ~check.()".postln;
|
||||
" Stop : ~teardown.()".postln;
|
||||
" -> ouvre 01_live.scd pour les blocs Cmd+Entree prets a l'emploi".postln;
|
||||
}).play(AppClock);
|
||||
)
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
// =====================================================================
|
||||
// live/chains.scd -- CHAINS / SEQUENCES LIVE (API ultra-courte)
|
||||
//
|
||||
// ATTENTION SC -- noter la notation des appels :
|
||||
//
|
||||
// NE MARCHE PAS : ~ch.drop.() ou ~cc.drop.()
|
||||
// -> SC passe l'event ~ch comme 1er arg, et les vrais args sont
|
||||
// PERDUS (test empirique sur SC 3.14.1).
|
||||
// -> Pour les fonctions sans args (~ch[\drop]), l'effet visible
|
||||
// peut etre OK, MAIS pour celles avec args (~ch[\buildup].(8))
|
||||
// l'arg est silencieusement perdu.
|
||||
//
|
||||
// MARCHE BIEN : ~ch[\drop].() (notation indexee)
|
||||
// ~chDrop.() (variable env directe)
|
||||
//
|
||||
// ~ch // dict catalogue
|
||||
// ~ch[\intro], [\drop], [\breakdown], [\buildup], [\outro]
|
||||
// ~ch[\techno], [\acid], [\dubstep], [\trance], [\dnb], [\hiphop], [\world]
|
||||
// ~ch[\stop], [\custom]
|
||||
// ~ch[\full][\intro2drop], [\dropToBreak], [\outroFade]
|
||||
// ~ch[\list].()
|
||||
//
|
||||
// RACCOURCIS env (API utilisateur primaire) :
|
||||
// ~chIntro, ~chDrop, ~chBreakdown, ~chBuildup, ~chOutro
|
||||
// ~chTechno, ~chAcid, ~chDubstep, ~chTrance, ~chDnb, ~chHiphop, ~chWorld
|
||||
// ~chStop, ~chCustom
|
||||
// ~chIntro2drop, ~chDropToBreak, ~chOutroFade
|
||||
// ~chList
|
||||
// ~cc -- alias env directe vers le dict (toujours valable pour
|
||||
// inspecter, mais pour APPELS utiliser les ~chXxx)
|
||||
//
|
||||
// Tous les wrappers gardes par ~helper !? { ... }.
|
||||
//
|
||||
// PREREQUIS : engine + palette/rhythm/sequences.scd + live/mixer.scd
|
||||
// charges (ou setupAll).
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
~ch = ();
|
||||
|
||||
// --- SECTIONS de track ---------------------------------------------
|
||||
~ch[\intro] = { ~seqIntro !? { ~seqIntro.() } };
|
||||
~ch[\drop] = { ~seqDrop !? { ~seqDrop.() } };
|
||||
~ch[\breakdown] = { ~seqBreakdown !? { ~seqBreakdown.() } };
|
||||
~ch[\buildup] = { |bars = 8| ~seqBuildup !? { ~seqBuildup.(bars) } };
|
||||
~ch[\outro] = { ~seqOutro !? { ~seqOutro.() } };
|
||||
|
||||
// --- LOOPS / EVOLUTIONS par genre ----------------------------------
|
||||
~ch[\techno] = { |repeats = 4| ~seqTechnoLoop !? { ~seqTechnoLoop.(repeats) } };
|
||||
~ch[\acid] = { ~seqAcidEvolve !? { ~seqAcidEvolve.() } };
|
||||
~ch[\dubstep] = { ~seqDubstepDrop !? { ~seqDubstepDrop.() } };
|
||||
~ch[\trance] = { ~seqTrance16 !? { ~seqTrance16.() } };
|
||||
~ch[\dnb] = { |repeats = 4| ~seqDnBSwitch !? { ~seqDnBSwitch.(repeats) } };
|
||||
~ch[\hiphop] = { |repeats = 8| ~seqHipHopLoop !? { ~seqHipHopLoop.(repeats) } };
|
||||
~ch[\world] = { ~seqWorldEvolve !? { ~seqWorldEvolve.() } };
|
||||
|
||||
// --- STOP / CUSTOM --------------------------------------------------
|
||||
~ch[\stop] = { ~seqStop !? { ~seqStop.() } };
|
||||
~ch[\custom] = { |actions| ~seqPlay !? { ~seqPlay.(actions) } };
|
||||
|
||||
// --- COMBOS pre-faits (enchaines) -----------------------------------
|
||||
~ch[\full] = ();
|
||||
|
||||
~ch[\full][\intro2drop] = { |introDur = 4, buildDur = 4|
|
||||
Routine({
|
||||
~seqIntro !? { ~seqIntro.() };
|
||||
introDur.wait;
|
||||
~seqBuildup !? { ~seqBuildup.(buildDur) };
|
||||
(buildDur * ~stepDur ? 0.25).wait;
|
||||
~seqDrop !? { ~seqDrop.() };
|
||||
}).play(TempoClock.default);
|
||||
"[ch.full.intro2drop] intro -> buildup -> drop".postln;
|
||||
};
|
||||
|
||||
~ch[\full][\dropToBreak] = { |breakDur = 8|
|
||||
Routine({
|
||||
~seqDrop !? { ~seqDrop.() };
|
||||
4.wait;
|
||||
~seqBreakdown !? { ~seqBreakdown.() };
|
||||
breakDur.wait;
|
||||
~seqDrop !? { ~seqDrop.() };
|
||||
}).play(TempoClock.default);
|
||||
"[ch.full.dropToBreak] drop -> break -> drop".postln;
|
||||
};
|
||||
|
||||
~ch[\full][\outroFade] = { |dur = 12|
|
||||
~seqOutro !? { ~seqOutro.() };
|
||||
~masterFadeOut !? { ~masterFadeOut.(dur) };
|
||||
("[ch.full.outroFade] outro + fade " ++ dur ++ "s").postln;
|
||||
};
|
||||
|
||||
// --- LISTE ----------------------------------------------------------
|
||||
~ch[\list] = {
|
||||
"=== ~ch -- CHAINS / SEQUENCES ===".postln;
|
||||
" sections : ~chIntro / ~chDrop / ~chBreakdown / ~chBuildup / ~chOutro".postln;
|
||||
" loops : ~chTechno / ~chAcid / ~chDubstep / ~chTrance / ~chDnb / ~chHiphop / ~chWorld".postln;
|
||||
" stop : ~chStop.()".postln;
|
||||
" custom : ~chCustom.([[N, action], ...])".postln;
|
||||
" combos : ~chIntro2drop.(4,4) | ~chDropToBreak.() | ~chOutroFade.(12)".postln;
|
||||
};
|
||||
|
||||
// --- API utilisateur : variables d'env top-level --------------------
|
||||
~chIntro = { ~ch[\intro].() };
|
||||
~chDrop = { ~ch[\drop].() };
|
||||
~chBreakdown = { ~ch[\breakdown].() };
|
||||
~chBuildup = { |bars = 8| ~ch[\buildup].(bars) };
|
||||
~chOutro = { ~ch[\outro].() };
|
||||
~chTechno = { |repeats = 4| ~ch[\techno].(repeats) };
|
||||
~chAcid = { ~ch[\acid].() };
|
||||
~chDubstep = { ~ch[\dubstep].() };
|
||||
~chTrance = { ~ch[\trance].() };
|
||||
~chDnb = { |repeats = 4| ~ch[\dnb].(repeats) };
|
||||
~chHiphop = { |repeats = 8| ~ch[\hiphop].(repeats) };
|
||||
~chWorld = { ~ch[\world].() };
|
||||
~chStop = { ~ch[\stop].() };
|
||||
~chCustom = { |actions| ~ch[\custom].(actions) };
|
||||
~chIntro2drop = { |introDur = 4, buildDur = 4| ~ch[\full][\intro2drop].(introDur, buildDur) };
|
||||
~chDropToBreak = { |breakDur = 8| ~ch[\full][\dropToBreak].(breakDur) };
|
||||
~chOutroFade = { |dur = 12| ~ch[\full][\outroFade].(dur) };
|
||||
~chList = { ~ch[\list].() };
|
||||
|
||||
// --- ALIAS court (catalogue, pour inspection) -----------------------
|
||||
~cc = ~ch; // ~cc[\drop].() encore valable, mais prefere ~chDrop.()
|
||||
|
||||
"=== ~ch pret -- ~chDrop.() | ~chTechno.(4) | ~chIntro2drop.() | ~chList.() ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES (Cmd+Entree)
|
||||
// =====================================================================
|
||||
|
||||
// --- sections ---
|
||||
// ( ~chIntro.(); )
|
||||
// ( ~chDrop.(); )
|
||||
// ( ~chBreakdown.(); )
|
||||
// ( ~chBuildup.(8); )
|
||||
// ( ~chOutro.(); )
|
||||
|
||||
// --- loops par genre ---
|
||||
// ( ~chTechno.(4); )
|
||||
// ( ~chAcid.(); )
|
||||
// ( ~chDubstep.(); )
|
||||
// ( ~chTrance.(); )
|
||||
// ( ~chDnb.(4); )
|
||||
// ( ~chHiphop.(8); )
|
||||
// ( ~chWorld.(); )
|
||||
|
||||
// --- stop ---
|
||||
// ( ~chStop.(); )
|
||||
|
||||
// --- combos pré-faits ---
|
||||
// ( ~chIntro2drop.(4, 4); )
|
||||
// ( ~chDropToBreak.(8); )
|
||||
// ( ~chOutroFade.(12); )
|
||||
|
||||
// --- custom (chaine arbitraire) ---
|
||||
// ( ~chCustom.([
|
||||
// [ 16, { ~kickSteps = [1,0,0,0]!4.flat; ~reload.value } ],
|
||||
// [ 16, { ~kickSteps = [1,0,1,0]!4.flat; ~reload.value } ],
|
||||
// [ 16, { ~kickSteps = (0!16); ~reload.value } ]
|
||||
// ]); )
|
||||
|
||||
// --- liste ---
|
||||
// ( ~chList.(); )
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
// =====================================================================
|
||||
// live/fx.scd -- FX LIVE (API ultra-courte, wrappers consolides)
|
||||
//
|
||||
// ATTENTION SC -- noter la notation des appels :
|
||||
//
|
||||
// NE MARCHE PAS : ~fx.preset.(\dub)
|
||||
// -> SC passe l'event ~fx comme 1er arg, et les vrais args sont
|
||||
// PERDUS (test empirique sur SC 3.14.1).
|
||||
//
|
||||
// MARCHE BIEN : ~fx[\preset].(\dub) (notation indexee)
|
||||
// ~fxPreset.(\dub) (variable env directe)
|
||||
// ~ff.(\dub) (alias env direct)
|
||||
//
|
||||
// ~fx // dict catalogue
|
||||
// ~fx[\preset].(\dub|\trance|...)
|
||||
// ~fx[\snd].(\rev, 0.4) // ~send (.send reservee)
|
||||
// ~fx[\st].(\dly, \delayTime, 0.5) // ~setFx (.set reservee)
|
||||
// ~fx[\tp].() // tap tempo (.tap reservee)
|
||||
// ~fx[\freeze].(0|1)
|
||||
// ~fx[\drop] / [\breakdown] / [\buildup]
|
||||
// ~fx[\glitch] / [\stutter] / [\freezeR]
|
||||
// ~fx[\tapeStop] / [\tapeRev] / [\handsUp] / [\jumpCut]
|
||||
// ~fx[\bitCrush] / [\ring] / [\shift] / [\gran]
|
||||
// ~fx[\vcf][\on], [\off], [\freq], [\q], [\sweep], [\preset]
|
||||
// ~fx[\lfo][\go] / [\stop][\go] / [\stop][\all]
|
||||
// ~fx[\cut] / [\rq] / [\drive]
|
||||
// ~fx[\comp][\go] / [\off] ~fx[\sat][\go] / [\off]
|
||||
// ~fx[\list].()
|
||||
//
|
||||
// RACCOURCIS env (API utilisateur primaire) :
|
||||
// ~fxPreset, ~fxSnd, ~fxSt, ~fxTp, ~fxFreeze
|
||||
// ~fxDrop, ~fxBreakdown, ~fxBuildup
|
||||
// ~fxGlitch, ~fxStutter, ~fxFreezeR
|
||||
// ~fxTapeStop, ~fxTapeRev, ~fxHandsUp, ~fxJumpCut
|
||||
// ~fxBitCrush, ~fxRing, ~fxShift, ~fxGran
|
||||
// ~fxVcfOn, ~fxVcfOff, ~fxVcfFreq, ~fxVcfQ, ~fxVcfSweep, ~fxVcfPreset
|
||||
// ~fxLfo, ~fxLfoStop, ~fxLfoStopAll
|
||||
// ~fxCut, ~fxRq, ~fxDrive
|
||||
// ~fxComp, ~fxCompOff, ~fxSat, ~fxSatOff
|
||||
// ~fxList
|
||||
// ~ff (= ~fxPreset)
|
||||
//
|
||||
// TOUS les wrappers gardes par ~helper !? { ... } pour ne pas planter
|
||||
// si le helper sous-jacent n'est pas charge.
|
||||
//
|
||||
// PREREQUIS : engine + live/fx_bus.scd + live/live.scd charges.
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
~fx = ();
|
||||
|
||||
// --- PRESETS FX (dub/space/trance/...) ------------------------------
|
||||
~fx[\preset] = { |name = \dry|
|
||||
~fxPreset !? { ~fxPreset.(name) };
|
||||
};
|
||||
|
||||
// --- SEND / SET sur un bus FX --------------------------------------
|
||||
~fx[\snd] = { |fxName, amount = 0.3|
|
||||
~send !? { ~send.(fxName, amount) };
|
||||
};
|
||||
~fx[\st] = { |fxName, param, value|
|
||||
~setFx !? { ~setFx.(fxName, param, value) };
|
||||
};
|
||||
|
||||
// --- FREEZE reverb permanent / TAP tempo ---------------------------
|
||||
~fx[\freeze] = { |on = 1|
|
||||
~setFx !? { ~setFx.(\rev, \freeze, on) };
|
||||
("[fx.freeze] " ++ on).postln;
|
||||
};
|
||||
~fx[\tp] = { ~tap !? { ~tap.() } };
|
||||
|
||||
// --- DROP / BREAKDOWN / BUILDUP ------------------------------------
|
||||
~fx[\drop] = { |dur = 4| ~drop !? { ~drop.(dur) } };
|
||||
~fx[\breakdown] = { |dur = 8| ~breakdown !? { ~breakdown.(dur) } };
|
||||
~fx[\buildup] = { |dur = 8| ~buildup !? { ~buildup.(dur) } };
|
||||
|
||||
// --- TRICKS scéniques ----------------------------------------------
|
||||
~fx[\glitch] = { |dur = 2| ~glitch !? { ~glitch.(dur) } };
|
||||
~fx[\stutter] = { |rate = 8, dur = 1| ~stutter !? { ~stutter.(rate, dur) } };
|
||||
~fx[\freezeR] = { |dur = 4| ~freeze !? { ~freeze.(dur) } };
|
||||
~fx[\tapeStop] = { |dur = 2| ~tapeStop !? { ~tapeStop.(dur) } };
|
||||
~fx[\tapeRev] = { |dur = 4| ~tapeReverse!? { ~tapeReverse.(dur) } };
|
||||
~fx[\handsUp] = { ~handsUp !? { ~handsUp.() } };
|
||||
~fx[\jumpCut] = { |dur = 0.5| ~jumpCut !? { ~jumpCut.(dur) } };
|
||||
~fx[\bitCrush] = { |bits = 6, sr = 6000, dur = 1| ~bitCrushNow !? { ~bitCrushNow.(bits, sr, dur) } };
|
||||
~fx[\ring] = { |freq = 200, dur = 1| ~ringMod !? { ~ringMod.(freq, dur) } };
|
||||
~fx[\shift] = { |hz = 100, dur = 1| ~freqShift !? { ~freqShift.(hz, dur) } };
|
||||
~fx[\gran] = { |dur = 2| ~granFreeze!? { ~granFreeze.(dur) } };
|
||||
|
||||
// --- VCF (filtre live tout-source) ---------------------------------
|
||||
~fx[\vcf] = ();
|
||||
~fx[\vcf][\on] = { |type = \moog, freq = 1500, q = 0.5|
|
||||
~vcfOn !? { ~vcfOn.(type, freq, q) };
|
||||
};
|
||||
~fx[\vcf][\off] = { ~vcfOff !? { ~vcfOff.() } };
|
||||
~fx[\vcf][\freq] = { |hz = 1500| ~vcfSet !? { ~vcfSet.(\freq, hz) } };
|
||||
~fx[\vcf][\q] = { |val = 0.5| ~vcfSet !? { ~vcfSet.(\q, val) } };
|
||||
~fx[\vcf][\sweep] = { |from = 200, to = 5000, dur = 4|
|
||||
~vcfSweep !? { ~vcfSweep.(from, to, dur) };
|
||||
};
|
||||
~fx[\vcf][\preset] = { |preset = \acid|
|
||||
~vcfPreset !? { ~vcfPreset.(preset) };
|
||||
};
|
||||
|
||||
// --- LFO sur n'importe quelle variable ~xxx ------------------------
|
||||
~fx[\lfo] = ();
|
||||
~fx[\lfo][\go] = { |paramName, rate = 0.5, depth = 0.3, shape = \sin, center = nil|
|
||||
~lfoTo !? { ~lfoTo.(paramName, rate, depth, shape, center) };
|
||||
};
|
||||
~fx[\lfo][\stop] = ();
|
||||
~fx[\lfo][\stop][\go] = { |paramName| ~lfoStopVar !? { ~lfoStopVar.(paramName) } };
|
||||
~fx[\lfo][\stop][\all] = { ~lfoStopAllVars !? { ~lfoStopAllVars.() } };
|
||||
|
||||
// --- SHORTCUTS cutoff / rq / drive par voie ------------------------
|
||||
~fx[\cut] = { |voie = \mel, hz = 2000|
|
||||
var v = voie.asSymbol;
|
||||
if (v == \mel or: { v == \melody }) {
|
||||
~melodyCutoff = hz; ~reload !? { ~reload.value };
|
||||
("[fx.cut] melody " ++ hz ++ "Hz").postln;
|
||||
} { if (v == \acid) {
|
||||
~acidCutoff = hz; ~reload !? { ~reload.value };
|
||||
("[fx.cut] acid " ++ hz ++ "Hz").postln;
|
||||
} { ("[fx.cut] voie inconnue : " ++ v ++ " (utilise \\mel ou \\acid)").postln } };
|
||||
};
|
||||
~fx[\rq] = { |voie = \mel, val = 0.5|
|
||||
var v = voie.asSymbol;
|
||||
if (v == \mel or: { v == \melody }) {
|
||||
~melodyRq = val; ~reload !? { ~reload.value };
|
||||
("[fx.rq] melody " ++ val).postln;
|
||||
} { if (v == \acid) {
|
||||
~acidRq = val; ~reload !? { ~reload.value };
|
||||
("[fx.rq] acid " ++ val).postln;
|
||||
} { ("[fx.rq] voie inconnue : " ++ v).postln } };
|
||||
};
|
||||
~fx[\drive] = { |voie = \mel, val = 1.5|
|
||||
var v = voie.asSymbol;
|
||||
if (v == \mel or: { v == \melody }) {
|
||||
~melodyDrive = val; ~reload !? { ~reload.value };
|
||||
("[fx.drive] melody " ++ val).postln;
|
||||
} { if (v == \acid) {
|
||||
~acidDrive = val; ~reload !? { ~reload.value };
|
||||
("[fx.drive] acid " ++ val).postln;
|
||||
} { ("[fx.drive] voie inconnue : " ++ v).postln } };
|
||||
};
|
||||
|
||||
// --- COMP / SAT master ---------------------------------------------
|
||||
~fx[\comp] = ();
|
||||
~fx[\comp][\go] = { |preset = \glue| ~compOn !? { ~compOn.(preset) } };
|
||||
~fx[\comp][\off] = { ~compOff !? { ~compOff.() } };
|
||||
~fx[\sat] = ();
|
||||
~fx[\sat][\go] = { |mode = \tanh, amount = 1.5|
|
||||
var modeNum = switch (mode.asSymbol, \tanh, 0, \softclip, 1, \fold, 2, 0);
|
||||
~satOn !? { ~satOn.(amount, modeNum) };
|
||||
};
|
||||
~fx[\sat][\off] = { ~satOff !? { ~satOff.() } };
|
||||
|
||||
// --- LISTE -----------------------------------------------------------
|
||||
~fx[\list] = {
|
||||
"=== ~fx -- FX LIVE ===".postln;
|
||||
" presets : dry / dub / space / trance / dubstep / retro /".postln;
|
||||
" industrial / dream / cosmic / drone".postln;
|
||||
" bus : rev / dly / chr / phs / flg / crsh / tape / shim / dist".postln;
|
||||
" tricks : drop / breakdown / buildup / glitch / stutter / freezeR /".postln;
|
||||
" tapeStop / tapeRev / handsUp / jumpCut / bitCrush / ring /".postln;
|
||||
" shift / gran".postln;
|
||||
" vcf : on / off / freq / q / sweep / preset".postln;
|
||||
" lfo : ~fxLfo.(\\param,rate,depth) | ~fxLfoStop.(\\p) | ~fxLfoStopAll.()".postln;
|
||||
" voie cut : ~fxCut.(\\mel|\\acid, hz)".postln;
|
||||
" comp/sat : ~fxComp.(\\glue) | ~fxSat.(\\tanh, 1.5)".postln;
|
||||
};
|
||||
|
||||
// --- API utilisateur : variables d'env top-level --------------------
|
||||
~fxPreset = { |name = \dry| ~fx[\preset].(name) };
|
||||
~fxSnd = { |fxName, amount = 0.3| ~fx[\snd].(fxName, amount) };
|
||||
~fxSt = { |fxName, param, value| ~fx[\st].(fxName, param, value) };
|
||||
~fxTp = { ~fx[\tp].() };
|
||||
~fxFreeze = { |on = 1| ~fx[\freeze].(on) };
|
||||
~fxDrop = { |dur = 4| ~fx[\drop].(dur) };
|
||||
~fxBreakdown = { |dur = 8| ~fx[\breakdown].(dur) };
|
||||
~fxBuildup = { |dur = 8| ~fx[\buildup].(dur) };
|
||||
~fxGlitch = { |dur = 2| ~fx[\glitch].(dur) };
|
||||
~fxStutter = { |rate = 8, dur = 1| ~fx[\stutter].(rate, dur) };
|
||||
~fxFreezeR = { |dur = 4| ~fx[\freezeR].(dur) };
|
||||
~fxTapeStop = { |dur = 2| ~fx[\tapeStop].(dur) };
|
||||
~fxTapeRev = { |dur = 4| ~fx[\tapeRev].(dur) };
|
||||
~fxHandsUp = { ~fx[\handsUp].() };
|
||||
~fxJumpCut = { |dur = 0.5| ~fx[\jumpCut].(dur) };
|
||||
~fxBitCrush = { |bits = 6, sr = 6000, dur = 1| ~fx[\bitCrush].(bits, sr, dur) };
|
||||
~fxRing = { |freq = 200, dur = 1| ~fx[\ring].(freq, dur) };
|
||||
~fxShift = { |hz = 100, dur = 1| ~fx[\shift].(hz, dur) };
|
||||
~fxGran = { |dur = 2| ~fx[\gran].(dur) };
|
||||
~fxVcfOn = { |type = \moog, freq = 1500, q = 0.5| ~fx[\vcf][\on].(type, freq, q) };
|
||||
~fxVcfOff = { ~fx[\vcf][\off].() };
|
||||
~fxVcfFreq = { |hz = 1500| ~fx[\vcf][\freq].(hz) };
|
||||
~fxVcfQ = { |val = 0.5| ~fx[\vcf][\q].(val) };
|
||||
~fxVcfSweep = { |from = 200, to = 5000, dur = 4| ~fx[\vcf][\sweep].(from, to, dur) };
|
||||
~fxVcfPreset = { |preset = \acid| ~fx[\vcf][\preset].(preset) };
|
||||
~fxLfo = { |paramName, rate = 0.5, depth = 0.3, shape = \sin, center = nil|
|
||||
~fx[\lfo][\go].(paramName, rate, depth, shape, center) };
|
||||
~fxLfoStop = { |paramName| ~fx[\lfo][\stop][\go].(paramName) };
|
||||
~fxLfoStopAll = { ~fx[\lfo][\stop][\all].() };
|
||||
~fxCut = { |voie = \mel, hz = 2000| ~fx[\cut].(voie, hz) };
|
||||
~fxRq = { |voie = \mel, val = 0.5| ~fx[\rq].(voie, val) };
|
||||
~fxDrive = { |voie = \mel, val = 1.5| ~fx[\drive].(voie, val) };
|
||||
~fxComp = { |preset = \glue| ~fx[\comp][\go].(preset) };
|
||||
~fxCompOff = { ~fx[\comp][\off].() };
|
||||
~fxSat = { |mode = \tanh, amount = 1.5| ~fx[\sat][\go].(mode, amount) };
|
||||
~fxSatOff = { ~fx[\sat][\off].() };
|
||||
~fxList = { ~fx[\list].() };
|
||||
~ff = { |name = \dry| ~fxPreset.(name) }; // alias court
|
||||
|
||||
"=== ~fx pret -- ~ff.(\\dub) | ~fxDrop.() | ~fxVcfPreset.(\\acid) | ~fxList.() ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES (Cmd+Entree)
|
||||
// =====================================================================
|
||||
|
||||
// --- presets prets ---
|
||||
// ( ~ff.(\dub); )
|
||||
// ( ~ff.(\trance); )
|
||||
// ( ~ff.(\dubstep); )
|
||||
// ( ~ff.(\space); )
|
||||
// ( ~ff.(\dry); )
|
||||
|
||||
// --- send / set manuel ---
|
||||
// ( ~fxSnd.(\rev, 0.4); )
|
||||
// ( ~fxSnd.(\dly, 0.3); )
|
||||
// ( ~fxSt.(\dly, \delayTime, 0.375); )
|
||||
// ( ~fxSt.(\rev, \room, 0.95); )
|
||||
|
||||
// --- freeze reverb ---
|
||||
// ( ~fxFreeze.(1); ~fxSnd.(\rev, 0.6); )
|
||||
// ( ~fxFreeze.(0); )
|
||||
|
||||
// --- drop / breakdown / buildup ---
|
||||
// ( ~fxDrop.(); )
|
||||
// ( ~fxBreakdown.(8); )
|
||||
// ( ~fxBuildup.(8); )
|
||||
|
||||
// --- tricks scéniques ---
|
||||
// ( ~fxGlitch.(2); )
|
||||
// ( ~fxStutter.(8, 1); )
|
||||
// ( ~fxFreezeR.(4); )
|
||||
// ( ~fxTapeStop.(2); )
|
||||
// ( ~fxTapeRev.(4); )
|
||||
// ( ~fxHandsUp.(); )
|
||||
// ( ~fxJumpCut.(0.5); )
|
||||
// ( ~fxBitCrush.(4, 4000, 1); )
|
||||
// ( ~fxRing.(200, 1); )
|
||||
// ( ~fxShift.(100, 1); )
|
||||
// ( ~fxGran.(2); )
|
||||
|
||||
// --- VCF live ---
|
||||
// ( ~fxVcfPreset.(\acid); )
|
||||
// ( ~fxVcfPreset.(\dub); )
|
||||
// ( ~fxVcfOn.(\moog, 800, 0.7); )
|
||||
// ( ~fxVcfFreq.(1200); )
|
||||
// ( ~fxVcfQ.(0.6); )
|
||||
// ( ~fxVcfSweep.(200, 4000, 6); )
|
||||
// ( ~fxVcfOff.(); )
|
||||
|
||||
// --- LFO sur var ---
|
||||
// ( ~fxLfo.(\melodyCutoff, 0.2, 800, \sin, 1500); )
|
||||
// ( ~fxLfoStop.(\melodyCutoff); )
|
||||
// ( ~fxLfoStopAll.(); )
|
||||
|
||||
// --- shortcuts par voie ---
|
||||
// ( ~fxCut.(\mel, 1200); )
|
||||
// ( ~fxCut.(\acid, 600); )
|
||||
// ( ~fxRq.(\mel, 0.7); )
|
||||
// ( ~fxDrive.(\acid, 3.0); )
|
||||
|
||||
// --- comp / sat master ---
|
||||
// ( ~fxComp.(\glue); )
|
||||
// ( ~fxCompOff.(); )
|
||||
// ( ~fxSat.(\tanh, 2.0); )
|
||||
// ( ~fxSatOff.(); )
|
||||
|
||||
// --- liste ---
|
||||
// ( ~fxList.(); )
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
// =====================================================================
|
||||
// live/fx_bus.scd -- Systeme FX live complet
|
||||
//
|
||||
// 9 bus FX : reverb / delay / chorus / phaser / flanger / bitcrush /
|
||||
// tape / shimmer / distortion
|
||||
// + helpers send / setFx
|
||||
// + automation LFO sur tout param
|
||||
// + presets / snapshots
|
||||
// + tap tempo pour delay
|
||||
// + freeze reverb (capture)
|
||||
// + crossfade entre FX
|
||||
//
|
||||
// USAGE
|
||||
// 1. SETUP FX -- charge SynthDefs + alloue les bus + lance les FX
|
||||
// en queue + cree les helpers (~send / ~lfo / ~fxPreset / ~tap /
|
||||
// ~crossfadeFx). Compatible .load (un seul bloc top-level).
|
||||
// 2. Helpers ~sendXxx pour envoyer dans un FX (live)
|
||||
// 3. Helpers ~lfoXxx pour automatiser un parametre (live)
|
||||
// 4. Presets ~fxPreset.(\name) pour rappeler un combo (live)
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// 1. SETUP FX (single-block) -- SynthDefs + bus + FX en queue + helpers
|
||||
// =====================================================================
|
||||
(
|
||||
// --- BUS allocation ---
|
||||
~fxBuses !? { ~fxBuses.do(_.free) };
|
||||
~fxBuses = (
|
||||
rev: Bus.audio(s, 2),
|
||||
dly: Bus.audio(s, 2),
|
||||
chr: Bus.audio(s, 2),
|
||||
phs: Bus.audio(s, 2),
|
||||
flg: Bus.audio(s, 2),
|
||||
crsh: Bus.audio(s, 2),
|
||||
tape: Bus.audio(s, 2),
|
||||
shim: Bus.audio(s, 2),
|
||||
dist: Bus.audio(s, 2),
|
||||
);
|
||||
|
||||
// --- REVERB (FreeVerb stereo + freeze) ---
|
||||
SynthDef(\fxReverb, {
|
||||
arg in, out = 0, mix = 0.4, room = 0.85, damp = 0.4,
|
||||
freeze = 0, amp = 1.0;
|
||||
var sig = In.ar(in, 2);
|
||||
sig = FreeVerb2.ar(sig[0], sig[1],
|
||||
Select.kr(freeze, [mix, 1.0]),
|
||||
Select.kr(freeze, [room, 0.999]),
|
||||
Select.kr(freeze, [damp, 0.001]));
|
||||
Out.ar(out, sig * amp);
|
||||
}).add;
|
||||
|
||||
// --- DELAY ping-pong avec saturation tape ---
|
||||
SynthDef(\fxDelay, {
|
||||
arg in, out = 0, delayTime = 0.375, feedback = 0.5,
|
||||
mix = 0.5, color = 0.3, amp = 1.0;
|
||||
var dry, wet, l, r, fb;
|
||||
dry = In.ar(in, 2);
|
||||
fb = LocalIn.ar(2); // vrai feedback stereo
|
||||
l = DelayC.ar(fb[1] + dry[0], 2.0, delayTime) * feedback; // ping
|
||||
r = DelayC.ar(fb[0] + dry[1], 2.0, delayTime) * feedback; // pong
|
||||
// Color : LPF pour effet tape vintage
|
||||
l = LPF.ar(l, color.linexp(0, 1, 800, 16000));
|
||||
r = LPF.ar(r, color.linexp(0, 1, 800, 16000));
|
||||
LocalOut.ar([l, r]);
|
||||
wet = [l, r];
|
||||
Out.ar(out, ((dry * (1 - mix)) + (wet * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- CHORUS (modulation stereo) ---
|
||||
SynthDef(\fxChorus, {
|
||||
arg in, out = 0, rate = 0.4, depth = 0.005,
|
||||
mix = 0.5, amp = 1.0;
|
||||
var sig = In.ar(in, 2);
|
||||
var l = DelayC.ar(sig[0], 0.05, SinOsc.kr(rate, 0).range(0.005, 0.005 + depth));
|
||||
var r = DelayC.ar(sig[1], 0.05, SinOsc.kr(rate, pi).range(0.005, 0.005 + depth));
|
||||
var wet = [l, r];
|
||||
Out.ar(out, ((sig * (1 - mix)) + (wet * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- PHASER (4-stage allpass + LFO) ---
|
||||
SynthDef(\fxPhaser, {
|
||||
arg in, out = 0, rate = 0.3, depth = 0.7, feedback = 0.4,
|
||||
mix = 0.5, amp = 1.0;
|
||||
var dry = In.ar(in, 2);
|
||||
var lfo = SinOsc.kr(rate).range(200, 200 + (3000 * depth));
|
||||
var sig = AllpassN.ar(dry, 0.01, lfo.reciprocal, 0.05);
|
||||
sig = AllpassN.ar(sig, 0.01, (lfo * 1.3).reciprocal, 0.05);
|
||||
sig = AllpassN.ar(sig, 0.01, (lfo * 1.7).reciprocal, 0.05);
|
||||
sig = AllpassN.ar(sig + (LocalIn.ar(2) * feedback), 0.01, (lfo * 2.1).reciprocal, 0.05);
|
||||
LocalOut.ar(sig);
|
||||
Out.ar(out, ((dry * (1 - mix)) + (sig * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- FLANGER (court delay + LFO + feedback) ---
|
||||
SynthDef(\fxFlanger, {
|
||||
arg in, out = 0, rate = 0.2, depth = 0.003, feedback = 0.6,
|
||||
mix = 0.5, amp = 1.0;
|
||||
var dry = In.ar(in, 2);
|
||||
var lfo = SinOsc.kr(rate).range(0.0005, 0.0005 + depth);
|
||||
var fb = LocalIn.ar(2) * feedback;
|
||||
var sig = DelayC.ar(dry + fb, 0.02, lfo);
|
||||
LocalOut.ar(sig);
|
||||
Out.ar(out, ((dry * (1 - mix)) + (sig * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- BITCRUSHER (lo-fi sample rate + bit depth) ---
|
||||
SynthDef(\fxBitcrush, {
|
||||
arg in, out = 0, bits = 8, sampleRate = 8000,
|
||||
mix = 0.6, amp = 1.0;
|
||||
var dry = In.ar(in, 2);
|
||||
// Bit reduction native (sans Decimator de sc3-plugins)
|
||||
var step = 2.pow(bits - 1);
|
||||
var crushed = (dry * step).round / step;
|
||||
var sig = Latch.ar(crushed, Impulse.ar(sampleRate));
|
||||
Out.ar(out, ((dry * (1 - mix)) + (sig * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- TAPE (saturation analog + wow/flutter) ---
|
||||
SynthDef(\fxTape, {
|
||||
arg in, out = 0, drive = 1.5, wow = 0.0015, flutter = 0.0008,
|
||||
mix = 1.0, amp = 1.0;
|
||||
var dry = In.ar(in, 2);
|
||||
var modL = SinOsc.kr(0.3).range(0, wow) + LFNoise2.kr(8).range(0, flutter);
|
||||
var modR = SinOsc.kr(0.31).range(0, wow) + LFNoise2.kr(8).range(0, flutter);
|
||||
var sig = [DelayC.ar(dry[0], 0.02, 0.005 + modL),
|
||||
DelayC.ar(dry[1], 0.02, 0.005 + modR)];
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
sig = LPF.ar(sig, 12000); // EQ tape rolloff aigu
|
||||
Out.ar(out, ((dry * (1 - mix)) + (sig * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- SHIMMER REVERB (octave up + reverb hall) ---
|
||||
SynthDef(\fxShimmer, {
|
||||
arg in, out = 0, mix = 0.5, room = 0.92, shimmer = 0.5, amp = 1.0;
|
||||
var dry = In.ar(in, 2);
|
||||
var pitched = PitchShift.ar(dry, 0.2, 2, 0.01, 0.005) * shimmer;
|
||||
var sig = FreeVerb2.ar(dry[0] + pitched[0], dry[1] + pitched[1],
|
||||
1.0, room, 0.3);
|
||||
Out.ar(out, ((dry * (1 - mix)) + (sig * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- DISTORTION (overdrive + tone) ---
|
||||
SynthDef(\fxDist, {
|
||||
arg in, out = 0, drive = 3.0, tone = 0.5,
|
||||
mix = 1.0, amp = 1.0;
|
||||
var dry = In.ar(in, 2);
|
||||
var sig = (dry * drive).tanh;
|
||||
sig = (sig * 1.5).tanh;
|
||||
sig = MoogFF.ar(sig, tone.linexp(0, 1, 500, 12000), 1.5);
|
||||
Out.ar(out, ((dry * (1 - mix)) + (sig * mix)) * amp);
|
||||
}).add;
|
||||
|
||||
// --- SEND (copie audio vers un FX bus, ratio reglable) ---
|
||||
SynthDef(\fxSend, {
|
||||
arg srcBus = 0, dstBus, amount = 0.3;
|
||||
var sig = In.ar(srcBus, 2);
|
||||
Out.ar(dstBus, sig * amount);
|
||||
}).add;
|
||||
|
||||
s.sync;
|
||||
|
||||
// --- INSTANCIER les 9 FX en queue + master limiter ----------------
|
||||
// .do sur Event : 1 arg = value. Le 2-arg form est |value, key| (synth d'abord).
|
||||
~fxFx !? { ~fxFx.do { |syn| syn !? { syn.free } } };
|
||||
~fxFx = (
|
||||
rev: Synth.tail(s.defaultGroup, \fxReverb, [\in, ~fxBuses[\rev].index]),
|
||||
dly: Synth.tail(s.defaultGroup, \fxDelay, [\in, ~fxBuses[\dly].index]),
|
||||
chr: Synth.tail(s.defaultGroup, \fxChorus, [\in, ~fxBuses[\chr].index]),
|
||||
phs: Synth.tail(s.defaultGroup, \fxPhaser, [\in, ~fxBuses[\phs].index]),
|
||||
flg: Synth.tail(s.defaultGroup, \fxFlanger, [\in, ~fxBuses[\flg].index]),
|
||||
crsh: Synth.tail(s.defaultGroup, \fxBitcrush,[\in, ~fxBuses[\crsh].index]),
|
||||
tape: Synth.tail(s.defaultGroup, \fxTape, [\in, ~fxBuses[\tape].index]),
|
||||
shim: Synth.tail(s.defaultGroup, \fxShimmer, [\in, ~fxBuses[\shim].index]),
|
||||
dist: Synth.tail(s.defaultGroup, \fxDist, [\in, ~fxBuses[\dist].index, \mix, 0.5]),
|
||||
);
|
||||
|
||||
// Master limiter en queue absolue
|
||||
~masterLim !? { ~masterLim.free };
|
||||
~masterLim = Synth.tail(s.defaultGroup, \masterLim);
|
||||
|
||||
~fxSends = (); // dictionnaire des Synth de send actifs
|
||||
~fxLfos = (); // dictionnaire des Routines LFO actives
|
||||
|
||||
// ---------- HELPERS SEND ---------------------------------------------
|
||||
~send = { |fxName, amount = 0.3|
|
||||
var key = fxName.asSymbol;
|
||||
~fxSends[key] !? { ~fxSends[key].free };
|
||||
if (amount > 0) {
|
||||
~fxSends[key] = Synth.before(~masterLim, \fxSend,
|
||||
[\srcBus, 0, \dstBus, ~fxBuses[key].index, \amount, amount]);
|
||||
} { ~fxSends.removeAt(key) };
|
||||
("send " ++ key ++ " = " ++ amount).postln;
|
||||
};
|
||||
|
||||
// Raccourcis
|
||||
~sendReverb = { |a = 0.3| ~send.(\rev, a) };
|
||||
~sendDelay = { |a = 0.3| ~send.(\dly, a) };
|
||||
~sendChorus = { |a = 0.3| ~send.(\chr, a) };
|
||||
~sendPhaser = { |a = 0.3| ~send.(\phs, a) };
|
||||
~sendFlanger = { |a = 0.3| ~send.(\flg, a) };
|
||||
~sendBitcrush = { |a = 0.3| ~send.(\crsh, a) };
|
||||
~sendTape = { |a = 1.0| ~send.(\tape, a) };
|
||||
~sendShimmer = { |a = 0.3| ~send.(\shim, a) };
|
||||
~sendDist = { |a = 0.3| ~send.(\dist, a) };
|
||||
|
||||
// Set un parametre de FX (~setFx.(\rev, \room, 0.95))
|
||||
~setFx = { |fxName, param, value|
|
||||
~fxFx[fxName.asSymbol] !? { ~fxFx[fxName.asSymbol].set(param, value) };
|
||||
};
|
||||
|
||||
// ---------- AUTOMATION LFO -------------------------------------------
|
||||
~lfo = { |fxName, param, rateHz = 0.5, lo = 0.0, hi = 1.0, shape = \sin|
|
||||
var key = (fxName ++ "_" ++ param).asSymbol;
|
||||
~fxLfos[key] !? { ~fxLfos[key].stop };
|
||||
~fxLfos[key] = Routine({
|
||||
var phase = 0;
|
||||
inf.do { |i|
|
||||
var x;
|
||||
x = switch (shape,
|
||||
\sin, { (phase * 2 * pi).sin * 0.5 + 0.5 },
|
||||
\tri, { (phase * 4 - 1).abs.linlin(0, 1, 1, 0) },
|
||||
\saw, { phase },
|
||||
\sqr, { if (phase < 0.5) {0} {1} },
|
||||
\rand, { 1.0.rand }
|
||||
);
|
||||
~setFx.(fxName, param, lo + (x * (hi - lo)));
|
||||
phase = (phase + (rateHz * 0.05)).mod(1);
|
||||
0.05.wait;
|
||||
};
|
||||
}).play;
|
||||
("LFO " ++ fxName ++ "." ++ param ++ " " ++ rateHz ++ "Hz " ++ shape).postln;
|
||||
};
|
||||
|
||||
~lfoStop = { |fxName, param|
|
||||
var key = (fxName ++ "_" ++ param).asSymbol;
|
||||
~fxLfos[key] !? { ~fxLfos[key].stop; ~fxLfos.removeAt(key) };
|
||||
("LFO " ++ fxName ++ "." ++ param ++ " STOPPED").postln;
|
||||
};
|
||||
|
||||
~lfoStopAll = {
|
||||
~fxLfos.do { |r| r.stop }; ~fxLfos = ();
|
||||
"all LFOs stopped".postln;
|
||||
};
|
||||
|
||||
// ---------- TAP TEMPO pour le delay ----------------------------------
|
||||
~tapTempo = ();
|
||||
~tap = {
|
||||
var now = SystemClock.seconds;
|
||||
~tapTempo[\last] !? { |last|
|
||||
var interval = now - last;
|
||||
if (interval < 2.0 and: { interval > 0.1 }) {
|
||||
~setFx.(\dly, \delayTime, interval);
|
||||
("TAP : " ++ interval.round(0.001) ++ "s = " ++
|
||||
(60 / interval).round(0.1) ++ " BPM").postln;
|
||||
};
|
||||
};
|
||||
~tapTempo[\last] = now;
|
||||
};
|
||||
|
||||
// ---------- CROSSFADE entre 2 FX -------------------------------------
|
||||
~crossfadeFx = { |fromFx, toFx, dur = 4|
|
||||
Routine({
|
||||
var steps = (dur * 20).asInteger;
|
||||
steps.do { |i|
|
||||
var x = (i + 1) / steps;
|
||||
~send.(fromFx, 0.3 * (1 - x));
|
||||
~send.(toFx, 0.3 * x);
|
||||
(dur / steps).wait;
|
||||
};
|
||||
}).play;
|
||||
("crossfade " ++ fromFx ++ " -> " ++ toFx ++ " sur " ++ dur ++ "s").postln;
|
||||
};
|
||||
|
||||
// ---------- PRESETS FX (combos pret a l'emploi par genre) ------------
|
||||
~fxPreset = { |name|
|
||||
switch (name,
|
||||
\dry, {
|
||||
[\rev,\dly,\chr,\phs,\flg,\crsh,\tape,\shim,\dist]
|
||||
.do { |k| ~send.(k, 0) };
|
||||
"preset DRY".postln;
|
||||
},
|
||||
\dub, {
|
||||
~sendReverb.(0.5); ~sendDelay.(0.6); ~sendTape.(0.7);
|
||||
~setFx.(\dly, \delayTime, 0.5);
|
||||
~setFx.(\dly, \feedback, 0.7);
|
||||
~setFx.(\rev, \room, 0.92);
|
||||
"preset DUB (rev hall + delay long + tape)".postln;
|
||||
},
|
||||
\space, {
|
||||
~sendReverb.(0.55); ~sendShimmer.(0.4); ~sendChorus.(0.3);
|
||||
~setFx.(\rev, \room, 0.95);
|
||||
"preset SPACE (shimmer + reverb + chorus)".postln;
|
||||
},
|
||||
\trance, {
|
||||
~sendReverb.(0.35); ~sendDelay.(0.4); ~sendChorus.(0.5);
|
||||
~setFx.(\dly, \delayTime, 0.375);
|
||||
~setFx.(\dly, \feedback, 0.5);
|
||||
"preset TRANCE (rev + delay 1/8 + chorus)".postln;
|
||||
},
|
||||
\dubstep, {
|
||||
~sendReverb.(0.2); ~sendDist.(0.3); ~sendBitcrush.(0.2);
|
||||
~setFx.(\dist, \drive, 4); ~setFx.(\dist, \tone, 0.4);
|
||||
~setFx.(\crsh, \bits, 6);
|
||||
"preset DUBSTEP (dist + bitcrush + reverb)".postln;
|
||||
},
|
||||
\retro, {
|
||||
~sendBitcrush.(0.4); ~sendTape.(1.0); ~sendChorus.(0.4);
|
||||
~setFx.(\crsh, \bits, 8); ~setFx.(\crsh, \sampleRate, 12000);
|
||||
~setFx.(\tape, \drive, 1.8);
|
||||
"preset RETRO (bitcrush + tape + chorus)".postln;
|
||||
},
|
||||
\industrial, {
|
||||
~sendDist.(0.6); ~sendFlanger.(0.4); ~sendBitcrush.(0.3);
|
||||
~setFx.(\dist, \drive, 5);
|
||||
~setFx.(\flg, \rate, 0.15); ~setFx.(\flg, \feedback, 0.7);
|
||||
"preset INDUSTRIAL (dist + flanger + bitcrush)".postln;
|
||||
},
|
||||
\dream, {
|
||||
~sendShimmer.(0.6); ~sendReverb.(0.5); ~sendChorus.(0.4);
|
||||
~setFx.(\shim, \shimmer, 0.7);
|
||||
"preset DREAM (shimmer + reverb + chorus)".postln;
|
||||
},
|
||||
\cosmic, {
|
||||
~sendPhaser.(0.5); ~sendShimmer.(0.4); ~sendReverb.(0.4);
|
||||
~lfo.(\phs, \rate, 0.05, 0.1, 0.8);
|
||||
"preset COSMIC (phaser LFO + shimmer + reverb)".postln;
|
||||
},
|
||||
\drone, {
|
||||
~sendReverb.(0.7); ~sendShimmer.(0.5);
|
||||
~setFx.(\rev, \freeze, 1); ~setFx.(\rev, \room, 0.99);
|
||||
"preset DRONE (reverb FROZEN + shimmer)".postln;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
"=== 9 FX BUSES + master limiter en queue ===".postln;
|
||||
" bus dispos : rev / dly / chr / phs / flg / crsh / tape / shim / dist".postln;
|
||||
"=== ~send / ~sendReverb / ~setFx / ~lfo / ~tap / ~crossfadeFx / ~fxPreset prets ===".postln;
|
||||
"=== presets : dry / dub / space / trance / dubstep / retro / industrial / dream / cosmic / drone ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// 2. EXEMPLES / TWEAKS LIVE -- Cmd+Entree sur ligne pendant track
|
||||
// (tout ce qui est en bas est interactif et NON .load -- garde
|
||||
// du multi-bloc pour evaluer un effet a la fois)
|
||||
// =====================================================================
|
||||
|
||||
// --- Send levels ----------------------------------------------------
|
||||
( ~sendReverb.(0.4); ~sendDelay.(0.3); )
|
||||
( ~sendReverb.(0); ~sendDelay.(0); ~sendChorus.(0); )
|
||||
( ~sendShimmer.(0.5); ~setFx.(\shim, \shimmer, 0.7); )
|
||||
( ~sendBitcrush.(0.5); ~setFx.(\crsh, \bits, 4); )
|
||||
( ~sendDist.(0.5); ~setFx.(\dist, \drive, 4); ~setFx.(\dist, \tone, 0.3); )
|
||||
( ~sendFlanger.(0.5); ~setFx.(\flg, \rate, 0.15); )
|
||||
( ~sendPhaser.(0.4); ~setFx.(\phs, \rate, 0.2); ~setFx.(\phs, \depth, 0.8); )
|
||||
( ~sendTape.(1.0); ~setFx.(\tape, \drive, 2.5); )
|
||||
|
||||
// --- Tempo synced delay ---------------------------------------------
|
||||
( ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo / 4); ) // 1/16
|
||||
( ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo / 2); ) // 1/8
|
||||
( ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo); ) // 1/4
|
||||
( ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo * 0.75); ) // 1/4 dotted
|
||||
|
||||
// --- Reverb size ----------------------------------------------------
|
||||
( ~setFx.(\rev, \room, 0.5); ~setFx.(\rev, \damp, 0.6); ) // room
|
||||
( ~setFx.(\rev, \room, 0.85);~setFx.(\rev, \damp, 0.4); ) // hall
|
||||
( ~setFx.(\rev, \room, 0.97);~setFx.(\rev, \damp, 0.1); ) // cathedral
|
||||
|
||||
// --- LFO automation -------------------------------------------------
|
||||
( ~lfo.(\dly, \feedback, 0.1, 0.2, 0.85, \sin); ) // feedback qui pulse
|
||||
( ~lfo.(\rev, \mix, 0.05, 0.1, 0.7, \tri); ) // wash de reverb
|
||||
( ~lfo.(\crsh, \bits, 0.2, 4, 12, \sqr); ) // glitch lo-fi
|
||||
( ~lfo.(\phs, \rate, 0.02, 0.1, 1.5, \sin); ) // phaser qui accelere
|
||||
( ~lfo.(\shim, \shimmer, 0.1, 0.2, 0.8, \rand); ) // shimmer chaos
|
||||
( ~lfoStopAll.value; )
|
||||
|
||||
// --- Tap tempo (au moins 2 fois pour calibrer) ---------------------
|
||||
( ~tap.value; )
|
||||
|
||||
// --- Freeze reverb (drone infini) -----------------------------------
|
||||
( ~setFx.(\rev, \freeze, 1); ~sendReverb.(0.6); )
|
||||
( ~setFx.(\rev, \freeze, 0); )
|
||||
|
||||
// --- Crossfade entre FX --------------------------------------------
|
||||
( ~crossfadeFx.(\dly, \rev, 8); ) // delay -> reverb sur 8s
|
||||
( ~crossfadeFx.(\dist, \shim, 4); ) // dist -> shimmer sur 4s
|
||||
|
||||
// --- Presets --------------------------------------------------------
|
||||
( ~fxPreset.(\dry); ) // tout off
|
||||
( ~fxPreset.(\dub); ) // dub techno
|
||||
( ~fxPreset.(\trance); ) // uplifting trance
|
||||
( ~fxPreset.(\dubstep); ) // dubstep dirty
|
||||
( ~fxPreset.(\space); ) // space ambient
|
||||
( ~fxPreset.(\retro); ) // 80s lo-fi
|
||||
( ~fxPreset.(\industrial); ) // hard distorted
|
||||
( ~fxPreset.(\dream); ) // dream pop
|
||||
( ~fxPreset.(\cosmic); ) // psy cosmic + LFO phaser
|
||||
( ~fxPreset.(\drone); ) // drone freeze infini
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// 3. STOP FX -- libere tout
|
||||
// =====================================================================
|
||||
(
|
||||
~lfoStopAll.value;
|
||||
~fxSends.do { |s| s.free }; ~fxSends = ();
|
||||
~fxFx.do { |s| s.free }; ~fxFx = ();
|
||||
~fxBuses.do { |b| b.free }; ~fxBuses = ();
|
||||
"=== ALL FX STOPPED ===".postln;
|
||||
)
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
// =====================================================================
|
||||
// live/kicks.scd -- KICKS LIVE (API ultra-courte)
|
||||
//
|
||||
// ATTENTION SC -- noter la notation des appels :
|
||||
//
|
||||
// NE MARCHE PAS : ~k.pat.(\amen)
|
||||
// -> SC passe l'event ~k comme 1er arg, et les vrais args sont
|
||||
// PERDUS (test empirique sur SC 3.14.1, cf Dictionary.sc:549).
|
||||
//
|
||||
// MARCHE BIEN : ~k[\pat].(\amen) (notation indexee)
|
||||
// ~kPat.(\amen) (variable env directe)
|
||||
// ~kk.(\techno) (alias env direct)
|
||||
//
|
||||
// ~k // dict : catalogue de toutes les
|
||||
// // donnees + helpers
|
||||
// ~k[\pat].(\name|N) // applique SEULEMENT un pattern
|
||||
// ~k[\tim].(\name|N) // applique SEULEMENT un timbre
|
||||
// ~k[\go].(\name) // pattern + timbre + reload
|
||||
// ~k[\list].() // liste tout
|
||||
//
|
||||
// RACCOURCIS env (API utilisateur primaire) :
|
||||
// ~kPat.(\amen) | ~kTim.(\808) | ~kk.(\techno) (combo)
|
||||
// ~kList.()
|
||||
//
|
||||
// EXEMPLES :
|
||||
// ~kk.(\techno) // 4/4 + rond
|
||||
// ~kk.(\gabber) // dense + distordu
|
||||
// ~kPat.(\amen) // juste le pattern amen-break
|
||||
// ~kTim.(\808) // juste le timbre 808 boom
|
||||
// ~kPat.(7) // pattern n°7
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue (defines ~kickSteps, ~kickFreq, etc.)
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
~k = ();
|
||||
|
||||
// --- 25 patterns kick (16 steps chacun) -----------------------------
|
||||
~k[\patterns] = (
|
||||
\four: [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ],
|
||||
\techno: [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0 ],
|
||||
\gabber: [ 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0 ],
|
||||
\dembow: [ 1,0,0,1, 0,0,1,0, 1,0,0,1, 0,0,1,0 ],
|
||||
\half: [ 1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ],
|
||||
\break: [ 1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0 ],
|
||||
\triplet: [ 1,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,1 ],
|
||||
\minimal: [ 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ],
|
||||
\ghost: [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0 ],
|
||||
\synco: [ 1,0,1,0, 1,0,0,1, 1,0,1,0, 1,0,1,1 ],
|
||||
\dnb: [ 1,0,0,1, 0,0,0,0, 0,0,1,0, 0,0,1,0 ],
|
||||
\amen: [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ],
|
||||
\dense: [ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 ],
|
||||
\hardstyle:[1,0,0,0, 1,0,0,1, 1,0,0,0, 1,1,0,0 ],
|
||||
\trance: [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,1 ],
|
||||
\house: [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ],
|
||||
\electro: [ 1,0,0,1, 0,0,0,0, 1,0,0,0, 0,0,1,0 ],
|
||||
\triphop: [ 1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0 ],
|
||||
\jungle: [ 1,0,0,1, 0,1,0,0, 1,0,0,1, 0,1,0,0 ],
|
||||
\dub: [ 0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ],
|
||||
\afro: [ 1,0,0,1, 0,1,0,0, 1,0,1,0, 0,1,0,0 ],
|
||||
\garage: [ 1,0,0,0, 0,0,1,0, 0,0,0,0, 1,0,0,0 ],
|
||||
\footwork:[ 1,0,0,1, 1,0,0,0, 1,0,1,1, 0,0,1,0 ],
|
||||
\off: (0 ! 16),
|
||||
);
|
||||
|
||||
// --- 12 timbres kick (params SynthDef) ------------------------------
|
||||
~k[\timbres] = (
|
||||
\rond: (freq: 55, pitchAmt: 3.0, decay: 0.32, drive: 1.3, click: 0.2),
|
||||
\sub: (freq: 42, pitchAmt: 2.0, decay: 0.50, drive: 1.0, click: 0.05),
|
||||
\punchy: (freq: 65, pitchAmt: 4.0, decay: 0.18, drive: 1.8, click: 0.45),
|
||||
\distorded:(freq:60, pitchAmt: 5.0, decay: 0.28, drive: 3.5, click: 0.30),
|
||||
\click: (freq: 70, pitchAmt: 2.5, decay: 0.10, drive: 1.0, click: 0.60),
|
||||
\boomy: (freq: 50, pitchAmt: 6.0, decay: 0.40, drive: 1.5, click: 0.10),
|
||||
\clap: (freq: 90, pitchAmt: 1.5, decay: 0.08, drive: 1.2, click: 0.50),
|
||||
\909: (freq: 60, pitchAmt: 3.5, decay: 0.45, drive: 1.4, click: 0.15),
|
||||
\808: (freq: 38, pitchAmt: 1.8, decay: 0.65, drive: 1.0, click: 0.05),
|
||||
\gabberT: (freq: 65, pitchAmt: 5.5, decay: 0.22, drive: 4.5, click: 0.50),
|
||||
\breakcore:(freq:80, pitchAmt: 2.0, decay: 0.06, drive: 2.5, click: 0.70),
|
||||
\dubT: (freq: 40, pitchAmt: 1.5, decay: 0.80, drive: 1.0, click: 0.02),
|
||||
);
|
||||
|
||||
// --- Combos pre-mappes (1 nom = pattern + timbre + reload) ----------
|
||||
~k[\combos] = (
|
||||
\techno: [\techno, \rond],
|
||||
\gabber: [\gabber, \gabberT],
|
||||
\dub: [\dub, \dubT],
|
||||
\dubstep: [\half, \808],
|
||||
\trance: [\trance, \punchy],
|
||||
\hardstyle: [\hardstyle, \distorded],
|
||||
\dnb: [\dnb, \punchy],
|
||||
\amen: [\amen, \punchy],
|
||||
\jungle: [\jungle, \click],
|
||||
\house: [\house, \909],
|
||||
\electro: [\electro, \click],
|
||||
\detroit: [\four, \909],
|
||||
\minimal: [\minimal, \rond],
|
||||
\phonk: [\half, \808],
|
||||
\afro: [\afro, \rond],
|
||||
\garage: [\garage, \rond],
|
||||
\triphop: [\triphop, \boomy],
|
||||
\footwork: [\footwork, \punchy],
|
||||
);
|
||||
|
||||
// --- Fonctions stockees dans le dict (appelees via ~k[\key].(args)) -
|
||||
// Signatures normales (PAS de `self`) -- jamais appelees en pseudo-
|
||||
// method (`.key`) sur l'event `~k`.
|
||||
|
||||
~k[\pat] = { |name|
|
||||
var p = if (name.isInteger) {
|
||||
~k[\patterns].values[(name - 1).clip(0, ~k[\patterns].size - 1)];
|
||||
} { ~k[\patterns][name] };
|
||||
if (p.isNil) {
|
||||
("[k] pattern '" ++ name ++ "' inconnu. Liste : " ++ ~k[\patterns].keys.asArray).postln;
|
||||
} {
|
||||
~kickSteps = p.copy;
|
||||
~reload.value;
|
||||
("[k.pat] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~k[\tim] = { |name|
|
||||
var t = if (name.isInteger) {
|
||||
~k[\timbres].values[(name - 1).clip(0, ~k[\timbres].size - 1)];
|
||||
} { ~k[\timbres][name] };
|
||||
if (t.isNil) {
|
||||
("[k] timbre '" ++ name ++ "' inconnu. Liste : " ++ ~k[\timbres].keys.asArray).postln;
|
||||
} {
|
||||
~kickFreq = t[\freq];
|
||||
~kickPitchAmt = t[\pitchAmt];
|
||||
~kickDecay = t[\decay];
|
||||
~kickDrive = t[\drive];
|
||||
~kickClick = t[\click];
|
||||
~reload.value;
|
||||
("[k.tim] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~k[\go] = { |name|
|
||||
var c = ~k[\combos][name];
|
||||
if (c.isNil) {
|
||||
~k[\pat].(name);
|
||||
} {
|
||||
~k[\pat].(c[0]);
|
||||
~k[\tim].(c[1]);
|
||||
("[k] combo " ++ name ++ " (" ++ c[0] ++ "+" ++ c[1] ++ ")").postln;
|
||||
};
|
||||
};
|
||||
|
||||
~k[\list] = {
|
||||
"=== ~k -- KICKS ===".postln;
|
||||
" combos : ".post; ~k[\combos].keys.asArray.sort.postln;
|
||||
" patterns : ".post; ~k[\patterns].keys.asArray.sort.postln;
|
||||
" timbres : ".post; ~k[\timbres].keys.asArray.sort.postln;
|
||||
" USAGE : ~kk.(\\techno) | ~kPat.(\\amen) | ~kTim.(\\808)".postln;
|
||||
};
|
||||
|
||||
// --- API utilisateur : variables d'env top-level --------------------
|
||||
// Ces wrappers acceptent les vrais args correctement.
|
||||
~kPat = { |name| ~k[\pat].(name) };
|
||||
~kTim = { |name| ~k[\tim].(name) };
|
||||
~kGo = { |name| ~k[\go].(name) };
|
||||
~kList = { ~k[\list].() };
|
||||
~kk = { |name| ~k[\go].(name) }; // alias court
|
||||
|
||||
"=== ~k pret -- ~kk.(\\techno) | ~kPat.(\\amen) | ~kTim.(\\808) | ~kList.() ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES (Cmd+Entree pour appliquer)
|
||||
// =====================================================================
|
||||
|
||||
--- combos prets ---
|
||||
( ~kk.(\techno); )
|
||||
( ~kk.(\gabber); )
|
||||
( ~kk.(\dub); )
|
||||
( ~kk.(\trance); )
|
||||
( ~kk.(\amen); )
|
||||
( ~kk.(\hardstyle); )
|
||||
( ~kk.(\dnb); )
|
||||
( ~kk.(\phonk); )
|
||||
( ~kk.(\detroit); )
|
||||
|
||||
--- pattern seul ---
|
||||
( ~kPat.(\amen); )
|
||||
( ~kPat.(\dense); )
|
||||
( ~kPat.(\off); ) // silence
|
||||
|
||||
--- timbre seul ---
|
||||
( ~kTim.(\808); )
|
||||
( ~kTim.(\909); )
|
||||
( ~kTim.(\distorded); )
|
||||
|
||||
--- accès direct par index ---
|
||||
( ~kPat.(7); ) // pattern n°7
|
||||
( ~kTim.(3); ) // timbre n°3
|
||||
|
||||
--- liste tout ---
|
||||
( ~kList.(); )
|
||||
+1393
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,826 @@
|
||||
// =====================================================================
|
||||
// live_fx_panel.scd -- PANNEAU FX LIVE (tout-en-un)
|
||||
//
|
||||
// USAGE :
|
||||
// 1. PREREQUIS -- evaluer les SETUP de :
|
||||
// - engine.scd (charge avec CHARGER TOUT du 00_load.scd)
|
||||
// - fx_bus.scd (Cmd+Entree sur le SETUP)
|
||||
// - live.scd (Cmd+Entree sur le SETUP)
|
||||
// 2. Lance une track ou les Pdef
|
||||
// 3. Cmd+Entree sur n'importe quel bloc de ce panneau pour declencher l'effet
|
||||
//
|
||||
// Toutes les commandes sont protegees par garde `~helper !? { ... }`
|
||||
// pour ne rien casser si un setup n'a pas ete evalue.
|
||||
//
|
||||
// CATEGORIES :
|
||||
// [A] FX BUS DYNAMIQUE (send / setFx / preset / freeze)
|
||||
// [B] LFO ASSIGNABLES (sur n'importe quelle variable)
|
||||
// [C] VCF MASTER (8 types + presets)
|
||||
// [D] TRICKS SCENIQUES (drop / breakdown / buildup / stutter ...)
|
||||
// [E] FX MOMENTANES (bitcrush / ringmod / freqshift / granfreeze ...)
|
||||
// [F] AUTO-PAN / TREMOLO
|
||||
// [G] FX SYNTHS ONESHOT (riser / sweep / impact / crash / vinyl / gong ...)
|
||||
// [H] FILLS RYTHMIQUES (snareFill / tomFill)
|
||||
// [I] MASTER COMP / SAT
|
||||
// [J] FX PAR GENRE (combos prets a l'emploi)
|
||||
// [K] TAP TEMPO
|
||||
// [L] FX BUS DETAIL (param par param par FX)
|
||||
// [M] STOP ALL FX (reset global)
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [A] FX BUS DYNAMIQUE
|
||||
// ~send.(\fx, amount) | ~setFx.(\fx, key, val) | ~fxPreset.(\preset)
|
||||
// =====================================================================
|
||||
|
||||
// --- Sends raccourcis (par bus) -----
|
||||
( ~sendReverb !? { ~sendReverb.(0.4) }; )
|
||||
( ~sendDelay !? { ~sendDelay.(0.3) }; )
|
||||
( ~sendChorus !? { ~sendChorus.(0.3) }; )
|
||||
( ~sendPhaser !? { ~sendPhaser.(0.4) }; )
|
||||
( ~sendFlanger !? { ~sendFlanger.(0.4) }; )
|
||||
( ~sendBitcrush !? { ~sendBitcrush.(0.4) }; )
|
||||
( ~sendTape !? { ~sendTape.(1.0) }; )
|
||||
( ~sendShimmer !? { ~sendShimmer.(0.5) }; )
|
||||
( ~sendDist !? { ~sendDist.(0.4) }; )
|
||||
|
||||
// --- Sends par FX/key (si tu veux varier) -----
|
||||
( ~send !? { ~send.(\rev, 0.4) }; )
|
||||
( ~send !? { ~send.(\dly, 0.3) }; )
|
||||
( ~send !? { ~send.(\chr, 0.3) }; )
|
||||
( ~send !? { ~send.(\phs, 0.4) }; )
|
||||
( ~send !? { ~send.(\flg, 0.4) }; )
|
||||
( ~send !? { ~send.(\crsh, 0.4) }; )
|
||||
( ~send !? { ~send.(\tape, 1.0) }; )
|
||||
( ~send !? { ~send.(\shim, 0.5) }; )
|
||||
( ~send !? { ~send.(\dist, 0.4) }; )
|
||||
|
||||
// --- Tout couper (sec) -----
|
||||
( ~send !? {
|
||||
[\rev,\dly,\chr,\phs,\flg,\crsh,\tape,\shim,\dist].do { |k| ~send.(k, 0) };
|
||||
}; )
|
||||
|
||||
// --- Reverb : mix max + room cathedrale -----
|
||||
( ~setFx !? { ~setFx.(\rev, \mix, 0.7) }; )
|
||||
( ~setFx !? { ~setFx.(\rev, \room, 0.97); ~setFx.(\rev, \damp, 0.1) }; )
|
||||
|
||||
// --- Reverb FREEZE on / off (drone infini) -----
|
||||
( ~setFx !? { ~setFx.(\rev, \freeze, 1) }; )
|
||||
( ~setFx !? { ~setFx.(\rev, \freeze, 0) }; )
|
||||
|
||||
// --- Crossfade entre 2 FX -----
|
||||
( ~crossfadeFx !? { ~crossfadeFx.(\dly, \rev, 8) }; )
|
||||
( ~crossfadeFx !? { ~crossfadeFx.(\dist, \shim, 4) }; )
|
||||
|
||||
// --- PRESETS FX (combo predefini sur le bus FX) -----
|
||||
( ~fxPreset !? { ~fxPreset.(\dry) }; ) // tout off
|
||||
( ~fxPreset !? { ~fxPreset.(\dub) }; ) // rev hall + delay long + tape
|
||||
( ~fxPreset !? { ~fxPreset.(\space) }; ) // shimmer + reverb + chorus
|
||||
( ~fxPreset !? { ~fxPreset.(\trance) }; ) // rev + delay 1/8 + chorus
|
||||
( ~fxPreset !? { ~fxPreset.(\dubstep) }; ) // dist + bitcrush + reverb
|
||||
( ~fxPreset !? { ~fxPreset.(\retro) }; ) // bitcrush + tape + chorus
|
||||
( ~fxPreset !? { ~fxPreset.(\industrial) }; ) // dist + flanger + bitcrush
|
||||
( ~fxPreset !? { ~fxPreset.(\dream) }; ) // shimmer + reverb + chorus
|
||||
( ~fxPreset !? { ~fxPreset.(\cosmic) }; ) // phaser LFO + shimmer + reverb
|
||||
( ~fxPreset !? { ~fxPreset.(\drone) }; ) // reverb FROZEN + shimmer
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [B] LFO ASSIGNABLES (~lfoTo / ~lfoSync)
|
||||
// shape : \sin \tri \saw \sqr \rand \smoothRand \drunk \noise
|
||||
// =====================================================================
|
||||
|
||||
// --- LFO sin sur cutoff melody (rate 0.5Hz, depth 1500, center 2500) -----
|
||||
( ~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.5, 1500, \sin, 2500) }; )
|
||||
|
||||
// --- LFO triangle slow sur cutoff acid -----
|
||||
( ~lfoTo !? { ~lfoTo.(\acidCutoff, 0.25, 800, \tri, 1000) }; )
|
||||
|
||||
// --- LFO saw rising (montee progressive) sur cutoff melody -----
|
||||
( ~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.2, 2500, \saw, 3000) }; )
|
||||
|
||||
// --- LFO sqr asymetrique (pulseWidth=0.3) sur kickAmp -> rythmique -----
|
||||
( ~lfoTo !? { ~lfoTo.(\kickAmp, 2, 0.2, \sqr, 0.5, true, 0.3) }; )
|
||||
|
||||
// --- LFO random (sample-and-hold) sur amp acid -----
|
||||
( ~lfoTo !? { ~lfoTo.(\acidAmp, 4, 0.15, \rand, 0.32) }; )
|
||||
|
||||
// --- LFO smooth random sur amp harmony -----
|
||||
( ~lfoTo !? { ~lfoTo.(\harmonyAmp, 0.3, 0.08, \smoothRand, 0.14) }; )
|
||||
|
||||
// --- LFO drunken walk sur drive melody -----
|
||||
( ~lfoTo !? { ~lfoTo.(\melodyDrive, 0.1, 0.8, \drunk, 1.2) }; )
|
||||
|
||||
// --- LFO noise pure (chaos) sur Rq melody -----
|
||||
( ~lfoTo !? { ~lfoTo.(\melodyRq, 5, 0.2, \noise, 0.3) }; )
|
||||
|
||||
// --- LFO sin sur wobbleRate (bass design en wobble) -----
|
||||
( ~lfoTo !? { ~lfoTo.(\melodyWobbleRate, 0.1, 4, \sin, 6) }; )
|
||||
|
||||
// --- LFO SYNC TEMPO : 1 cycle complet sur N beats -----
|
||||
( ~lfoSync !? { ~lfoSync.(\melodyCutoff, 4, 1500, \sin, 2500) }; ) // 4 beats
|
||||
( ~lfoSync !? { ~lfoSync.(\acidCutoff, 8, 600, \sin, 800) }; ) // 8 beats
|
||||
( ~lfoSync !? { ~lfoSync.(\melodyAmp, 0.25, 0.1, \tri, 0.16) }; ) // 1/4 beat = 16eme
|
||||
|
||||
// --- Stop UN LFO precis -----
|
||||
( ~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) }; )
|
||||
( ~lfoStopVar !? { ~lfoStopVar.(\acidCutoff) }; )
|
||||
( ~lfoStopVar !? { ~lfoStopVar.(\kickAmp) }; )
|
||||
|
||||
// --- Stop tous les LFO de variables (~xxx) -----
|
||||
( ~lfoStopAllVars !? { ~lfoStopAllVars.() }; )
|
||||
|
||||
// --- Stop TOUT (LFO vars + LFO FX) -----
|
||||
( ~lfoStopEverything !? { ~lfoStopEverything.() }; )
|
||||
|
||||
// --- Liste les LFO actifs -----
|
||||
( ~lfoList !? { ~lfoList.() }; )
|
||||
|
||||
// --- LFO sur PARAM FX (sur le bus FX, different de ~lfoTo) -----
|
||||
( ~lfo !? { ~lfo.(\dly, \feedback, 0.1, 0.2, 0.85, \sin) }; )
|
||||
( ~lfo !? { ~lfo.(\rev, \mix, 0.05, 0.1, 0.7, \tri) }; )
|
||||
( ~lfo !? { ~lfo.(\crsh, \bits, 0.2, 4, 12, \sqr) }; )
|
||||
( ~lfo !? { ~lfo.(\phs, \rate, 0.02, 0.1, 1.5, \sin) }; )
|
||||
( ~lfo !? { ~lfo.(\shim, \shimmer, 0.1, 0.2, 0.8, \rand) }; )
|
||||
|
||||
// --- Stop un LFO FX precis -----
|
||||
( ~lfoStop !? { ~lfoStop.(\dly, \feedback) }; )
|
||||
|
||||
// --- Stop tous les LFO FX (sans toucher aux LFO vars) -----
|
||||
( ~lfoStopAll !? { ~lfoStopAll.() }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [C] VCF MASTER (filtre insere sur tout le mix)
|
||||
// types : \moog \ms20 \ladder \formant \comb \hpf \bpf \notch
|
||||
// =====================================================================
|
||||
|
||||
// --- Activation par type -----
|
||||
( ~vcfOn !? { ~vcfOn.(\moog, 800, 0.7) }; ) // 4-pole vintage
|
||||
( ~vcfOn !? { ~vcfOn.(\ms20, 900, 0.6) }; ) // Sallen-Key agressif
|
||||
( ~vcfOn !? { ~vcfOn.(\ladder, 900, 0.5) }; ) // 24 dB/oct
|
||||
( ~vcfOn !? { ~vcfOn.(\formant, 0, 0.15) }; ) // freq=vowel index 0..4
|
||||
( ~vcfOn !? { ~vcfOn.(\comb, 220, 1.5) }; ) // resonator
|
||||
( ~vcfOn !? { ~vcfOn.(\hpf, 400, 0.5) }; ) // HPF resonant
|
||||
( ~vcfOn !? { ~vcfOn.(\bpf, 1200, 0.4) }; ) // BPF resonant
|
||||
( ~vcfOn !? { ~vcfOn.(\notch, 1000, 0.3) }; ) // BRF (anti-bande)
|
||||
|
||||
// --- Set un parametre du VCF actif -----
|
||||
( ~vcfSet !? { ~vcfSet.(\freq, 1500) }; )
|
||||
( ~vcfSet !? { ~vcfSet.(\freq, 350) }; )
|
||||
( ~vcfSet !? { ~vcfSet.(\mix, 0.8) }; )
|
||||
|
||||
// --- Sweep automatique du cutoff -----
|
||||
( ~vcfSweep !? { ~vcfSweep.(200, 5000, 4) }; ) // up 4s
|
||||
( ~vcfSweep !? { ~vcfSweep.(8000, 200, 4) }; ) // down 4s
|
||||
( ~vcfSweep !? { ~vcfSweep.(400, 6000, 8, \exp) }; )
|
||||
|
||||
// --- PRESETS VCF -----
|
||||
( ~vcfPreset !? { ~vcfPreset.(\acid) }; ) // moog 600 q=0.85
|
||||
( ~vcfPreset !? { ~vcfPreset.(\dub) }; ) // ladder 900 q=0.5
|
||||
( ~vcfPreset !? { ~vcfPreset.(\deep) }; ) // moog 400 q=0.4
|
||||
( ~vcfPreset !? { ~vcfPreset.(\bright) }; ) // bpf 3500 q=0.4
|
||||
( ~vcfPreset !? { ~vcfPreset.(\dark) }; ) // moog 250 q=0.3
|
||||
( ~vcfPreset !? { ~vcfPreset.(\formantA) }; )
|
||||
( ~vcfPreset !? { ~vcfPreset.(\formantE) }; )
|
||||
( ~vcfPreset !? { ~vcfPreset.(\formantI) }; )
|
||||
( ~vcfPreset !? { ~vcfPreset.(\formantO) }; )
|
||||
( ~vcfPreset !? { ~vcfPreset.(\formantU) }; )
|
||||
|
||||
// --- VCF off -----
|
||||
( ~vcfOff !? { ~vcfOff.() }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [D] TRICKS SCENIQUES (~drop / ~breakdown / ~buildup / ~stutter ...)
|
||||
// =====================================================================
|
||||
|
||||
// --- DROP : silence -> fill -> freeze -> blast -----
|
||||
( ~drop !? { ~drop.(4) }; ) // build 4s
|
||||
( ~drop !? { ~drop.(8) }; ) // build 8s
|
||||
|
||||
// --- BREAKDOWN progressif -----
|
||||
( ~breakdown !? { ~breakdown.(8) }; )
|
||||
( ~breakdown !? { ~breakdown.(16) }; )
|
||||
|
||||
// --- BUILDUP crescendo (riser + filterSweepUp) -----
|
||||
( ~buildup !? { ~buildup.(8) }; )
|
||||
( ~buildup !? { ~buildup.(16) }; )
|
||||
|
||||
// --- HANDS UP : sub mute + lead boost + delay courte -----
|
||||
( ~handsUp !? { ~handsUp.() }; )
|
||||
|
||||
// --- STUTTER master (gate rythmique sur amps) -----
|
||||
( ~stutter !? { ~stutter.(8, 1) }; ) // 8Hz pendant 1s
|
||||
( ~stutter !? { ~stutter.(16, 0.5) }; ) // 16Hz pendant 0.5s
|
||||
( ~stutter !? { ~stutter.(4, 2) }; ) // 4Hz pendant 2s
|
||||
|
||||
// --- GLITCH : bitcrush + stutter + delay courte -----
|
||||
( ~glitch !? { ~glitch.(2) }; )
|
||||
( ~glitch !? { ~glitch.(4) }; )
|
||||
|
||||
// --- FREEZE : reverb freeze + cut sec -----
|
||||
( ~freeze !? { ~freeze.(4) }; )
|
||||
( ~freeze !? { ~freeze.(8) }; )
|
||||
|
||||
// --- REVERB TAIL : kill all + reverb send max + queue dur s -----
|
||||
( ~reverbTail !? { ~reverbTail.(4) }; )
|
||||
( ~reverbTail !? { ~reverbTail.(8) }; )
|
||||
|
||||
// --- TAPE STOP : ralenti tempo puis stop -----
|
||||
( ~tapeStop !? { ~tapeStop.(2) }; )
|
||||
( ~tapeStop !? { ~tapeStop.(4) }; )
|
||||
|
||||
// --- TAPE REVERSE : sweep + freeze -----
|
||||
( ~tapeReverse !? { ~tapeReverse.(2) }; )
|
||||
( ~tapeReverse !? { ~tapeReverse.(4) }; )
|
||||
|
||||
// --- JUMP CUT : silence sec dur s puis reprend -----
|
||||
( ~jumpCut !? { ~jumpCut.(0.5) }; )
|
||||
( ~jumpCut !? { ~jumpCut.(1) }; )
|
||||
( ~jumpCut !? { ~jumpCut.(2) }; )
|
||||
|
||||
// --- SWAP scene A -> scene B (necessite ~scene) -----
|
||||
( ~swap !? { ~swap.(\sceneA, \sceneB, 4) }; )
|
||||
|
||||
// --- CHOKE : coupe la rythmique / lead -----
|
||||
( ~chokePerc !? { ~chokePerc.() }; )
|
||||
( ~chokeLead !? { ~chokeLead.() }; )
|
||||
|
||||
// --- ENV one-shot sur une var (attack/sustain/release) -----
|
||||
( ~envTo !? { ~envTo.(\melodyCutoff, 0.5, 1.0, 2.0, 6000, 1500) }; )
|
||||
|
||||
// --- ENV burst percussif sur une var -----
|
||||
( ~envBurst !? { ~envBurst.(\acidCutoff, 4000, 0.3) }; )
|
||||
|
||||
// --- ENV sweep (monte/descend lineaire ou expo) -----
|
||||
( ~envSweep !? { ~envSweep.(\melodyCutoff, 200, 6000, 4, \exp) }; )
|
||||
( ~envSweep !? { ~envSweep.(\melodyCutoff, 6000, 200, 4, \exp) }; )
|
||||
|
||||
// --- Filter sweep raccourcis -----
|
||||
( ~filterSweepUp !? { ~filterSweepUp.(4) }; )
|
||||
( ~filterSweepDown !? { ~filterSweepDown.(4) }; )
|
||||
|
||||
// --- AMP DUCK momentane sur tous les amps -----
|
||||
( ~ampDuck !? { ~ampDuck.(0.3, 0.7) }; )
|
||||
( ~ampDuck !? { ~ampDuck.(0.6, 0.5) }; )
|
||||
|
||||
// --- Sidechain dynamique (kick -> cible) -----
|
||||
( ~scTrigger !? { ~scTrigger.(\kick, \acid, 0.85) }; )
|
||||
( ~scTrigger !? { ~scTrigger.(\kick, \melody, 0.6) }; )
|
||||
( ~scTrigger !? { ~scTrigger.(\kick, \harmony, 0.6) }; )
|
||||
( ~scTrigger !? { ~scTrigger.(\kick, \master, 0.7) }; )
|
||||
|
||||
// --- SC auto global (pompe sur tout le mix) -----
|
||||
( ~scAuto !? { ~scAuto.(0.7) }; )
|
||||
|
||||
// --- SC off -----
|
||||
( ~scOff !? { ~scOff.() }; )
|
||||
|
||||
// --- COMBOS sceniques -----
|
||||
( ~breakdown !? { ~breakdown.(8); }; ~buildup !? { ~buildup.(8); }; ~drop !? { ~drop.(2); }; )
|
||||
( ~vcfPreset !? { ~vcfPreset.(\acid) }; ~lfoSync !? { ~lfoSync.(\acidCutoff, 8, 600, \sin, 800) }; )
|
||||
( ~scAuto !? { ~scAuto.(0.7) }; ~compOn !? { ~compOn.(\pump) }; ~satOn !? { ~satOn.(1.5) }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [E] FX MOMENTANES (~bitCrushNow / ~ringMod / ~freqShift / ~granFreeze ...)
|
||||
// =====================================================================
|
||||
|
||||
// --- SLIP TIME (pitch master sur dur s) -----
|
||||
( ~slipTime !? { ~slipTime.(0.5, 1) }; ) // -1 octave 1s
|
||||
( ~slipTime !? { ~slipTime.(2.0, 0.5) }; ) // +1 octave 0.5s
|
||||
( ~slipTime !? { ~slipTime.(0.75, 2) }; ) // -3st 2s
|
||||
|
||||
// --- BITCRUSH momentane -----
|
||||
( ~bitCrushNow !? { ~bitCrushNow.(4, 4000, 1) }; )
|
||||
( ~bitCrushNow !? { ~bitCrushNow.(6, 8000, 2) }; )
|
||||
( ~bitCrushNow !? { ~bitCrushNow.(3, 3000, 0.5) }; )
|
||||
|
||||
// --- RING MOD momentane -----
|
||||
( ~ringMod !? { ~ringMod.(150, 1) }; )
|
||||
( ~ringMod !? { ~ringMod.(300, 2) }; )
|
||||
( ~ringMod !? { ~ringMod.(50, 0.5) }; )
|
||||
|
||||
// --- FREQ SHIFT momentane -----
|
||||
( ~freqShift !? { ~freqShift.(50, 1) }; )
|
||||
( ~freqShift !? { ~freqShift.(-100, 2) }; )
|
||||
( ~freqShift !? { ~freqShift.(200, 0.5) }; )
|
||||
|
||||
// --- GRAN FREEZE momentane -----
|
||||
( ~granFreeze !? { ~granFreeze.(2) }; )
|
||||
( ~granFreeze !? { ~granFreeze.(4) }; )
|
||||
|
||||
// --- SCRATCH (vinyl-like) -----
|
||||
( ~scratch !? { ~scratch.(1, 0.3) }; )
|
||||
( ~scratch !? { ~scratch.(-1, 0.5) }; )
|
||||
|
||||
// --- BEAT REPEAT (gate stutter rythmique) -----
|
||||
( ~repeat !? { ~repeat.(8, 1) }; )
|
||||
( ~repeat !? { ~repeat.(16, 0.5) }; )
|
||||
( ~repeat !? { ~repeat.(4, 2) }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [F] AUTO-PAN / TREMOLO (par voix)
|
||||
// =====================================================================
|
||||
|
||||
// --- AUTOPAN par voix (sur ~xxxPan) -----
|
||||
( ~autoPan !? { ~autoPan.(\melody, 0.5, 0.8) }; )
|
||||
( ~autoPan !? { ~autoPan.(\acid, 0.3, 0.6) }; )
|
||||
( ~autoPan !? { ~autoPan.(\harmony, 0.2, 1.0) }; )
|
||||
|
||||
// --- TREMOLO par voix (LFO sur ~xxxAmp) -----
|
||||
( ~tremolo !? { ~tremolo.(\melody, 5, 0.5) }; )
|
||||
( ~tremolo !? { ~tremolo.(\acid, 8, 0.4) }; )
|
||||
( ~tremolo !? { ~tremolo.(\harmony, 3, 0.6) }; )
|
||||
|
||||
// --- Stop l'auto-fx d'une voie -----
|
||||
( ~stopAutoFx !? { ~stopAutoFx.(\melody) }; )
|
||||
( ~stopAutoFx !? { ~stopAutoFx.(\acid) }; )
|
||||
( ~stopAutoFx !? { ~stopAutoFx.(\harmony) }; )
|
||||
|
||||
// --- AUTOPAN / TREMOLO en SEND (sur le bus FX, voix indep) -----
|
||||
( ~addFx !? { ~addFx.(\autopan, [\rate, 0.5, \depth, 1]) }; ~send !? { ~send.(\autopan, 1.0) }; )
|
||||
( ~addFx !? { ~addFx.(\trem, [\rate, 6, \depth, 0.7]) }; ~send !? { ~send.(\trem, 1.0) }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [G] FX SYNTHS ONESHOT (riser / sweep / impact / crash / vinyl / gong ...)
|
||||
// =====================================================================
|
||||
|
||||
// --- RISER (montee filtree) -----
|
||||
( Synth(\riser, [\dur, 4, \startCutoff, 200, \endCutoff, 8000, \amp, 0.25]); )
|
||||
( Synth(\riser, [\dur, 8, \startCutoff, 300, \endCutoff, 10000, \amp, 0.30]); )
|
||||
( Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.35]); )
|
||||
|
||||
// --- SWEEP (descente filtree) -----
|
||||
( Synth(\sweep, [\dur, 4, \startCutoff, 8000, \endCutoff, 200, \amp, 0.25]); )
|
||||
( Synth(\sweep, [\dur, 8, \startCutoff, 12000, \endCutoff, 200, \amp, 0.35]); )
|
||||
|
||||
// --- IMPACT (sub-boom de drop) -----
|
||||
( Synth(\impact, [\freq, 45, \decay, 1.5, \amp, 0.7]); )
|
||||
( Synth(\impact, [\freq, 35, \decay, 2.5, \amp, 0.8]); )
|
||||
( Synth(\impact, [\freq, 25, \decay, 4, \amp, 0.9]); ) // gabber
|
||||
|
||||
// --- CRASH (cymbale crash) -----
|
||||
( Synth(\crash, [\decay, 2.0, \amp, 0.3]); )
|
||||
( Synth(\crash, [\decay, 4.0, \amp, 0.4]); )
|
||||
( Synth(\crash, [\decay, 6.0, \amp, 0.5]); )
|
||||
|
||||
// --- GONG (asia, decay long) -----
|
||||
( Synth(\gong, [\freq, 50, \decay, 8, \amp, 0.5]); )
|
||||
( Synth(\gong, [\freq, 40, \decay, 12, \amp, 0.6]); )
|
||||
( Synth(\gong, [\freq, 25, \decay, 30, \amp, 0.95]); ) // drone doom
|
||||
|
||||
// --- VINYL (crackle continu) on / off -----
|
||||
( ~vinyl !? { ~vinyl.free }; ~vinyl = Synth(\vinyl, [\amp, 0.05]); "vinyl ON".postln; )
|
||||
( ~vinyl !? { ~vinyl.free }; ~vinyl = Synth(\vinyl, [\amp, 0.10]); "vinyl ON normal".postln; )
|
||||
( ~vinyl !? { ~vinyl.free }; ~vinyl = Synth(\vinyl, [\amp, 0.15]); "vinyl ON fort".postln; )
|
||||
( ~vinyl !? { ~vinyl.free; ~vinyl = nil }; "vinyl OFF".postln; )
|
||||
|
||||
// --- TAIKO / TOM / SNARE / CLAP / KICKS one-shots -----
|
||||
( Synth(\taiko, [\freq, 80, \decay, 0.6, \amp, 0.5]); )
|
||||
( Synth(\tom, [\freq, 120, \decay, 0.3, \amp, 0.5]); )
|
||||
( Synth(\snare, [\amp, 0.5, \decay, 0.06, \freq, 220]); )
|
||||
( Synth(\clap, [\amp, 0.4, \decay, 0.3]); )
|
||||
( Synth(\kick808, [\freq, 35, \decay, 1.2, \amp, 0.7]); )
|
||||
( Synth(\kickGabber, [\amp, 0.7]); )
|
||||
|
||||
// --- Cowbell, guzheng (asian) -----
|
||||
( Synth(\cowbell, [\freq, 800, \decay, 0.2, \amp, 0.4]); )
|
||||
( Synth(\guzheng, [\freq, 220, \amp, 0.18, \release, 1.0]); )
|
||||
|
||||
// --- SCRATCH SynthDef direct -----
|
||||
( Synth(\scratch, [\dur, 0.2, \freq, 1000, \sweepDir, 1, \amp, 0.4]); )
|
||||
( Synth(\scratch, [\dur, 0.3, \freq, 800, \sweepDir, -1, \amp, 0.4]); )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [H] FILLS RYTHMIQUES
|
||||
// =====================================================================
|
||||
|
||||
// --- Snare fill standard (8 hits / 1s) -----
|
||||
( ~snareFill !? { ~snareFill.value }; )
|
||||
|
||||
// --- Snare fill long accelerando (16 hits / 2s) -----
|
||||
( ~snareFill !? { ~snareFill.(16, 2, 0.2, 0.55) }; )
|
||||
|
||||
// --- Snare fill court rapide (32 hits / 1s -- roll) -----
|
||||
( ~snareFill !? { ~snareFill.(32, 1, 0.15, 0.6) }; )
|
||||
|
||||
// --- Snare fill epique (32 hits / 16s, build) -----
|
||||
( ~snareFill !? { ~snareFill.(32, 16, 0.2, 0.55) }; )
|
||||
|
||||
// --- Tom fill standard (descente 4 toms) -----
|
||||
( ~tomFill !? { ~tomFill.value }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [I] MASTER COMP / SAT
|
||||
// =====================================================================
|
||||
|
||||
// --- Compresseur ON par preset -----
|
||||
( ~compOn !? { ~compOn.(\soft) }; ) // glue tres leger
|
||||
( ~compOn !? { ~compOn.(\glue) }; ) // glue (default)
|
||||
( ~compOn !? { ~compOn.(\punch) }; ) // attack rapide
|
||||
( ~compOn !? { ~compOn.(\pump) }; ) // sidechain-style
|
||||
|
||||
// --- Compresseur OFF -----
|
||||
( ~compOff !? { ~compOff.() }; )
|
||||
|
||||
// --- Saturation ON par mode -----
|
||||
( ~satOn !? { ~satOn.(1.5, 0) }; ) // tanh doux
|
||||
( ~satOn !? { ~satOn.(2.0, 0) }; ) // tanh fort
|
||||
( ~satOn !? { ~satOn.(2.0, 1) }; ) // softclip
|
||||
( ~satOn !? { ~satOn.(1.8, 2) }; ) // fold (extreme)
|
||||
|
||||
// --- Saturation OFF -----
|
||||
( ~satOff !? { ~satOff.() }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [J] FX PAR GENRE (combos prets a l'emploi -- palette/fx_genre.scd)
|
||||
// Chaque bloc = transition / signature scenique complete
|
||||
// =====================================================================
|
||||
|
||||
// --- TRANCE BUILD-UP : snare roll + riser long + impact (16s) -----
|
||||
(
|
||||
~snareFill !? {
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.35]);
|
||||
~snareFill.(32, 16, 0.2, 0.55);
|
||||
fork {
|
||||
16.wait;
|
||||
Synth(\impact, [\freq, 35, \decay, 3, \amp, 0.7]);
|
||||
Synth(\crash, [\decay, 4, \amp, 0.4]);
|
||||
};
|
||||
"=== TRANCE BUILD 16s ===".postln;
|
||||
};
|
||||
)
|
||||
|
||||
// --- DUBSTEP DROP : impact + crash + riser court (4s) -----
|
||||
(
|
||||
Synth(\riser, [\dur, 4, \startCutoff, 500, \endCutoff, 11000, \amp, 0.4]);
|
||||
fork {
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 30, \decay, 3.5, \amp, 0.85]);
|
||||
Synth(\crash, [\decay, 3, \amp, 0.5]);
|
||||
};
|
||||
"=== DUBSTEP DROP 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- HARDCORE GABBER DROP : impact massif + double crash -----
|
||||
(
|
||||
Synth(\impact, [\freq, 25, \decay, 4, \amp, 0.9]);
|
||||
Synth(\crash, [\decay, 5, \amp, 0.6]);
|
||||
fork { 0.5.wait; Synth(\crash, [\decay, 3, \amp, 0.4]); };
|
||||
"=== HARDCORE DROP ===".postln;
|
||||
)
|
||||
|
||||
// --- DnB BUILD : snare roll accelerando + drop (4s) -----
|
||||
(
|
||||
~snareFill !? {
|
||||
~snareFill.(16, 4, 0.3, 0.6);
|
||||
fork {
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 40, \decay, 2.5, \amp, 0.65]);
|
||||
};
|
||||
"=== DnB BUILD 4s ===".postln;
|
||||
};
|
||||
)
|
||||
|
||||
// --- ASIAN CINEMATIC : gong cascade descendant -----
|
||||
(
|
||||
[40, 50, 60, 70].do { |f, i|
|
||||
fork { (i * 0.8).wait; Synth(\gong, [\freq, f, \decay, 8 - (i * 0.5), \amp, 0.45]); };
|
||||
};
|
||||
"=== GONG CASCADE 3s ===".postln;
|
||||
)
|
||||
|
||||
// --- DUB TECHNO ECHO : clap dub avec delay -----
|
||||
(
|
||||
fork {
|
||||
5.do { |i|
|
||||
Synth(\clap, [\amp, 0.4 - (i * 0.06), \decay, 0.3]);
|
||||
0.4.wait;
|
||||
};
|
||||
};
|
||||
"=== DUB ECHO CLAP ===".postln;
|
||||
)
|
||||
|
||||
// --- DETROIT FILTER SWEEP DOWN -----
|
||||
( Synth(\sweep, [\dur, 8, \startCutoff, 12000, \endCutoff, 200, \amp, 0.35]); )
|
||||
|
||||
// --- INDUSTRIAL TENSION : sweep slow + drone vinyl (16s) -----
|
||||
(
|
||||
Synth(\sweep, [\dur, 16, \startCutoff, 8000, \endCutoff, 100, \amp, 0.4]);
|
||||
~vinyl !? { ~vinyl.free };
|
||||
~vinyl = Synth(\vinyl, [\amp, 0.12]);
|
||||
fork { 16.wait; ~vinyl !? { ~vinyl.free; ~vinyl = nil }; };
|
||||
"=== INDUSTRIAL TENSION 16s ===".postln;
|
||||
)
|
||||
|
||||
// --- GLITCH IDM : scratch + impacts random -----
|
||||
(
|
||||
fork {
|
||||
8.do {
|
||||
if (0.6.coin) { Synth(\scratch, [\dur, rrand(0.1, 0.4), \freq, rrand(400, 2000),
|
||||
\sweepDir, [-1, 1].choose, \amp, 0.3]) };
|
||||
if (0.3.coin) { Synth(\impact, [\freq, rrand(40, 80), \decay, rrand(0.5, 1.5),
|
||||
\amp, 0.4]) };
|
||||
rrand(0.15, 0.5).wait;
|
||||
};
|
||||
};
|
||||
"=== GLITCH 8 hits 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- VOCAL TRANCE SWELL : riser + crash + impact (12s) -----
|
||||
(
|
||||
Synth(\riser, [\dur, 12, \startCutoff, 600, \endCutoff, 13000, \amp, 0.4]);
|
||||
fork {
|
||||
12.wait;
|
||||
Synth(\impact, [\freq, 38, \decay, 3, \amp, 0.7]);
|
||||
Synth(\crash, [\decay, 5, \amp, 0.45]);
|
||||
};
|
||||
"=== VOCAL TRANCE SWELL 12s ===".postln;
|
||||
)
|
||||
|
||||
// --- TRIBAL TOM ROLL DESCENDANT (taiko) -----
|
||||
(
|
||||
[180, 140, 110, 85, 70, 55, 40].do { |f, i|
|
||||
fork { (i * 0.12).wait; Synth(\taiko, [\freq, f, \decay, 0.6, \amp, 0.5]); };
|
||||
};
|
||||
"=== TRIBAL TOM ROLL ===".postln;
|
||||
)
|
||||
|
||||
// --- DRONE DOOM : gong tres profond (30s) -----
|
||||
(
|
||||
Synth(\gong, [\freq, 25, \decay, 30, \amp, 0.95]);
|
||||
fork { 5.wait; Synth(\gong, [\freq, 30, \decay, 25, \amp, 0.7]); };
|
||||
"=== DRONE DOOM gong massif 30s ===".postln;
|
||||
)
|
||||
|
||||
// --- HARDSTYLE BUILD : kick reverse + snare roll + impact (4s) -----
|
||||
(
|
||||
Synth(\sweep, [\dur, 4, \startCutoff, 200, \endCutoff, 8000, \amp, 0.45]);
|
||||
fork {
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 30, \decay, 3.5, \amp, 0.85]);
|
||||
Synth(\kickGabber, [\amp, 0.7]);
|
||||
};
|
||||
"=== HARDSTYLE BUILD 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- PHONK : vinyl + cowbell + 808 sub -----
|
||||
(
|
||||
~vinyl !? { ~vinyl.free };
|
||||
~vinyl = Synth(\vinyl, [\amp, 0.15]);
|
||||
fork {
|
||||
4.do {
|
||||
Synth(\cowbell, [\freq, 800, \decay, 0.2, \amp, 0.4]);
|
||||
0.5.wait;
|
||||
};
|
||||
Synth(\kick808, [\freq, 35, \decay, 1.2, \amp, 0.7]);
|
||||
};
|
||||
"=== PHONK VINYL 2.5s ===".postln;
|
||||
)
|
||||
|
||||
// --- FUTURE GARAGE : vocal-like swell + sub (6s) -----
|
||||
(
|
||||
Synth(\sweep, [\dur, 6, \startCutoff, 6000, \endCutoff, 800, \amp, 0.3]);
|
||||
fork { 5.wait; Synth(\impact, [\freq, 40, \decay, 2.5, \amp, 0.55]); };
|
||||
"=== FUTURE GARAGE SWELL 6s ===".postln;
|
||||
)
|
||||
|
||||
// --- SCRATCH FX x4 -----
|
||||
(
|
||||
4.do { |i|
|
||||
fork {
|
||||
(i * 0.15).wait;
|
||||
Synth(\scratch, [\dur, 0.2, \freq, 800 + (i * 200),
|
||||
\sweepDir, [-1, 1].choose, \amp, 0.4]);
|
||||
};
|
||||
};
|
||||
"=== SCRATCH x4 ===".postln;
|
||||
)
|
||||
|
||||
// --- GLITCH STUTTER : impacts rapides random -----
|
||||
(
|
||||
fork {
|
||||
16.do { |i|
|
||||
Synth(\impact, [\freq, rrand(35, 60), \decay, 0.15, \amp, 0.4]);
|
||||
rrand(0.06, 0.15).wait;
|
||||
};
|
||||
};
|
||||
"=== GLITCH STUTTER 2s ===".postln;
|
||||
)
|
||||
|
||||
// --- ASIAN MELODIC FILL (guzheng arpege descendant) -----
|
||||
(
|
||||
[79, 77, 75, 72, 70, 67, 65, 63, 60].do { |n, i|
|
||||
fork {
|
||||
(i * 0.15).wait;
|
||||
Synth(\guzheng, [\freq, n.midicps, \amp, 0.18, \release, 1.0]);
|
||||
};
|
||||
};
|
||||
"=== ASIAN GUZHENG FILL ===".postln;
|
||||
)
|
||||
|
||||
// --- DROP CUT brutal : coupe tout + sweep down + impact (2s) -----
|
||||
(
|
||||
~reload !? {
|
||||
Routine({
|
||||
var oldKick = ~kickAmp; var oldHat = ~hatAmp; var oldClap = ~clapAmp;
|
||||
~kickAmp = 0; ~hatAmp = 0; ~clapAmp = 0; ~reload.value;
|
||||
Synth(\sweep, [\dur, 2, \startCutoff, 8000, \endCutoff, 200, \amp, 0.4]);
|
||||
2.wait;
|
||||
Synth(\impact, [\freq, 30, \decay, 3, \amp, 0.85]);
|
||||
Synth(\crash, [\decay, 3, \amp, 0.4]);
|
||||
~kickAmp = oldKick; ~hatAmp = oldHat; ~clapAmp = oldClap; ~reload.value;
|
||||
}).play;
|
||||
"=== DROP CUT 2s ===".postln;
|
||||
};
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [K] TAP TEMPO (tap au moins 2 fois en rythme pour caler le delay)
|
||||
// =====================================================================
|
||||
|
||||
// --- Tap (au moins 2 fois successifs) -----
|
||||
( ~tap !? { ~tap.value }; )
|
||||
( ~tap !? { ~tap.value }; )
|
||||
( ~tap !? { ~tap.value }; )
|
||||
( ~tap !? { ~tap.value }; )
|
||||
|
||||
// --- Reset du tap (efface l'historique) -----
|
||||
( ~tapTempo !? { ~tapTempo[\last] = nil; "tap reset".postln }; )
|
||||
|
||||
// --- Set delayTime par division de tempo (sans tap) -----
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo / 4) }; ) // 1/16
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo / 2) }; ) // 1/8
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo) }; ) // 1/4
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo * 0.75) }; ) // 1/4 dotted
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 60 / TempoClock.default.tempo * 2) }; ) // 1/2
|
||||
|
||||
// --- Tempo en live (BPM direct) -----
|
||||
( TempoClock.default.tempo = 110/60; )
|
||||
( TempoClock.default.tempo = 132/60; )
|
||||
( TempoClock.default.tempo = 145/60; )
|
||||
( TempoClock.default.tempo = 174/60; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [L] FX BUS DETAIL (param par param par FX)
|
||||
// Pour chaque FX du bus, exposer les params principaux
|
||||
// =====================================================================
|
||||
|
||||
// ---------- REVERB ----------
|
||||
( ~setFx !? { ~setFx.(\rev, \mix, 0.4) }; ) // 0..1
|
||||
( ~setFx !? { ~setFx.(\rev, \room, 0.5) }; ) // 0..1 (small room)
|
||||
( ~setFx !? { ~setFx.(\rev, \room, 0.85) }; ) // hall
|
||||
( ~setFx !? { ~setFx.(\rev, \room, 0.97) }; ) // cathedral
|
||||
( ~setFx !? { ~setFx.(\rev, \damp, 0.6) }; ) // 0=brillant, 1=mat
|
||||
( ~setFx !? { ~setFx.(\rev, \damp, 0.1) }; ) // tres brillant
|
||||
( ~setFx !? { ~setFx.(\rev, \freeze, 1) }; )
|
||||
( ~setFx !? { ~setFx.(\rev, \freeze, 0) }; )
|
||||
|
||||
// ---------- DELAY ----------
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 0.375) }; ) // 1/8 a 120bpm
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 0.5) }; ) // 1/4
|
||||
( ~setFx !? { ~setFx.(\dly, \delayTime, 0.25) }; ) // 1/8 a 120
|
||||
( ~setFx !? { ~setFx.(\dly, \feedback, 0.5) }; ) // normal
|
||||
( ~setFx !? { ~setFx.(\dly, \feedback, 0.85) }; ) // self-oscillating
|
||||
( ~setFx !? { ~setFx.(\dly, \feedback, 0.2) }; ) // 2 echos
|
||||
( ~setFx !? { ~setFx.(\dly, \mix, 0.5) }; )
|
||||
( ~setFx !? { ~setFx.(\dly, \color, 0.3) }; ) // 0=tape dark, 1=clean
|
||||
|
||||
// ---------- CHORUS ----------
|
||||
( ~setFx !? { ~setFx.(\chr, \rate, 0.4) }; )
|
||||
( ~setFx !? { ~setFx.(\chr, \rate, 1.5) }; ) // rapide
|
||||
( ~setFx !? { ~setFx.(\chr, \depth, 0.005) }; ) // subtil
|
||||
( ~setFx !? { ~setFx.(\chr, \depth, 0.015) }; ) // large
|
||||
( ~setFx !? { ~setFx.(\chr, \mix, 0.5) }; )
|
||||
|
||||
// ---------- PHASER ----------
|
||||
( ~setFx !? { ~setFx.(\phs, \rate, 0.3) }; )
|
||||
( ~setFx !? { ~setFx.(\phs, \rate, 0.05) }; ) // tres slow
|
||||
( ~setFx !? { ~setFx.(\phs, \depth, 0.7) }; )
|
||||
( ~setFx !? { ~setFx.(\phs, \depth, 1.0) }; )
|
||||
( ~setFx !? { ~setFx.(\phs, \feedback, 0.4) }; )
|
||||
( ~setFx !? { ~setFx.(\phs, \feedback, 0.85) }; ) // self-osc
|
||||
( ~setFx !? { ~setFx.(\phs, \mix, 0.5) }; )
|
||||
|
||||
// ---------- FLANGER ----------
|
||||
( ~setFx !? { ~setFx.(\flg, \rate, 0.2) }; )
|
||||
( ~setFx !? { ~setFx.(\flg, \rate, 0.05) }; ) // jet plane slow
|
||||
( ~setFx !? { ~setFx.(\flg, \depth, 0.003) }; )
|
||||
( ~setFx !? { ~setFx.(\flg, \depth, 0.008) }; ) // tres prononce
|
||||
( ~setFx !? { ~setFx.(\flg, \feedback, 0.6) }; )
|
||||
( ~setFx !? { ~setFx.(\flg, \feedback, 0.9) }; ) // metallic
|
||||
( ~setFx !? { ~setFx.(\flg, \mix, 0.5) }; )
|
||||
|
||||
// ---------- BITCRUSH ----------
|
||||
( ~setFx !? { ~setFx.(\crsh, \bits, 8) }; ) // 8bit
|
||||
( ~setFx !? { ~setFx.(\crsh, \bits, 4) }; ) // 4bit
|
||||
( ~setFx !? { ~setFx.(\crsh, \bits, 2) }; ) // 2bit destroy
|
||||
( ~setFx !? { ~setFx.(\crsh, \sampleRate, 8000) }; ) // lo-fi
|
||||
( ~setFx !? { ~setFx.(\crsh, \sampleRate, 4000) }; ) // C64
|
||||
( ~setFx !? { ~setFx.(\crsh, \sampleRate, 2000) }; ) // gameboy
|
||||
( ~setFx !? { ~setFx.(\crsh, \mix, 0.6) }; )
|
||||
|
||||
// ---------- TAPE ----------
|
||||
( ~setFx !? { ~setFx.(\tape, \drive, 1.5) }; )
|
||||
( ~setFx !? { ~setFx.(\tape, \drive, 3.0) }; ) // saturated
|
||||
( ~setFx !? { ~setFx.(\tape, \wow, 0.0015) }; )
|
||||
( ~setFx !? { ~setFx.(\tape, \wow, 0.005) }; ) // wobble fort
|
||||
( ~setFx !? { ~setFx.(\tape, \flutter, 0.0008) }; )
|
||||
( ~setFx !? { ~setFx.(\tape, \flutter, 0.003) }; )
|
||||
( ~setFx !? { ~setFx.(\tape, \mix, 1.0) }; )
|
||||
|
||||
// ---------- SHIMMER ----------
|
||||
( ~setFx !? { ~setFx.(\shim, \shimmer, 0.5) }; )
|
||||
( ~setFx !? { ~setFx.(\shim, \shimmer, 0.9) }; ) // octave-up tres present
|
||||
( ~setFx !? { ~setFx.(\shim, \room, 0.92) }; )
|
||||
( ~setFx !? { ~setFx.(\shim, \mix, 0.5) }; )
|
||||
|
||||
// ---------- DIST ----------
|
||||
( ~setFx !? { ~setFx.(\dist, \drive, 3.0) }; )
|
||||
( ~setFx !? { ~setFx.(\dist, \drive, 5.0) }; ) // industriel
|
||||
( ~setFx !? { ~setFx.(\dist, \drive, 8.0) }; ) // wall of sound
|
||||
( ~setFx !? { ~setFx.(\dist, \tone, 0.5) }; ) // 0=dark, 1=bright
|
||||
( ~setFx !? { ~setFx.(\dist, \tone, 0.2) }; )
|
||||
( ~setFx !? { ~setFx.(\dist, \tone, 0.8) }; )
|
||||
( ~setFx !? { ~setFx.(\dist, \mix, 0.5) }; )
|
||||
|
||||
// ---------- FX additionnels (ajoutes via ~addFx) ----------
|
||||
( ~addFx !? { ~addFx.(\ringmod, [\freq, 200, \mix, 0.5]) }; ~send !? { ~send.(\ringmod, 0.4) }; )
|
||||
( ~addFx !? { ~addFx.(\fshift, [\shift, 80]) }; ~send !? { ~send.(\fshift, 0.3) }; )
|
||||
( ~addFx !? { ~addFx.(\gran, [\grainDur, 0.15, \pitch, 0.5]) }; ~send !? { ~send.(\gran, 0.4) }; )
|
||||
( ~addFx !? { ~addFx.(\comb, [\freq, 220, \decay, 2]) }; ~send !? { ~send.(\comb, 0.4) }; )
|
||||
( ~addFx !? { ~addFx.(\formant, [\vowel, 0]) }; ~send !? { ~send.(\formant, 0.5) }; )
|
||||
( ~addFx !? { ~addFx.(\autoflt, [\rate, 0.3, \lo, 200, \hi, 4000]) }; ~send !? { ~send.(\autoflt, 0.5) }; )
|
||||
( ~addFx !? { ~addFx.(\stut, [\rate, 8, \dutyCycle, 0.5]) }; ~send !? { ~send.(\stut, 1.0) }; )
|
||||
( ~addFx !? { ~addFx.(\reson, [\freq, 220, \decay, 3]) }; ~send !? { ~send.(\reson, 0.5) }; )
|
||||
( ~addFx !? { ~addFx.(\spring, [\decay, 1.5]) }; ~send !? { ~send.(\spring, 0.4) }; )
|
||||
( ~addFx !? { ~addFx.(\plate, [\decay, 2.5, \damp, 0.3]) }; ~send !? { ~send.(\plate, 0.4) }; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// [M] STOP ALL FX (reset global -- panique mode)
|
||||
// =====================================================================
|
||||
|
||||
// --- Stop tous les LFO (vars + FX) -----
|
||||
( ~lfoStopEverything !? { ~lfoStopEverything.() }; )
|
||||
|
||||
// --- VCF off -----
|
||||
( ~vcfOff !? { ~vcfOff.() }; )
|
||||
|
||||
// --- Comp / Sat off -----
|
||||
( ~compOff !? { ~compOff.() }; )
|
||||
( ~satOff !? { ~satOff.() }; )
|
||||
|
||||
// --- Reset FX bus (tout coupe) -----
|
||||
( ~fxPreset !? { ~fxPreset.(\dry) }; )
|
||||
|
||||
// --- Stop autoFx par voix -----
|
||||
( ~stopAutoFx !? { ~stopAutoFx.(\melody); }; )
|
||||
( ~stopAutoFx !? { ~stopAutoFx.(\acid); }; )
|
||||
( ~stopAutoFx !? { ~stopAutoFx.(\harmony); }; )
|
||||
|
||||
// --- Sidechain off -----
|
||||
( ~scOff !? { ~scOff.() }; )
|
||||
|
||||
// --- Vinyl off -----
|
||||
( ~vinyl !? { ~vinyl.free; ~vinyl = nil }; "vinyl OFF".postln; )
|
||||
|
||||
// --- Unfreeze reverb (au cas ou) -----
|
||||
( ~setFx !? { ~setFx.(\rev, \freeze, 0) }; )
|
||||
|
||||
// --- RESET TOTAL : combine tout ce qui precede -----
|
||||
(
|
||||
~lfoStopEverything !? { ~lfoStopEverything.() };
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~compOff !? { ~compOff.() };
|
||||
~satOff !? { ~satOff.() };
|
||||
~scOff !? { ~scOff.() };
|
||||
~stopAutoFx !? { [\melody, \acid, \harmony].do { |t| ~stopAutoFx.(t) } };
|
||||
~vinyl !? { ~vinyl.free; ~vinyl = nil };
|
||||
~setFx !? { ~setFx.(\rev, \freeze, 0) };
|
||||
~fxPreset !? { ~fxPreset.(\dry) };
|
||||
"=== FX RESET TOTAL ===".postln;
|
||||
)
|
||||
+693
@@ -0,0 +1,693 @@
|
||||
// =====================================================================
|
||||
// loops.scd -- Gestionnaire de pistes / boucles pour live SuperCollider
|
||||
//
|
||||
// PREREQUIS : engine.scd charge (Pdef nommes + ~bpm + ~reload).
|
||||
// Optionnel : palette/melodies/tracks.scd (~melTrackOn/Off),
|
||||
// palette/rhythm/sequences.scd (~seqPlay/~seqStop),
|
||||
// live/mixer.scd.
|
||||
//
|
||||
// CONCEPT
|
||||
// Une "boucle" est une entite a etat (ON / OFF, count, max, source).
|
||||
// Source possible :
|
||||
// - un Symbol -> Pdef de ce nom (ex: \kickSeq, \m1Seq)
|
||||
// - une Function -> jouee en Routine (yields = beats)
|
||||
//
|
||||
// HELPERS PRINCIPAUX
|
||||
// ~loopOn / ~loopOff / ~loopOffAll / ~loopToggle / ~loopIsOn
|
||||
// ~loopList / ~loopInfo / ~loopProgress / ~loopShow
|
||||
// ~loopRepeat / ~loopBeats / ~loopBars / ~loopSync
|
||||
// ~loopCount / ~loopReset / ~loopMax
|
||||
// ~loopCountdown / ~loopWithCountdown
|
||||
// ~loopSnapshot / ~loopRestore / ~loopSave / ~loopLoad
|
||||
// ~loopChain / ~loopParallel
|
||||
// ~loopFade / ~loopFadeIn / ~loopAutoStop / ~loopAutoFade
|
||||
// ~kickLoop / ~hatLoop / ~snareLoop / ~clapLoop / ~percLoop
|
||||
// ~acidLoop / ~melodyLoop / ~harmonyLoop / ~allOn / ~allOff
|
||||
//
|
||||
// Un seul bloc top-level pour compatibilite .load
|
||||
// =====================================================================
|
||||
(
|
||||
// ---------- Etat global ---------------------------------------------
|
||||
~loops = ~loops ?? { () }; // dict des boucles (Event)
|
||||
~loopsSnap = ~loopsSnap ?? { () }; // snapshots (params + amps)
|
||||
~loopAutos = ~loopAutos ?? { () }; // routines d'auto-stop / auto-fade
|
||||
~loopChainR = ~loopChainR ?? { nil }; // routine chain en cours
|
||||
~loopParR = ~loopParR ?? { () }; // routines parallel par groupe
|
||||
|
||||
// ---------- Pdef du moteur (8 voies nommees) ------------------------
|
||||
~loopEngineSyms = [\kickSeq, \hatSeq, \snareSeq, \clapSeq,
|
||||
\percSeq, \acidSeq, \melodySeq, \harmonySeq];
|
||||
|
||||
// ---------- Utilitaires internes ------------------------------------
|
||||
// Renvoie true si la source est un Symbol qui correspond a un Pdef
|
||||
~loopIsPdef = { |source| source.isKindOf(Symbol) };
|
||||
|
||||
// Demarre une source dans une Routine (Function) ou via Pdef (Symbol).
|
||||
// Renvoie une "handle" : un EventStreamPlayer / Routine selon le cas.
|
||||
~loopStartSource = { |source, name|
|
||||
var handle;
|
||||
if (~loopIsPdef.(source)) {
|
||||
Pdef(source).play;
|
||||
handle = (kind: \pdef, sym: source);
|
||||
} {
|
||||
// Function : on l'execute en Routine. La fonction recoit le
|
||||
// nom de la boucle pour pouvoir incrementer le compteur si elle
|
||||
// veut (sinon on incrementera depuis l'exterieur).
|
||||
var r = Routine({ source.value(name) }).play;
|
||||
handle = (kind: \routine, rout: r);
|
||||
};
|
||||
handle
|
||||
};
|
||||
|
||||
~loopStopHandle = { |h|
|
||||
if (h.notNil) {
|
||||
switch (h[\kind],
|
||||
\pdef, { Pdef(h[\sym]).stop },
|
||||
\routine, { h[\rout] !? { h[\rout].stop } }
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 1. GESTION DE BASE (on/off/toggle/list/isOn)
|
||||
// =====================================================================
|
||||
|
||||
// ~loopOn.(\name, source [, max])
|
||||
// source : Symbol (Pdef) ou Function. max optionnel (defaut inf).
|
||||
~loopOn = { |name, source, max = inf|
|
||||
var l = ~loops[name];
|
||||
if (l.notNil and: { l[\state] == \on }) {
|
||||
("[loop] " ++ name ++ " deja ON").postln;
|
||||
} {
|
||||
// Source heritee si pas fournie
|
||||
var src = source ?? { l !? { l[\source] } };
|
||||
if (src.isNil) {
|
||||
("[loop] " ++ name ++ " : pas de source connue").postln;
|
||||
} {
|
||||
var handle = ~loopStartSource.(src, name);
|
||||
~loops[name] = (
|
||||
state: \on,
|
||||
source: src,
|
||||
handle: handle,
|
||||
count: (l !? { l[\count] }) ? 0,
|
||||
max: max,
|
||||
startedAt: Main.elapsedTime,
|
||||
lastResetAt: Main.elapsedTime,
|
||||
);
|
||||
("[loop] ON " ++ name).postln;
|
||||
};
|
||||
};
|
||||
name
|
||||
};
|
||||
|
||||
~loopOff = { |name|
|
||||
var l = ~loops[name];
|
||||
if (l.isNil) {
|
||||
("[loop] " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
~loopStopHandle.(l[\handle]);
|
||||
// Annule auto-stop / auto-fade en cours
|
||||
~loopAutos[name] !? { |r| r.stop; ~loopAutos[name] = nil };
|
||||
l[\state] = \off;
|
||||
l[\handle] = nil;
|
||||
("[loop] OFF " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~loopOffAll = {
|
||||
~loops.keysDo { |k|
|
||||
var l = ~loops[k];
|
||||
if (l.notNil and: { l[\state] == \on }) { ~loopOff.(k) };
|
||||
};
|
||||
"[loop] offAll".postln;
|
||||
};
|
||||
|
||||
~loopToggle = { |name|
|
||||
var l = ~loops[name];
|
||||
if (l.notNil and: { l[\state] == \on }) {
|
||||
~loopOff.(name);
|
||||
} {
|
||||
~loopOn.(name);
|
||||
};
|
||||
};
|
||||
|
||||
~loopIsOn = { |name|
|
||||
var l = ~loops[name];
|
||||
(l.notNil and: { l[\state] == \on })
|
||||
};
|
||||
|
||||
// Affichage : etat / source / count / max
|
||||
~loopList = {
|
||||
"=== loops ===".postln;
|
||||
if (~loops.isEmpty) {
|
||||
" (aucune boucle)".postln;
|
||||
} {
|
||||
~loops.keysValuesDo { |k, v|
|
||||
var st = if (v[\state] == \on) { "ON " } { "off" };
|
||||
var src = v[\source];
|
||||
var srcStr = if (src.isKindOf(Symbol)) { src.asString }
|
||||
{ if (src.isKindOf(Function)) { "<fn>" } { "?" } };
|
||||
var maxStr = if (v[\max] == inf) { "inf" } { v[\max].asString };
|
||||
(" [" ++ st ++ "] " ++ k
|
||||
++ " src=" ++ srcStr
|
||||
++ " count=" ++ (v[\count] ? 0)
|
||||
++ "/" ++ maxStr
|
||||
).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 2. COMPTEURS
|
||||
// =====================================================================
|
||||
|
||||
// ~loopRepeat.(\name, source, n, dur)
|
||||
// Joue source N fois (chaque iter dure `dur` battements), puis stop.
|
||||
~loopRepeat = { |name, source, n = 4, dur = 4|
|
||||
var t = TempoClock.default;
|
||||
var max = n;
|
||||
~loopOn.(name, source, max);
|
||||
// Routine qui incremente le compteur a chaque dur, et stoppe a max
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
n.do { |i|
|
||||
dur.wait;
|
||||
if (~loops[name].notNil) {
|
||||
~loops[name][\count] = (~loops[name][\count] ? 0) + 1;
|
||||
};
|
||||
};
|
||||
// Fin atteinte : stop
|
||||
~loopOff.(name);
|
||||
}).play(t);
|
||||
("[loop] repeat " ++ name ++ " n=" ++ n ++ " dur=" ++ dur ++ "b").postln;
|
||||
name
|
||||
};
|
||||
|
||||
~loopCount = { |name|
|
||||
var l = ~loops[name];
|
||||
if (l.isNil) { 0 } { l[\count] ? 0 }
|
||||
};
|
||||
|
||||
~loopReset = { |name|
|
||||
var l = ~loops[name];
|
||||
if (l.notNil) {
|
||||
l[\count] = 0;
|
||||
l[\lastResetAt] = Main.elapsedTime;
|
||||
("[loop] reset " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~loopMax = { |name, n|
|
||||
var l = ~loops[name];
|
||||
if (l.notNil) {
|
||||
l[\max] = n;
|
||||
("[loop] max " ++ name ++ " = " ++ n).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 3. SYNCHRONISATION AU TEMPO
|
||||
// =====================================================================
|
||||
|
||||
// Joue une source pendant N battements, puis stop.
|
||||
~loopBeats = { |name, source, beats = 16|
|
||||
var t = TempoClock.default;
|
||||
~loopOn.(name, source, beats);
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
beats.wait;
|
||||
~loopOff.(name);
|
||||
}).play(t);
|
||||
("[loop] " ++ name ++ " pendant " ++ beats ++ " beats").postln;
|
||||
name
|
||||
};
|
||||
|
||||
// N mesures (defaut 4 battements/mesure)
|
||||
~loopBars = { |name, source, bars = 4, beatsPerBar = 4|
|
||||
~loopBeats.(name, source, bars * beatsPerBar);
|
||||
};
|
||||
|
||||
// Aligne le demarrage de toutes les boucles ON au prochain temps fort
|
||||
// (utilise pour resync apres avoir lance plusieurs boucles).
|
||||
~loopSync = { |beatsPerBar = 4|
|
||||
var t = TempoClock.default;
|
||||
var now = t.beats;
|
||||
var nextBar = now.ceil + ((beatsPerBar - (now.ceil.asInteger % beatsPerBar)) % beatsPerBar);
|
||||
var wait = nextBar - now;
|
||||
var snapshot = (); // {name -> source}
|
||||
~loops.keysValuesDo { |k, v|
|
||||
if (v[\state] == \on) { snapshot[k] = v[\source] };
|
||||
};
|
||||
if (snapshot.isEmpty) {
|
||||
"[loop] sync : aucune boucle ON".postln;
|
||||
} {
|
||||
("[loop] sync dans " ++ wait.round(0.01) ++ " beats ("
|
||||
++ snapshot.size ++ " boucles)").postln;
|
||||
// Stop immediat, restart sur la barre suivante
|
||||
snapshot.keysDo { |k| ~loopOff.(k) };
|
||||
Routine({
|
||||
wait.wait;
|
||||
snapshot.keysValuesDo { |k, src| ~loopOn.(k, src) };
|
||||
"[loop] sync OK".postln;
|
||||
}).play(t);
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 4. PRE-ROLL / COUNTDOWN
|
||||
// =====================================================================
|
||||
|
||||
// Compte avant de lancer une action. action est une Function (sans arg).
|
||||
~loopCountdown = { |beats = 4, action|
|
||||
var t = TempoClock.default;
|
||||
Routine({
|
||||
beats.do { |i|
|
||||
var n = beats - i;
|
||||
(n.asString ++ "...").postln;
|
||||
1.wait;
|
||||
};
|
||||
"GO".postln;
|
||||
action !? { action.value };
|
||||
}).play(t);
|
||||
("[loop] countdown " ++ beats ++ "b").postln;
|
||||
};
|
||||
|
||||
// Countdown puis lance la boucle (max optionnel)
|
||||
~loopWithCountdown = { |name, source, beats = 4, max = inf|
|
||||
~loopCountdown.(beats, { ~loopOn.(name, source, max) });
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 5. SNAPSHOT / RESTORE / SAVE / LOAD
|
||||
// =====================================================================
|
||||
|
||||
// Cle des "params interessants" a sauvegarder (heuristique).
|
||||
// On capture toutes les vars ~xxx qui sont des Number/Symbol/SimpleNumber
|
||||
// liees au prefixe du nom (ex: \kick -> ~kickAmp, ~kickDrive...) +
|
||||
// les amps connus du moteur.
|
||||
~loopSnapKeys = (~loopSnapKeys ?? { [
|
||||
\bpm,
|
||||
\kickAmp, \kickDrive, \kickDecay,
|
||||
\hatAmp, \hatDecay,
|
||||
\snareAmp, \snareDrive,
|
||||
\clapAmp,
|
||||
\percAmp,
|
||||
\acidAmp, \acidCutoff, \acidDrive, \acidRq,
|
||||
\melodyAmp, \melodyBoost, \melodyCutoff,
|
||||
\harmonyAmp,
|
||||
\leadScAmt, \scShape,
|
||||
] });
|
||||
|
||||
~loopSnapshot = { |name|
|
||||
var snap = ();
|
||||
~loopSnapKeys.do { |k|
|
||||
var v = currentEnvironment[k];
|
||||
if (v.notNil and: { v.isKindOf(Number) or: { v.isKindOf(Symbol) } }) {
|
||||
snap[k] = v;
|
||||
};
|
||||
};
|
||||
// Ajoute les coefs mixer si presents
|
||||
if (~mix.notNil) { snap[\__mix] = ~mix.copy };
|
||||
// Ajoute l'etat de la boucle si elle existe
|
||||
if (~loops[name].notNil) {
|
||||
snap[\__loopState] = (
|
||||
count: ~loops[name][\count] ? 0,
|
||||
max: ~loops[name][\max] ? inf,
|
||||
source: ~loops[name][\source]
|
||||
);
|
||||
};
|
||||
~loopsSnap[name] = snap;
|
||||
("[loop] snapshot " ++ name ++ " (" ++ snap.size ++ " cles)").postln;
|
||||
snap
|
||||
};
|
||||
|
||||
~loopRestore = { |name|
|
||||
var snap = ~loopsSnap[name];
|
||||
if (snap.isNil) {
|
||||
("[loop] restore : pas de snapshot pour " ++ name).postln;
|
||||
} {
|
||||
snap.keysValuesDo { |k, v|
|
||||
if (k == \__mix) {
|
||||
if (~mix.notNil) {
|
||||
v.keysValuesDo { |k2, v2| ~mix[k2] = v2 };
|
||||
};
|
||||
} {
|
||||
if (k != \__loopState) {
|
||||
currentEnvironment[k] = v;
|
||||
};
|
||||
};
|
||||
};
|
||||
// Reload des Pdef du moteur si dispo
|
||||
~reload !? { ~reload.value };
|
||||
("[loop] restore " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// Save / Load disque (en .scd : on serialise via Object.asCompileString)
|
||||
~loopSavePath = { |name|
|
||||
(~base ? "") ++ ".loops_" ++ name.asString ++ ".scd"
|
||||
};
|
||||
|
||||
~loopSave = { |name|
|
||||
var snap = ~loopsSnap[name] ?? { ~loopSnapshot.(name) };
|
||||
var path = ~loopSavePath.(name);
|
||||
var f = File.open(path, "w");
|
||||
if (f.isNil) {
|
||||
("[loop] save : impossible d'ouvrir " ++ path).postln;
|
||||
} {
|
||||
f.write(snap.asCompileString);
|
||||
f.close;
|
||||
("[loop] save " ++ name ++ " -> " ++ path).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~loopLoad = { |name|
|
||||
var path = ~loopSavePath.(name);
|
||||
if (File.exists(path).not) {
|
||||
("[loop] load : fichier absent " ++ path).postln;
|
||||
} {
|
||||
var snap = path.load;
|
||||
if (snap.notNil) {
|
||||
~loopsSnap[name] = snap;
|
||||
("[loop] load " ++ name ++ " <- " ++ path).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 6. COMPOSITIONS
|
||||
// =====================================================================
|
||||
|
||||
// Chaine sequentielle : [[name, source, beats], ...]
|
||||
// Chaque entree joue `beats` battements, puis on passe au suivant.
|
||||
~loopChain = { |entries|
|
||||
var t = TempoClock.default;
|
||||
~loopChainR !? { |r| r.stop };
|
||||
~loopChainR = Routine({
|
||||
entries.do { |e|
|
||||
var name = e[0];
|
||||
var source = e[1];
|
||||
var beats = e[2] ? 16;
|
||||
~loopOn.(name, source);
|
||||
beats.wait;
|
||||
~loopOff.(name);
|
||||
};
|
||||
"[loop] chain done".postln;
|
||||
}).play(t);
|
||||
("[loop] chain " ++ entries.size ++ " entrees").postln;
|
||||
};
|
||||
|
||||
// Lance plusieurs boucles simultanement : [[name, source], ...]
|
||||
~loopParallel = { |entries|
|
||||
entries.do { |e|
|
||||
var name = e[0];
|
||||
var source = e[1];
|
||||
~loopOn.(name, source);
|
||||
};
|
||||
("[loop] parallel " ++ entries.size ++ " boucles").postln;
|
||||
};
|
||||
|
||||
// Fade-out d'une boucle (sur l'amp de la voie correspondante au
|
||||
// prefixe du nom : \kickXxx -> ~kickAmp). Stoppe a la fin.
|
||||
~loopFadeAmpKey = { |name|
|
||||
// \kickLoop -> \kickAmp ; \m1 -> nil (cas multi-pistes : on
|
||||
// fait un fade local en surtout via un Pdef)
|
||||
var s = name.asString;
|
||||
var prefixes = ["kick","hat","snare","clap","perc","acid",
|
||||
"melody","harmony"];
|
||||
var found = nil;
|
||||
prefixes.do { |p|
|
||||
if (found.isNil and: { s.beginsWith(p) }) {
|
||||
found = (p ++ "Amp").asSymbol;
|
||||
};
|
||||
};
|
||||
found
|
||||
};
|
||||
|
||||
~loopFade = { |name, fadeOutDur = 2|
|
||||
var t = TempoClock.default;
|
||||
var ampKey = ~loopFadeAmpKey.(name);
|
||||
var l = ~loops[name];
|
||||
if (l.isNil) {
|
||||
("[loop] fade : " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
if (ampKey.notNil) {
|
||||
var startAmp = currentEnvironment[ampKey] ? 0.3;
|
||||
var steps = (fadeOutDur * 20).asInteger.max(1);
|
||||
var step = 1.0 / steps;
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
steps.do { |i|
|
||||
currentEnvironment[ampKey] = startAmp * (1 - ((i + 1) * step));
|
||||
~reload !? { ~reload.value };
|
||||
(fadeOutDur / steps).wait;
|
||||
};
|
||||
~loopOff.(name);
|
||||
currentEnvironment[ampKey] = startAmp; // restore amp
|
||||
~reload !? { ~reload.value };
|
||||
}).play(t);
|
||||
("[loop] fade " ++ name ++ " (" ++ fadeOutDur ++ "s)").postln;
|
||||
} {
|
||||
// Pas d'ampKey : on attend simplement, puis stop
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
fadeOutDur.wait;
|
||||
~loopOff.(name);
|
||||
}).play(t);
|
||||
("[loop] fade " ++ name ++ " (timed, no amp key)").postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
~loopFadeIn = { |name, source, fadeInDur = 2, max = inf|
|
||||
var t = TempoClock.default;
|
||||
var ampKey = ~loopFadeAmpKey.(name);
|
||||
var targetAmp = if (ampKey.notNil) {
|
||||
currentEnvironment[ampKey] ? 0.3
|
||||
} { nil };
|
||||
if (ampKey.notNil) {
|
||||
currentEnvironment[ampKey] = 0.0001;
|
||||
~reload !? { ~reload.value };
|
||||
};
|
||||
~loopOn.(name, source, max);
|
||||
if (ampKey.notNil) {
|
||||
var steps = (fadeInDur * 20).asInteger.max(1);
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
steps.do { |i|
|
||||
currentEnvironment[ampKey] = targetAmp * ((i + 1) / steps);
|
||||
~reload !? { ~reload.value };
|
||||
(fadeInDur / steps).wait;
|
||||
};
|
||||
}).play(t);
|
||||
("[loop] fadeIn " ++ name ++ " -> " ++ targetAmp).postln;
|
||||
} {
|
||||
("[loop] fadeIn " ++ name ++ " (no amp key)").postln;
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 7. AFFICHAGE / DEBUG
|
||||
// =====================================================================
|
||||
|
||||
// Bargraph ASCII court pour count/max
|
||||
~loopBar = { |count, max, width = 20|
|
||||
var ratio, full, str;
|
||||
if (max == inf or: { max == 0 }) {
|
||||
// Pas de max : on affiche un placeholder
|
||||
"[--------------------]"
|
||||
} {
|
||||
ratio = (count / max).clip(0, 1);
|
||||
full = (ratio * width).asInteger;
|
||||
str = "[" ++ ("#" ! full).join ++ ("." ! (width - full)).join ++ "]";
|
||||
str
|
||||
}
|
||||
};
|
||||
|
||||
~loopProgress = {
|
||||
"=== loop progress ===".postln;
|
||||
if (~loops.isEmpty) {
|
||||
" (aucune boucle)".postln;
|
||||
} {
|
||||
~loops.keysValuesDo { |k, v|
|
||||
var st = if (v[\state] == \on) { "ON " } { "off" };
|
||||
var c = v[\count] ? 0;
|
||||
var m = v[\max] ? inf;
|
||||
var bar = ~loopBar.(c, m, 20);
|
||||
var maxStr = if (m == inf) { "inf" } { m.asString };
|
||||
(" [" ++ st ++ "] " ++ k ++ " " ++ bar
|
||||
++ " " ++ c ++ "/" ++ maxStr).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Alias visuel
|
||||
~loopShow = { ~loopProgress.value };
|
||||
|
||||
// Info compacte d'une seule boucle
|
||||
~loopInfo = { |name|
|
||||
var v = ~loops[name];
|
||||
if (v.isNil) {
|
||||
("[loop] " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
var st = if (v[\state] == \on) { "ON" } { "off" };
|
||||
var src = v[\source];
|
||||
var srcStr = if (src.isKindOf(Symbol)) { src.asString }
|
||||
{ if (src.isKindOf(Function)) { "<fn>" } { "?" } };
|
||||
var c = v[\count] ? 0;
|
||||
var m = v[\max] ? inf;
|
||||
var bar = ~loopBar.(c, m, 20);
|
||||
var maxStr = if (m == inf) { "inf" } { m.asString };
|
||||
var elapsed = (Main.elapsedTime - (v[\startedAt] ? Main.elapsedTime)).round(0.1);
|
||||
("[loop] " ++ name ++ " " ++ st
|
||||
++ " src=" ++ srcStr
|
||||
++ " " ++ bar ++ " " ++ c ++ "/" ++ maxStr
|
||||
++ " age=" ++ elapsed ++ "s").postln;
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 8. AUTO-STOP / AUTO-FADE PROGRAMMES
|
||||
// =====================================================================
|
||||
|
||||
~loopAutoStop = { |name, beats = 16|
|
||||
var t = TempoClock.default;
|
||||
if (~loops[name].isNil) {
|
||||
("[loop] autoStop : " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
beats.wait;
|
||||
~loopOff.(name);
|
||||
}).play(t);
|
||||
("[loop] autoStop " ++ name ++ " dans " ++ beats ++ "b").postln;
|
||||
};
|
||||
};
|
||||
|
||||
~loopAutoFade = { |name, beats = 16, fadeDur = 1|
|
||||
var t = TempoClock.default;
|
||||
if (~loops[name].isNil) {
|
||||
("[loop] autoFade : " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
~loopAutos[name] !? { |r| r.stop };
|
||||
~loopAutos[name] = Routine({
|
||||
beats.wait;
|
||||
~loopFade.(name, fadeDur);
|
||||
}).play(t);
|
||||
("[loop] autoFade " ++ name ++ " dans " ++ beats ++ "b ("
|
||||
++ fadeDur ++ "s)").postln;
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// 9. HELPERS POUR LES PDEF DU MOTEUR
|
||||
// =====================================================================
|
||||
// Chaque helper utilise un nom de boucle base sur la voie + source
|
||||
// Pdef correspondant. Si beats = inf -> simple ~loopOn ; sinon ~loopBeats.
|
||||
|
||||
~loopEngineHelper = { |voiceSym, beats|
|
||||
var seqSym = (voiceSym.asString ++ "Seq").asSymbol;
|
||||
var loopName = (voiceSym.asString ++ "Loop").asSymbol;
|
||||
if (beats == inf or: { beats.isNil }) {
|
||||
~loopOn.(loopName, seqSym);
|
||||
} {
|
||||
~loopBeats.(loopName, seqSym, beats);
|
||||
};
|
||||
loopName
|
||||
};
|
||||
|
||||
~kickLoop = { |beats = inf| ~loopEngineHelper.(\kick, beats) };
|
||||
~hatLoop = { |beats = inf| ~loopEngineHelper.(\hat, beats) };
|
||||
~snareLoop = { |beats = inf| ~loopEngineHelper.(\snare, beats) };
|
||||
~clapLoop = { |beats = inf| ~loopEngineHelper.(\clap, beats) };
|
||||
~percLoop = { |beats = inf| ~loopEngineHelper.(\perc, beats) };
|
||||
~acidLoop = { |beats = inf| ~loopEngineHelper.(\acid, beats) };
|
||||
~melodyLoop = { |beats = inf| ~loopEngineHelper.(\melody, beats) };
|
||||
~harmonyLoop = { |beats = inf| ~loopEngineHelper.(\harmony, beats) };
|
||||
|
||||
// Lance / stoppe les 8 Pdef du moteur d'un coup
|
||||
~allOn = {
|
||||
~loopEngineSyms.do { |sym|
|
||||
var voice = sym.asString.replace("Seq", "").asSymbol;
|
||||
var loopName = (voice.asString ++ "Loop").asSymbol;
|
||||
~loopOn.(loopName, sym);
|
||||
};
|
||||
"[loop] allOn (8 voies moteur)".postln;
|
||||
};
|
||||
|
||||
~allOff = {
|
||||
~loopEngineSyms.do { |sym|
|
||||
var voice = sym.asString.replace("Seq", "").asSymbol;
|
||||
var loopName = (voice.asString ++ "Loop").asSymbol;
|
||||
if (~loops[loopName].notNil and: { ~loops[loopName][\state] == \on }) {
|
||||
~loopOff.(loopName);
|
||||
};
|
||||
};
|
||||
// Coupe aussi les Pdef directement, au cas ou on n'est pas passe
|
||||
// par ~loopOn (compatibilite avec l'ancien workflow PLAY)
|
||||
~loopEngineSyms.do { |sym| Pdef(sym).stop };
|
||||
"[loop] allOff (8 voies moteur)".postln;
|
||||
};
|
||||
|
||||
"[loops] gestionnaire pret -- ~loopList ~loopProgress ~allOn ~allOff".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES (Cmd+Entree sur une parenthese)
|
||||
// =====================================================================
|
||||
//
|
||||
// // --- Boucles simples sur les Pdef du moteur -----------------------
|
||||
// ( ~kickLoop.(); ) // kick infini
|
||||
// ( ~hatLoop.(16); ) // hat sur 16 beats
|
||||
// ( ~loopOff.(\kickLoop); )
|
||||
// ( ~allOn.(); ) // les 8 voies du moteur
|
||||
// ( ~allOff.(); )
|
||||
//
|
||||
// // --- Boucles sur fonctions custom ---------------------------------
|
||||
// ( ~loopOn.(\blip, { 8.do { |i| (instrument: \pluck, midinote: 60+i).play; 0.25.wait } }); )
|
||||
// ( ~loopOff.(\blip); )
|
||||
//
|
||||
// // --- Repeat / countdown -------------------------------------------
|
||||
// ( ~loopRepeat.(\drop, \kickSeq, 4, 4); ) // 4 fois 4 beats
|
||||
// ( ~loopWithCountdown.(\intro, \melodySeq, 4, inf); )
|
||||
// ( ~loopCountdown.(4, { "drop !".postln }); )
|
||||
//
|
||||
// // --- Tempo-sync ---------------------------------------------------
|
||||
// ( ~loopBeats.(\stab, \snareSeq, 8); )
|
||||
// ( ~loopBars.(\verse, \melodySeq, 4); ) // 4 mesures
|
||||
// ( ~loopSync.(); ) // resync au temps fort
|
||||
//
|
||||
// // --- Compositions -------------------------------------------------
|
||||
// ( ~loopChain.([
|
||||
// [\a, \kickSeq, 8],
|
||||
// [\b, \snareSeq, 8],
|
||||
// [\c, \melodySeq, 16]
|
||||
// ]); )
|
||||
// ( ~loopParallel.([[\k, \kickSeq], [\h, \hatSeq], [\m, \melodySeq]]); )
|
||||
// ( ~loopFade.(\kickLoop, 2); )
|
||||
// ( ~loopFadeIn.(\melodyLoop, \melodySeq, 4); )
|
||||
//
|
||||
// // --- Compteurs ----------------------------------------------------
|
||||
// ( ~loopCount.(\drop).postln; )
|
||||
// ( ~loopReset.(\drop); )
|
||||
// ( ~loopMax.(\drop, 8); )
|
||||
//
|
||||
// // --- Auto-stop / auto-fade ----------------------------------------
|
||||
// ( ~loopAutoStop.(\kickLoop, 32); )
|
||||
// ( ~loopAutoFade.(\acidLoop, 16, 2); )
|
||||
//
|
||||
// // --- Snapshot / restore -------------------------------------------
|
||||
// ( ~loopSnapshot.(\acidLoop); )
|
||||
// ( ~loopRestore.(\acidLoop); )
|
||||
// ( ~loopSave.(\acidLoop); )
|
||||
// ( ~loopLoad.(\acidLoop); )
|
||||
//
|
||||
// // --- Affichage ----------------------------------------------------
|
||||
// ( ~loopList.(); )
|
||||
// ( ~loopProgress.(); )
|
||||
// ( ~loopShow.(); )
|
||||
// ( ~loopInfo.(\kickLoop); )
|
||||
// ( ~loopIsOn.(\kickLoop).postln; )
|
||||
//
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,222 @@
|
||||
// =====================================================================
|
||||
// live/melodies.scd -- MELODIES LIVE (API ultra-courte)
|
||||
//
|
||||
// ATTENTION SC -- noter la notation des appels :
|
||||
//
|
||||
// NE MARCHE PAS : ~m.short.(50)
|
||||
// -> SC passe l'event ~m comme 1er arg, et les vrais args sont
|
||||
// PERDUS (test empirique sur SC 3.14.1).
|
||||
//
|
||||
// MARCHE BIEN : ~m[\short].(50) (notation indexee)
|
||||
// ~mShort.(50) (variable env directe)
|
||||
// ~mm.(50) (alias env direct)
|
||||
//
|
||||
// ~m // dict catalogue
|
||||
// ~m[\short].(N) // applique m{N} (32 pas, 1..78)
|
||||
// ~m[\long].(N) // applique ml{N} (64 pas, 1..30)
|
||||
// ~m[\xlong].(N) // applique mxl{N} (96 pas, 1..15)
|
||||
// ~m[\epic].(N) // applique mepic{N}(128 pas, 1..10)
|
||||
// ~m[\rnd][\short].() etc.
|
||||
// ~m[\gen].(\acid|\trance|...) // random par genre
|
||||
// ~m[\nx].() / ~m[\pv].() // next/prev
|
||||
// ~m[\inst].(\warmPad) // change ~melodyInst + reload
|
||||
// ~m[\harm][\go].(\third) // ~enableHarmony
|
||||
// ~m[\harm][\inst].(\warmPad) // change ~harmonyInst
|
||||
// ~m[\amp] / [\cut] / [\drive] / [\off]
|
||||
// ~m[\list].()
|
||||
//
|
||||
// RACCOURCIS env (API utilisateur primaire) :
|
||||
// ~mShort, ~mLong, ~mXlong, ~mEpic
|
||||
// ~mRnd, ~mRndLong, ~mRndXlong, ~mRndEpic
|
||||
// ~mGen, ~mNx, ~mPv
|
||||
// ~mInst, ~mHarm, ~mHarmInst
|
||||
// ~mAmp, ~mCut, ~mDrive, ~mOff
|
||||
// ~mList
|
||||
// ~mm (= ~mShort, alias court)
|
||||
//
|
||||
// EXEMPLES :
|
||||
// ~mm.(29) // melodie acid m29
|
||||
// ~mLong.(15) // melodie longue ml15
|
||||
// ~mGen.(\trance) // random dans le genre trance
|
||||
// ~mHarm.(\third) // ajoute la 2e voix en tierce
|
||||
// ~mNx.() // melodie suivante
|
||||
//
|
||||
// NOTE : noms reserves Object/Server (`s` = Server.default, `next`,
|
||||
// `prev`...) ne marcheraient pas comme cles d'Event SC pseudo-method.
|
||||
// Mais comme on N'UTILISE PAS la pseudo-method (~m.key.()), les noms
|
||||
// des cles dans ~m peuvent rester courts (\short, \long, \nx, \pv).
|
||||
// Les renommages c->cur etc. sont quand meme appliques pour clarte.
|
||||
//
|
||||
// PREREQUIS : engine + palette/melodies/* + palette/harmonics/* charges.
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
~m = ();
|
||||
|
||||
// --- etat courant : kind + numero (pour ~m[\nx] / ~m[\pv]) ----------
|
||||
~m[\cur] = ( kind: \short, n: 1 );
|
||||
|
||||
// --- helper interne ------------------------------------------------
|
||||
~m[\apply] = { |kind, n|
|
||||
var prefix, max, key, notes;
|
||||
prefix = switch (kind,
|
||||
\short, "m",
|
||||
\long, "ml",
|
||||
\xlong, "mxl",
|
||||
\epic, "mepic",
|
||||
"m"
|
||||
);
|
||||
max = switch (kind, \short, 78, \long, 30, \xlong, 15, \epic, 10, 78);
|
||||
n = ((n - 1).mod(max)) + 1;
|
||||
key = (prefix ++ n).asSymbol;
|
||||
notes = currentEnvironment[key];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
~melodyNotes = notes.copy;
|
||||
~reload !? { ~reload.value };
|
||||
~m[\cur] = ( kind: kind, n: n );
|
||||
("[m." ++ kind ++ "] " ++ key).postln;
|
||||
} {
|
||||
("[m] melodie " ++ key ++ " inconnue (charge palette/melodies ?)").postln;
|
||||
};
|
||||
};
|
||||
|
||||
~m[\short] = { |n = 1| ~m[\apply].(\short, n) };
|
||||
~m[\long] = { |n = 1| ~m[\apply].(\long, n) };
|
||||
~m[\xlong] = { |n = 1| ~m[\apply].(\xlong, n) };
|
||||
~m[\epic] = { |n = 1| ~m[\apply].(\epic, n) };
|
||||
|
||||
~m[\rnd] = ();
|
||||
~m[\rnd][\short] = { ~m[\apply].(\short, 78.rand + 1) };
|
||||
~m[\rnd][\long] = { ~randomLong !? { ~randomLong.() }; ~m[\cur] = ( kind: \long, n: 1 ) };
|
||||
~m[\rnd][\xlong] = { ~randomXLong !? { ~randomXLong.() }; ~m[\cur] = ( kind: \xlong, n: 1 ) };
|
||||
~m[\rnd][\epic] = { ~randomEpic !? { ~randomEpic.() }; ~m[\cur] = ( kind: \epic, n: 1 ) };
|
||||
~m[\rnd][\value] = { ~m[\apply].(\short, 78.rand + 1) };
|
||||
|
||||
~m[\gen] = { |genre = \acid|
|
||||
~melodyByGenre !? { ~melodyByGenre.(genre) };
|
||||
};
|
||||
|
||||
~m[\nx] = { ~m[\apply].(~m[\cur][\kind], ~m[\cur][\n] + 1) };
|
||||
~m[\pv] = { ~m[\apply].(~m[\cur][\kind], ~m[\cur][\n] - 1) };
|
||||
|
||||
~m[\inst] = { |inst = \lead|
|
||||
~melodyInst = inst;
|
||||
~reload !? { ~reload.value };
|
||||
("[m.inst] ~melodyInst = " ++ inst).postln;
|
||||
};
|
||||
|
||||
~m[\harm] = ();
|
||||
~m[\harm][\go] = { |preset = \off|
|
||||
~enableHarmony !? { ~enableHarmony.(preset) };
|
||||
("[m.harm] " ++ preset).postln;
|
||||
};
|
||||
~m[\harm][\inst] = { |inst = \pad|
|
||||
~harmonyInst = inst;
|
||||
~reload !? { ~reload.value };
|
||||
("[m.harm.inst] ~harmonyInst = " ++ inst).postln;
|
||||
};
|
||||
|
||||
~m[\amp] = { |val = 0.16|
|
||||
~melodyAmp = val.clip(0, 1);
|
||||
~reload !? { ~reload.value };
|
||||
("[m.amp] " ++ ~melodyAmp).postln;
|
||||
};
|
||||
~m[\cut] = { |hz = 2400|
|
||||
~melodyCutoff = hz.clip(20, 20000);
|
||||
~reload !? { ~reload.value };
|
||||
("[m.cut] " ++ ~melodyCutoff ++ "Hz").postln;
|
||||
};
|
||||
~m[\drive] = { |val = 1.2|
|
||||
~melodyDrive = val.max(0.1);
|
||||
~reload !? { ~reload.value };
|
||||
("[m.drive] " ++ ~melodyDrive).postln;
|
||||
};
|
||||
~m[\off] = {
|
||||
~melodyAmp = 0;
|
||||
~reload !? { ~reload.value };
|
||||
"[m.off] melody silencieuse".postln;
|
||||
};
|
||||
|
||||
~m[\list] = {
|
||||
"=== ~m -- MELODIES ===".postln;
|
||||
(" courant : " ++ ~m[\cur][\kind] ++ " #" ++ ~m[\cur][\n]).postln;
|
||||
" ranges : short 1..78 / long 1..30 / xlong 1..15 / epic 1..10".postln;
|
||||
if (~melodyBank.notNil) {
|
||||
" genres : ".post; ~melodyBank.keys.asArray.sort.postln;
|
||||
} { " genres : (~melodyBank non charge)".postln };
|
||||
" USAGE : ~mm.(29) | ~mLong.(15) | ~mGen.(\\trance) | ~mNx.()".postln;
|
||||
};
|
||||
|
||||
// --- API utilisateur : variables d'env top-level --------------------
|
||||
~mShort = { |n = 1| ~m[\apply].(\short, n) };
|
||||
~mLong = { |n = 1| ~m[\apply].(\long, n) };
|
||||
~mXlong = { |n = 1| ~m[\apply].(\xlong, n) };
|
||||
~mEpic = { |n = 1| ~m[\apply].(\epic, n) };
|
||||
~mRnd = { ~m[\apply].(\short, 78.rand + 1) };
|
||||
~mRndLong = { ~randomLong !? { ~randomLong.() }; ~m[\cur] = ( kind: \long, n: 1 ) };
|
||||
~mRndXlong = { ~randomXLong !? { ~randomXLong.() }; ~m[\cur] = ( kind: \xlong, n: 1 ) };
|
||||
~mRndEpic = { ~randomEpic !? { ~randomEpic.() }; ~m[\cur] = ( kind: \epic, n: 1 ) };
|
||||
~mGen = { |genre = \acid| ~melodyByGenre !? { ~melodyByGenre.(genre) } };
|
||||
~mNx = { ~m[\apply].(~m[\cur][\kind], ~m[\cur][\n] + 1) };
|
||||
~mPv = { ~m[\apply].(~m[\cur][\kind], ~m[\cur][\n] - 1) };
|
||||
~mInst = { |inst = \lead| ~m[\inst].(inst) };
|
||||
~mHarm = { |preset = \off| ~m[\harm][\go].(preset) };
|
||||
~mHarmInst = { |inst = \pad| ~m[\harm][\inst].(inst) };
|
||||
~mAmp = { |val = 0.16| ~m[\amp].(val) };
|
||||
~mCut = { |hz = 2400| ~m[\cut].(hz) };
|
||||
~mDrive = { |val = 1.2| ~m[\drive].(val) };
|
||||
~mOff = { ~m[\off].() };
|
||||
~mList = { ~m[\list].() };
|
||||
~mm = { |n = 1| ~m[\apply].(\short, n) }; // alias court
|
||||
|
||||
"=== ~m pret -- ~mm.(29) | ~mLong.(15) | ~mGen.(\\trance) | ~mList.() ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES (Cmd+Entree pour appliquer)
|
||||
// =====================================================================
|
||||
|
||||
// --- short / long / xlong / epic par numero ---
|
||||
// ( ~mm.(29); ) // m29 (acid classique)
|
||||
// ( ~mm.(50); ) // m50
|
||||
// ( ~mLong.(15); ) // ml15 (long 64 pas)
|
||||
// ( ~mXlong.(5); ) // mxl5 (xlong 96 pas)
|
||||
// ( ~mEpic.(1); ) // mepic1 (epic 128 pas)
|
||||
|
||||
// --- random ---
|
||||
// ( ~mRnd.(); ) // short random
|
||||
// ( ~mRndLong.(); ) // long random
|
||||
// ( ~mRndXlong.(); ) // xlong random
|
||||
// ( ~mRndEpic.(); ) // epic random
|
||||
|
||||
// --- random par genre ---
|
||||
// ( ~mGen.(\acid); )
|
||||
// ( ~mGen.(\trance); )
|
||||
// ( ~mGen.(\dub); )
|
||||
// ( ~mGen.(\detroit); )
|
||||
// ( ~mGen.(\oriental); )
|
||||
|
||||
// --- navigation ---
|
||||
// ( ~mNx.(); ) // suivante
|
||||
// ( ~mPv.(); ) // precedente
|
||||
|
||||
// --- timbre / harmonie ---
|
||||
( ~mInst.(\warmPad); )
|
||||
( ~mInst.(\pluck); )
|
||||
( ~mInst.(\stab); )
|
||||
// ( ~mHarm.(\third); ) // tierce
|
||||
( ~mHarm.(\fifth); ) // quinte
|
||||
// ( ~mHarm.(\counter); )
|
||||
// ( ~mHarm.(\off); )
|
||||
// ( ~mHarmInst.(\warmPad); )
|
||||
|
||||
// --- reglages live ---
|
||||
( ~mAmp.(0.2); )
|
||||
( ~mCut.(1200); )
|
||||
( ~mDrive.(2.0); )
|
||||
( ~mOff.(); ) // mute melodie
|
||||
|
||||
// --- liste ---
|
||||
// ( ~mList.(); )
|
||||
+693
@@ -0,0 +1,693 @@
|
||||
// =====================================================================
|
||||
// mixer.scd -- Mixer / faders par voie pour systeme live
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue (~kickAmp, ~hatAmp, ..., ~reload defini)
|
||||
//
|
||||
// PHILOSOPHIE
|
||||
// Les amps "de reference" (~mixRef) sont les valeurs courantes au
|
||||
// moment de l'init du mixer. Les coefficients ~mix sont des
|
||||
// multiplicateurs (0..1+) appliques sur ~mixRef avant chaque reload.
|
||||
// -> ~setVol.(\kick, 0.5) baisse le kick a 50% de sa valeur de base
|
||||
// -> ~mixReset remet tous les coefs a 1 (= valeurs de reference)
|
||||
// -> changer ~mixRef.kick rebase la reference (ex: changement de kit)
|
||||
//
|
||||
// USAGE RAPIDE
|
||||
// ( ~setVol.(\kick, 0.7); )
|
||||
// ( ~mute.(\hat); ) ( ~unmute.(\hat); )
|
||||
// ( ~solo.(\acid); ) ( ~unsolo.(); )
|
||||
// ( ~xfade.(\acid, \melody, 4); )
|
||||
// ( ~mixPreset.(\drumsHeavy); )
|
||||
// ( ~mixShow.(); )
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
// --- 1. Init des structures ----------------------------------------
|
||||
~mixVoices = [\kick, \hat, \snare, \clap, \perc, \acid, \melody, \harmony];
|
||||
|
||||
// Coefficients courants (multiplicateurs 0..1+ par voie)
|
||||
~mix = ~mix ?? {
|
||||
(kick: 1, hat: 1, snare: 1, clap: 1, perc: 1, acid: 1, melody: 1, harmony: 1)
|
||||
};
|
||||
|
||||
// Etats internes
|
||||
~mixMuted = ~mixMuted ?? { Dictionary.new }; // voies mutees -> ancien coef
|
||||
~mixSoloed = ~mixSoloed ?? { Dictionary.new }; // snapshot avant solo
|
||||
~mixesSaved = ~mixesSaved ?? { Dictionary.new }; // mixes nommes
|
||||
~mixFocusBak = ~mixFocusBak ?? { nil }; // snapshot avant focus
|
||||
~mixDuckRout = ~mixDuckRout ?? { nil }; // routine duck en cours
|
||||
~mixFadeRout = ~mixFadeRout ?? { Dictionary.new }; // routines de fade par voie
|
||||
~mixMasterRt = ~mixMasterRt ?? { nil }; // routine master fade
|
||||
|
||||
|
||||
// ~mixRef : valeurs "de reference" des amps moteur (capturees a l'init)
|
||||
// Si une voie est consideree mutee (amp = 0), on garde une reference par
|
||||
// defaut pour pouvoir restaurer.
|
||||
~mixRefDefaults = (
|
||||
kick: 0.5, hat: 0.18, snare: 0.45, clap: 0.35,
|
||||
perc: 0.25, acid: 0.32, melody: 0.16, harmony: 0.14
|
||||
);
|
||||
|
||||
// Capture les amps moteur courants comme reference (1ere fois seulement)
|
||||
~mixCaptureRef = {
|
||||
~mixRef = ();
|
||||
~mixVoices.do { |v|
|
||||
var key = (v.asString ++ "Amp").asSymbol;
|
||||
var cur = currentEnvironment[key];
|
||||
// si amp courant est nil ou 0 -> prend la valeur par defaut
|
||||
if (cur.isNil or: { cur == 0 }) {
|
||||
~mixRef[v] = ~mixRefDefaults[v];
|
||||
} {
|
||||
~mixRef[v] = cur;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Capture seulement si pas deja fait (preserve la reference entre reloads)
|
||||
~mixRef ?? { ~mixCaptureRef.value };
|
||||
|
||||
// Re-capture force (utile apres changement de kit / preset moteur)
|
||||
~mixRebase = {
|
||||
~mixCaptureRef.value;
|
||||
"[mixer] reference rebase".postln;
|
||||
};
|
||||
|
||||
|
||||
// --- 2. Application des coefficients --------------------------------
|
||||
// amp = ref * coef_voie * master (puis reload des Pdef)
|
||||
~mixMaster = ~mixMaster ?? 1.0; // multiplicateur global non-destructif
|
||||
~mixApply = {
|
||||
~mixVoices.do { |v|
|
||||
var key = (v.asString ++ "Amp").asSymbol;
|
||||
var refV = ~mixRef[v] ? 0;
|
||||
var coef = ~mix[v] ? 1;
|
||||
currentEnvironment.put(key, refV * coef * ~mixMaster);
|
||||
};
|
||||
~reload.value;
|
||||
};
|
||||
|
||||
|
||||
// --- 3. Set / get / reset volume par voie ---------------------------
|
||||
~setVol = { |voie, val|
|
||||
if (~mixVoices.includes(voie).not) {
|
||||
("!! voie inconnue : " ++ voie ++ " -- voies : " ++ ~mixVoices).postln;
|
||||
} {
|
||||
~mix[voie] = val.max(0);
|
||||
~mixApply.value;
|
||||
("[mix] " ++ voie ++ " = " ++ val.round(0.01)).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~getVol = { |voie| ~mix[voie] ? 1 };
|
||||
|
||||
~mixReset = {
|
||||
~mixVoices.do { |v| ~mix[v] = 1 };
|
||||
~mixMuted.clear;
|
||||
~mixSoloed.clear;
|
||||
~mixApply.value;
|
||||
"[mix] reset (tous coefs = 1)".postln;
|
||||
};
|
||||
|
||||
|
||||
// --- 4. Mute / Unmute / Solo ----------------------------------------
|
||||
~mute = { |voie|
|
||||
if (~mixVoices.includes(voie).not) {
|
||||
("!! voie inconnue : " ++ voie).postln;
|
||||
} {
|
||||
if (~mixMuted.includesKey(voie).not) {
|
||||
~mixMuted[voie] = ~mix[voie] ? 1;
|
||||
~mix[voie] = 0;
|
||||
~mixApply.value;
|
||||
("[mute] " ++ voie).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
~unmute = { |voie|
|
||||
if (~mixMuted.includesKey(voie)) {
|
||||
~mix[voie] = ~mixMuted[voie];
|
||||
~mixMuted.removeAt(voie);
|
||||
~mixApply.value;
|
||||
("[unmute] " ++ voie).postln;
|
||||
} {
|
||||
("[unmute] " ++ voie ++ " n'etait pas mute").postln;
|
||||
};
|
||||
};
|
||||
|
||||
~muteToggle = { |voie|
|
||||
if (~mixMuted.includesKey(voie)) { ~unmute.(voie) } { ~mute.(voie) };
|
||||
};
|
||||
|
||||
~muteAll = {
|
||||
~mixVoices.do { |v|
|
||||
if (~mixMuted.includesKey(v).not) {
|
||||
~mixMuted[v] = ~mix[v] ? 1;
|
||||
~mix[v] = 0;
|
||||
};
|
||||
};
|
||||
~mixApply.value;
|
||||
"[mute all]".postln;
|
||||
};
|
||||
|
||||
~unmuteAll = {
|
||||
~mixMuted.keysValuesDo { |v, prev| ~mix[v] = prev };
|
||||
~mixMuted.clear;
|
||||
~mixApply.value;
|
||||
"[unmute all]".postln;
|
||||
};
|
||||
|
||||
~mutedList = {
|
||||
var l = ~mixMuted.keys.asArray;
|
||||
("[muted] " ++ l).postln;
|
||||
l;
|
||||
};
|
||||
|
||||
// Solo : mute toutes les autres voies (snapshot dans ~mixSoloed)
|
||||
~solo = { |voie|
|
||||
if (~mixVoices.includes(voie).not) {
|
||||
("!! voie inconnue : " ++ voie).postln;
|
||||
} {
|
||||
// Si pas deja en solo, snapshot l'etat courant
|
||||
if (~mixSoloed.size == 0) {
|
||||
~mixVoices.do { |v| ~mixSoloed[v] = ~mix[v] ? 1 };
|
||||
};
|
||||
~mixVoices.do { |v|
|
||||
~mix[v] = if (v == voie) { ~mixSoloed[v] } { 0 };
|
||||
};
|
||||
~mixApply.value;
|
||||
("[solo] " ++ voie).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~unsolo = {
|
||||
if (~mixSoloed.size == 0) {
|
||||
"[unsolo] aucun solo actif".postln;
|
||||
} {
|
||||
~mixSoloed.keysValuesDo { |v, val| ~mix[v] = val };
|
||||
~mixSoloed.clear;
|
||||
~mixApply.value;
|
||||
"[unsolo]".postln;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- 5. Master volume / fades ---------------------------------------
|
||||
// Set le multiplicateur master ABSOLU (non destructif sur les coefs voies)
|
||||
// ~masterVol.(0.5) -> moitie ; ~masterVol.(1) -> retour normal
|
||||
~masterVol = { |val|
|
||||
~mixMaster = val.max(0);
|
||||
~mixApply.value;
|
||||
("[master] = " ++ ~mixMaster.round(0.01)).postln;
|
||||
};
|
||||
|
||||
// Fade le multiplicateur master vers une valeur cible (preserve les coefs voies)
|
||||
~masterFade = { |target = 0, dur = 4|
|
||||
~mixMasterRt !? { ~mixMasterRt.stop };
|
||||
~mixMasterRt = Routine({
|
||||
var steps = (dur * 30).max(2).asInteger;
|
||||
var startMaster = ~mixMaster ? 1;
|
||||
steps.do { |i|
|
||||
var t = (i + 1) / steps;
|
||||
~mixMaster = startMaster.blend(target, t);
|
||||
~mixApply.value;
|
||||
(dur / steps).wait;
|
||||
};
|
||||
("[master fade] -> " ++ target.round(0.01)).postln;
|
||||
}).play;
|
||||
};
|
||||
|
||||
// Fade-in depuis 0 vers le master courant (1.0 par defaut)
|
||||
~masterFadeIn = { |dur = 4, target = 1|
|
||||
~mixMaster = 0;
|
||||
~mixApply.value;
|
||||
~masterFade.(target, dur);
|
||||
};
|
||||
|
||||
// Fade-out vers 0 puis stop des Pdef sequencer (preserve les coefs voies)
|
||||
~masterFadeOut = { |dur = 4|
|
||||
~mixMasterRt !? { ~mixMasterRt.stop };
|
||||
~mixMasterRt = Routine({
|
||||
var steps = (dur * 30).max(2).asInteger;
|
||||
var startMaster = ~mixMaster ? 1;
|
||||
steps.do { |i|
|
||||
var t = (i + 1) / steps;
|
||||
~mixMaster = startMaster.blend(0, t);
|
||||
~mixApply.value;
|
||||
(dur / steps).wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[master fade-out] STOP".postln;
|
||||
}).play;
|
||||
};
|
||||
|
||||
// Duck momentane : baisse a depth*current pendant attack, restaure en release
|
||||
~masterDuck = { |depth = 0.3, attack = 0.05, release = 0.4|
|
||||
~mixDuckRout !? { ~mixDuckRout.stop };
|
||||
~mixDuckRout = Routine({
|
||||
var snapshot = ();
|
||||
var stepsA = (attack * 30).max(2).asInteger;
|
||||
var stepsR = (release * 30).max(2).asInteger;
|
||||
~mixVoices.do { |v| snapshot[v] = ~mix[v] ? 1 };
|
||||
// attack : descente vers depth*current
|
||||
stepsA.do { |i|
|
||||
var t = (i + 1) / stepsA;
|
||||
~mixVoices.do { |v|
|
||||
~mix[v] = snapshot[v].blend(snapshot[v] * depth, t);
|
||||
};
|
||||
~mixApply.value;
|
||||
(attack / stepsA).wait;
|
||||
};
|
||||
// release : remontee
|
||||
stepsR.do { |i|
|
||||
var t = (i + 1) / stepsR;
|
||||
~mixVoices.do { |v|
|
||||
~mix[v] = (snapshot[v] * depth).blend(snapshot[v], t);
|
||||
};
|
||||
~mixApply.value;
|
||||
(release / stepsR).wait;
|
||||
};
|
||||
"[duck] OK".postln;
|
||||
}).play;
|
||||
};
|
||||
|
||||
|
||||
// --- 6. Presets de balance ------------------------------------------
|
||||
~mixPresets = (
|
||||
flat: (kick: 1.0, hat: 1.0, snare: 1.0, clap: 1.0,
|
||||
perc: 1.0, acid: 1.0, melody: 1.0, harmony: 1.0),
|
||||
drumsHeavy: (kick: 1.3, hat: 1.2, snare: 1.2, clap: 1.1,
|
||||
perc: 1.1, acid: 0.7, melody: 0.5, harmony: 0.4),
|
||||
melodicLead: (kick: 0.7, hat: 0.6, snare: 0.6, clap: 0.5,
|
||||
perc: 0.5, acid: 0.6, melody: 1.5, harmony: 1.1),
|
||||
acidFocus: (kick: 0.8, hat: 0.6, snare: 0.5, clap: 0.4,
|
||||
perc: 0.4, acid: 1.5, melody: 0.5, harmony: 0.3),
|
||||
bassFocus: (kick: 1.3, hat: 0.5, snare: 0.6, clap: 0.4,
|
||||
perc: 0.4, acid: 1.3, melody: 1.1, harmony: 0.5),
|
||||
breakdown: (kick: 0.0, hat: 0.0, snare: 0.0, clap: 0.0,
|
||||
perc: 0.3, acid: 0.6, melody: 1.1, harmony: 1.0),
|
||||
buildup: (kick: 0.4, hat: 0.7, snare: 0.5, clap: 0.5,
|
||||
perc: 0.6, acid: 0.9, melody: 1.0, harmony: 0.8),
|
||||
drop: (kick: 1.2, hat: 1.1, snare: 1.1, clap: 1.1,
|
||||
perc: 1.0, acid: 1.0, melody: 1.0, harmony: 0.9),
|
||||
dub: (kick: 1.3, hat: 1.0, snare: 0.5, clap: 0.6,
|
||||
perc: 1.2, acid: 0.7, melody: 1.4, harmony: 0.6),
|
||||
trance: (kick: 1.2, hat: 1.2, snare: 0.8, clap: 1.2,
|
||||
perc: 0.7, acid: 0.6, melody: 1.4, harmony: 1.0),
|
||||
detroit: (kick: 1.0, hat: 0.9, snare: 0.9, clap: 0.8,
|
||||
perc: 0.8, acid: 1.0, melody: 1.0, harmony: 0.9),
|
||||
hardcore: (kick: 1.5, hat: 1.0, snare: 1.4, clap: 1.0,
|
||||
perc: 0.9, acid: 1.1, melody: 0.5, harmony: 0.3),
|
||||
);
|
||||
|
||||
~mixPreset = { |name|
|
||||
var p = ~mixPresets[name];
|
||||
if (p.isNil) {
|
||||
("!! preset inconnu : " ++ name ++
|
||||
" -- dispos : " ++ ~mixPresets.keys.asArray).postln;
|
||||
} {
|
||||
~mixVoices.do { |v| ~mix[v] = p[v] ? 1 };
|
||||
~mixMuted.clear;
|
||||
~mixSoloed.clear;
|
||||
~mixApply.value;
|
||||
("[preset] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- 7. Save / recall des balances ----------------------------------
|
||||
~saveMix = { |name|
|
||||
var snap = ();
|
||||
~mixVoices.do { |v| snap[v] = ~mix[v] ? 1 };
|
||||
~mixesSaved[name] = snap;
|
||||
("[mix saved] " ++ name).postln;
|
||||
};
|
||||
|
||||
~loadMix = { |name|
|
||||
var snap = ~mixesSaved[name];
|
||||
if (snap.isNil) {
|
||||
("!! mix '" ++ name ++ "' inexistant. Dispos : " ++
|
||||
~mixesSaved.keys.asArray).postln;
|
||||
} {
|
||||
~mixVoices.do { |v| ~mix[v] = snap[v] ? 1 };
|
||||
~mixMuted.clear;
|
||||
~mixSoloed.clear;
|
||||
~mixApply.value;
|
||||
("[mix loaded] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~listMixes = {
|
||||
"=== MIXES sauvegardes ===".postln;
|
||||
if (~mixesSaved.size == 0) {
|
||||
" (aucun)".postln;
|
||||
} {
|
||||
~mixesSaved.keysValuesDo { |k, v|
|
||||
(" " ++ k).postln;
|
||||
};
|
||||
};
|
||||
~mixesSaved.keys.asArray;
|
||||
};
|
||||
|
||||
~deleteMix = { |name|
|
||||
if (~mixesSaved.includesKey(name)) {
|
||||
~mixesSaved.removeAt(name);
|
||||
("[mix deleted] " ++ name).postln;
|
||||
} { ("mix '" ++ name ++ "' inexistant").postln };
|
||||
};
|
||||
|
||||
|
||||
// --- 8. Helpers de balance live -------------------------------------
|
||||
// Crossfade entre 2 voies sur dur secondes
|
||||
~xfade = { |voieA, voieB, dur = 4|
|
||||
var key = (voieA.asString ++ "_" ++ voieB.asString).asSymbol;
|
||||
~mixFadeRout[key] !? { ~mixFadeRout[key].stop };
|
||||
~mixFadeRout[key] = Routine({
|
||||
var steps = (dur * 30).max(2).asInteger;
|
||||
var startA = ~mix[voieA] ? 1;
|
||||
var startB = ~mix[voieB] ? 1;
|
||||
var targetA = 0;
|
||||
var targetB = if (startB > 0) { startB } { 1 };
|
||||
steps.do { |i|
|
||||
var t = (i + 1) / steps;
|
||||
~mix[voieA] = startA.blend(targetA, t);
|
||||
~mix[voieB] = startB.blend(targetB, t);
|
||||
~mixApply.value;
|
||||
(dur / steps).wait;
|
||||
};
|
||||
("[xfade] " ++ voieA ++ " -> " ++ voieB).postln;
|
||||
}).play;
|
||||
};
|
||||
|
||||
// Fade smooth d'une voie vers une cible
|
||||
~fadeVol = { |voie, target = 1, dur = 2|
|
||||
if (~mixVoices.includes(voie).not) {
|
||||
("!! voie inconnue : " ++ voie).postln;
|
||||
} {
|
||||
~mixFadeRout[voie] !? { ~mixFadeRout[voie].stop };
|
||||
~mixFadeRout[voie] = Routine({
|
||||
var steps = (dur * 30).max(2).asInteger;
|
||||
var start = ~mix[voie] ? 1;
|
||||
steps.do { |i|
|
||||
var t = (i + 1) / steps;
|
||||
~mix[voie] = start.blend(target, t);
|
||||
~mixApply.value;
|
||||
(dur / steps).wait;
|
||||
};
|
||||
("[fade] " ++ voie ++ " -> " ++ target.round(0.01)).postln;
|
||||
}).play;
|
||||
};
|
||||
};
|
||||
|
||||
// Echange instantane de 2 voies
|
||||
~swapVol = { |voieA, voieB|
|
||||
var tmp = ~mix[voieA] ? 1;
|
||||
~mix[voieA] = ~mix[voieB] ? 1;
|
||||
~mix[voieB] = tmp;
|
||||
~mixApply.value;
|
||||
("[swap] " ++ voieA ++ " <-> " ++ voieB).postln;
|
||||
};
|
||||
|
||||
// Focus : boost une voie, baisse les autres a "others"
|
||||
~focus = { |voie, others = 0.3|
|
||||
if (~mixVoices.includes(voie).not) {
|
||||
("!! voie inconnue : " ++ voie).postln;
|
||||
} {
|
||||
// snapshot avant focus
|
||||
~mixFocusBak = ();
|
||||
~mixVoices.do { |v| ~mixFocusBak[v] = ~mix[v] ? 1 };
|
||||
~mixVoices.do { |v|
|
||||
~mix[v] = if (v == voie) { 1.0 } { others };
|
||||
};
|
||||
~mixApply.value;
|
||||
("[focus] " ++ voie ++ " (others=" ++ others ++ ")").postln;
|
||||
};
|
||||
};
|
||||
|
||||
~unfocus = {
|
||||
if (~mixFocusBak.isNil) {
|
||||
"[unfocus] aucun focus actif".postln;
|
||||
} {
|
||||
~mixFocusBak.keysValuesDo { |v, val| ~mix[v] = val };
|
||||
~mixFocusBak = nil;
|
||||
~mixApply.value;
|
||||
"[unfocus]".postln;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- 9. Affichage / debug -------------------------------------------
|
||||
// Bargraph ASCII (12 cells, max coef = 1.5 pour la visu)
|
||||
~mixShow = {
|
||||
var max = 1.5;
|
||||
var cells = 12;
|
||||
"=== MIXER ===".postln;
|
||||
~mixVoices.do { |v|
|
||||
var coef = ~mix[v] ? 1;
|
||||
var filled = ((coef / max) * cells).round.asInteger.clip(0, cells);
|
||||
var empty = cells - filled;
|
||||
var bar = String.fill(filled, $|) ++ String.fill(empty, $.);
|
||||
var lbl = (v.asString ++ " ").copyRange(0, 7);
|
||||
var muted = if (~mixMuted.includesKey(v)) { " [MUTED]" } { "" };
|
||||
var soloed = if (~mixSoloed.size > 0 and: { coef > 0 }) {
|
||||
" [SOLO]"
|
||||
} { "" };
|
||||
// remplace les pipes pour rendre visuel : utilise des chars block
|
||||
bar = bar.replace("|", "#");
|
||||
(" " ++ lbl ++ "|" ++ bar ++ " " ++
|
||||
coef.round(0.01).asString ++ muted ++ soloed).postln;
|
||||
};
|
||||
"=============".postln;
|
||||
};
|
||||
|
||||
// Info compacte une ligne
|
||||
~mixInfo = {
|
||||
var s = "[mix] ";
|
||||
~mixVoices.do { |v|
|
||||
s = s ++ v.asString ++ ":" ++ (~mix[v] ? 1).round(0.01).asString ++ " ";
|
||||
};
|
||||
s.postln;
|
||||
};
|
||||
|
||||
|
||||
// --- 10. Limiter / clip warning -------------------------------------
|
||||
// Calcul approximatif : somme des coef * amp_ref par voie
|
||||
// Si > seuil -> warn (le master limiter sauvera, mais le mix est sale)
|
||||
~mixClipWarn = { |seuil = 1.2|
|
||||
var sum = 0;
|
||||
~mixVoices.do { |v|
|
||||
var refV = ~mixRef[v] ? 0;
|
||||
var coef = ~mix[v] ? 1;
|
||||
sum = sum + (refV * coef);
|
||||
};
|
||||
if (sum > seuil) {
|
||||
("!! [clip warn] somme amps = " ++ sum.round(0.01) ++
|
||||
" > seuil " ++ seuil ++ " -- risque de pompage limiter").postln;
|
||||
} {
|
||||
("[ok] somme amps = " ++ sum.round(0.01) ++
|
||||
" (seuil " ++ seuil ++ ")").postln;
|
||||
};
|
||||
sum;
|
||||
};
|
||||
|
||||
|
||||
"=== mixer pret -- ~setVol ~mute ~solo ~mixPreset ~mixShow ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES D'USAGE -- Cmd+Entree sur un bloc pour l'executer
|
||||
// PREREQUIS : avoir evalue le bloc SETUP en tete de fichier d'abord
|
||||
// =====================================================================
|
||||
|
||||
// --- Faders simples --------------------------------------------------
|
||||
|
||||
// Baisse kick a 70%
|
||||
( ~setVol.(\kick, 0.7); )
|
||||
|
||||
// Boost acid a 130%
|
||||
( ~setVol.(\acid, 1.3); )
|
||||
|
||||
// Baisse melody a 40%
|
||||
( ~setVol.(\melody, 0.4); )
|
||||
|
||||
// Lit le coef courant d'une voie
|
||||
( ~getVol.(\kick); )
|
||||
|
||||
// Reset tous les coefs a 1
|
||||
( ~mixReset.(); )
|
||||
|
||||
|
||||
// --- Mute / unmute ---------------------------------------------------
|
||||
|
||||
// Mute hat
|
||||
( ~mute.(\hat); )
|
||||
|
||||
// Unmute hat
|
||||
( ~unmute.(\hat); )
|
||||
|
||||
// Toggle mute acid
|
||||
( ~muteToggle.(\acid); )
|
||||
|
||||
// Mute toutes les voies
|
||||
( ~muteAll.(); )
|
||||
|
||||
// Unmute toutes les voies
|
||||
( ~unmuteAll.(); )
|
||||
|
||||
// Liste les voies mutees
|
||||
( ~mutedList.(); )
|
||||
|
||||
|
||||
// --- Solo ------------------------------------------------------------
|
||||
|
||||
// Solo acid (tout sauf acid -> mute)
|
||||
( ~solo.(\acid); )
|
||||
|
||||
// Restore l'etat avant solo
|
||||
( ~unsolo.(); )
|
||||
|
||||
|
||||
// --- Master volume / fades -------------------------------------------
|
||||
|
||||
// Baisse global x0.5
|
||||
( ~masterVol.(0.5); )
|
||||
|
||||
// Fade tous les coefs vers 0 en 8s
|
||||
( ~masterFade.(0, 8); )
|
||||
|
||||
// Fade-in 4s depuis silence
|
||||
( ~masterFadeIn.(4); )
|
||||
|
||||
// Fade-out 6s puis stop des Pdef
|
||||
( ~masterFadeOut.(6); )
|
||||
|
||||
// Duck momentane (drop) : depth=0.3, attack=0.05s, release=0.5s
|
||||
( ~masterDuck.(0.3, 0.05, 0.5); )
|
||||
|
||||
|
||||
// --- Presets de balance ----------------------------------------------
|
||||
|
||||
// Tous coefs = 1
|
||||
( ~mixPreset.(\flat); )
|
||||
|
||||
// Drums devant
|
||||
( ~mixPreset.(\drumsHeavy); )
|
||||
|
||||
// Melody devant
|
||||
( ~mixPreset.(\melodicLead); )
|
||||
|
||||
// Acid devant
|
||||
( ~mixPreset.(\acidFocus); )
|
||||
|
||||
// Kick + acid devant
|
||||
( ~mixPreset.(\bassFocus); )
|
||||
|
||||
// Drums coupes (breakdown)
|
||||
( ~mixPreset.(\breakdown); )
|
||||
|
||||
// Buildup
|
||||
( ~mixPreset.(\buildup); )
|
||||
|
||||
// Drop
|
||||
( ~mixPreset.(\drop); )
|
||||
|
||||
// Dub
|
||||
( ~mixPreset.(\dub); )
|
||||
|
||||
// Trance
|
||||
( ~mixPreset.(\trance); )
|
||||
|
||||
// Detroit
|
||||
( ~mixPreset.(\detroit); )
|
||||
|
||||
// Hardcore
|
||||
( ~mixPreset.(\hardcore); )
|
||||
|
||||
|
||||
// --- Save / recall des balances --------------------------------------
|
||||
|
||||
// Sauvegarde la balance courante sous \verseA
|
||||
( ~saveMix.(\verseA); )
|
||||
|
||||
// Sauvegarde sous \drop1
|
||||
( ~saveMix.(\drop1); )
|
||||
|
||||
// Recharge \verseA
|
||||
( ~loadMix.(\verseA); )
|
||||
|
||||
// Liste les mixes sauvegardes
|
||||
( ~listMixes.(); )
|
||||
|
||||
// Supprime un mix sauvegarde
|
||||
( ~deleteMix.(\verseA); )
|
||||
|
||||
|
||||
// --- Helpers live ----------------------------------------------------
|
||||
|
||||
// Crossfade acid -> melody en 4s
|
||||
( ~xfade.(\acid, \melody, 4); )
|
||||
|
||||
// Fade kick vers 0.3 en 2s
|
||||
( ~fadeVol.(\kick, 0.3, 2); )
|
||||
|
||||
// Echange instantane des coefs acid <-> melody
|
||||
( ~swapVol.(\acid, \melody); )
|
||||
|
||||
// Focus acid (devant), autres voies a 0.2
|
||||
( ~focus.(\acid, 0.2); )
|
||||
|
||||
// Restore l'etat avant focus
|
||||
( ~unfocus.(); )
|
||||
|
||||
|
||||
// --- Affichage / debug -----------------------------------------------
|
||||
|
||||
// Bargraph ASCII de tous les coefs
|
||||
( ~mixShow.(); )
|
||||
|
||||
// Info compacte une ligne
|
||||
( ~mixInfo.(); )
|
||||
|
||||
// Alerte si la somme des amps depasse le seuil (1.2 par defaut)
|
||||
( ~mixClipWarn.(); )
|
||||
|
||||
|
||||
// --- Rebase reference (apres changement de kit moteur) ---------------
|
||||
|
||||
// Re-capture les ~xxxAmp courants comme nouvelle reference
|
||||
( ~mixRebase.(); )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// WORKFLOW LIVE PERFORMANCE COMPLET (sequence d'exemples chainables)
|
||||
// =====================================================================
|
||||
|
||||
// 1. Demarrage en silence puis montee
|
||||
( ~mixPreset.(\breakdown); ~masterFadeIn.(8); )
|
||||
|
||||
// 2. Verse calme (melody devant) + sauvegarde
|
||||
( ~mixPreset.(\melodicLead); ~saveMix.(\verseA); )
|
||||
|
||||
// 3. Buildup progressif
|
||||
( ~mixPreset.(\buildup); ~fadeVol.(\hat, 1.2, 4); )
|
||||
|
||||
// 4a. DROP : duck preparatoire
|
||||
( ~masterDuck.(0.3, 0.1, 0.5); )
|
||||
|
||||
// 4b. DROP : preset drop + sauvegarde
|
||||
( ~mixPreset.(\drop); ~saveMix.(\drop1); )
|
||||
|
||||
// 5a. Section acid solo : focus
|
||||
( ~focus.(\acid, 0.25); )
|
||||
|
||||
// 5b. ... 16 mesures plus tard : unfocus
|
||||
( ~unfocus.(); )
|
||||
|
||||
// 6. Breakdown ambient
|
||||
( ~mixPreset.(\breakdown); )
|
||||
|
||||
// 7. Retour drop final
|
||||
( ~loadMix.(\drop1); )
|
||||
|
||||
// 8. Fade-out final
|
||||
( ~masterFadeOut.(12); )
|
||||
@@ -0,0 +1,538 @@
|
||||
// =====================================================================
|
||||
// live/patterns.scd -- RHYTHM PRESETS LIVE (API ultra-courte)
|
||||
//
|
||||
// ATTENTION SC -- la notation `~p.kit.(\name)` NE marche PAS :
|
||||
// SC passe l'event ~p comme 1er arg et perd les vrais args.
|
||||
// Utiliser ~p[\kit].(\name) ou les variables ~pKit.(\name).
|
||||
//
|
||||
// ~p // dict catalogue
|
||||
// ~p[\kit].(\name) // applique un kit complet
|
||||
// ~p[\genre].(\name) // applique un preset rythmique
|
||||
// ~p[\kick].(N|\name) // raccourci -> ~k[\go]
|
||||
// ~p[\hat] / [\snare] / [\clap] / [\perc] / [\list]
|
||||
//
|
||||
// RACCOURCIS env (API utilisateur primaire) :
|
||||
// ~pKit, ~pGenre, ~pKick
|
||||
// ~pHat, ~pSnare, ~pClap, ~pPerc
|
||||
// ~pList
|
||||
//
|
||||
// KITS DISPO (extraits de drum_kits.scd) :
|
||||
// \techno \dubstep \dnb \trap \house \breakbeat \hardstyle \jungle
|
||||
// \garage \trap808 \phonk \footwork \liquidDnB \synthwave \industrial
|
||||
// \tribalWorld \hardcore \lofiHipHop \futureGarage \detroitDeep
|
||||
//
|
||||
// GENRES DISPO (extraits de patterns_genre.scd) :
|
||||
// \hardTechno \acidHouse \trance138 \psyTrance \hardstyle \handsUp
|
||||
// \liquidDnB \neurofunk \jungle165 \dnbJumpup \futureBass \deepHouse
|
||||
// \techHouse \progHouse \tribalTechno \industrialV2 \breakcore
|
||||
// \footwork \idm \glitchHop
|
||||
//
|
||||
// HAT/SNARE/CLAP/PERC presets : voir blocs ci-dessous.
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Les valeurs sont dupliquees ici donc
|
||||
// ~p est utilisable independamment des fichiers palette/rhythm/*.
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
~p = ();
|
||||
|
||||
// --- KITS COMPLETS (duplique les valeurs canoniques de drum_kits.scd)
|
||||
// Chaque kit est un Event de variables a appliquer + ~reload.
|
||||
//
|
||||
// NOTE : on utilise la notation `~p[\key]` partout en interne pour
|
||||
// eviter toute collision pseudo-methode. Les sous-cles `kit`, `genre`,
|
||||
// `kick`, `hat`, `snare`, `clap`, `perc`, `list` sont assez longues
|
||||
// pour ne pas collisionner avec les methodes Object SC.
|
||||
~p[\kits] = (
|
||||
\techno: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:55, kickPitchAmt:3.0, kickDecay:0.32, kickDrive:1.3, kickClick:0.2,
|
||||
hatSteps: [0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.18,
|
||||
snareSteps:(0!16), clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\dubstep: (
|
||||
kickSteps:[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], kickAmp:0.6,
|
||||
kickFreq:48, kickPitchAmt:3.5, kickDecay:0.5, kickDrive:1.5, kickClick:0.15,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.5,
|
||||
snareFreq:220, snareNoiseAmt:0.65, snareDecay:0.16,
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.10,
|
||||
clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\dnb: (
|
||||
kickSteps:[1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:55, kickPitchAmt:4.0, kickDecay:0.18, kickDrive:1.5, kickClick:0.3,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1], snareAmp:0.5,
|
||||
snareFreq:240, snareNoiseAmt:0.7, snareDecay:0.10,
|
||||
hatSteps:[1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1], hatAmp:0.12,
|
||||
clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\trap: (
|
||||
kickSteps:[1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0], kickAmp:0.55,
|
||||
kickFreq:42, kickPitchAmt:2.5, kickDecay:0.6, kickDrive:1.2, kickClick:0.08,
|
||||
hatSteps:[1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0], hatAmp:0.10,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.3,
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1], percAmp:0.2,
|
||||
snareSteps:(0!16)
|
||||
),
|
||||
\house: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:50, kickPitchAmt:2.8, kickDecay:0.35, kickDrive:1.2, kickClick:0.12,
|
||||
hatSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.15,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.35,
|
||||
snareSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\hardstyle: (
|
||||
kickSteps:[1,0,0,0,1,0,0,1,1,0,0,0,1,1,0,0], kickAmp:0.65,
|
||||
kickFreq:62, kickPitchAmt:5.5, kickDecay:0.30, kickDrive:4.0, kickClick:0.45,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.55,
|
||||
snareFreq:230, snareNoiseAmt:0.7, snareDecay:0.18,
|
||||
hatSteps:[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1], hatAmp:0.12,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.45,
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,1], percAmp:0.22
|
||||
),
|
||||
\jungle: (
|
||||
kickSteps:[1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0], kickAmp:0.55,
|
||||
kickFreq:55, kickPitchAmt:3.5, kickDecay:0.20, kickDrive:1.6, kickClick:0.32,
|
||||
snareSteps:[0,0,0,0,1,0,1,0,0,0,0,1,1,0,0,1], snareAmp:0.55,
|
||||
snareFreq:220, snareNoiseAmt:0.7, snareDecay:0.10,
|
||||
hatSteps:[1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1], hatAmp:0.12,
|
||||
clapSteps:(0!16),
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0], percAmp:0.30
|
||||
),
|
||||
\garage: (
|
||||
kickSteps:[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0], kickAmp:0.5,
|
||||
kickFreq:50, kickPitchAmt:2.8, kickDecay:0.35, kickDrive:1.2, kickClick:0.15,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0], snareAmp:0.4,
|
||||
snareFreq:200, snareNoiseAmt:0.55, snareDecay:0.20,
|
||||
hatSteps:[0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1], hatAmp:0.11,
|
||||
clapSteps:[0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0], clapAmp:0.32,
|
||||
percInst:\rim, percSteps:(0!16)
|
||||
),
|
||||
\trap808: (
|
||||
kickSteps:[1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0], kickAmp:0.6,
|
||||
kickFreq:38, kickPitchAmt:1.8, kickDecay:0.85, kickDrive:1.0, kickClick:0.05,
|
||||
snareSteps:(0!16),
|
||||
hatSteps:[1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1], hatAmp:0.09,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.35,
|
||||
percInst:\rim, percSteps:[0,0,1,1,0,1,0,0,1,0,1,0,0,1,1,0], percAmp:0.18
|
||||
),
|
||||
\phonk: (
|
||||
kickSteps:[1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0], kickAmp:0.6,
|
||||
kickFreq:40, kickPitchAmt:2.0, kickDecay:0.7, kickDrive:1.2, kickClick:0.08,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.45,
|
||||
snareFreq:280, snareNoiseAmt:0.65, snareDecay:0.14,
|
||||
hatSteps:[1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0], hatAmp:0.11,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.30,
|
||||
percInst:\cowbell, cowbellFreq:800,
|
||||
percSteps:[0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0], percAmp:0.32
|
||||
),
|
||||
\footwork: (
|
||||
kickSteps:[1,0,0,1,1,0,0,0,1,0,1,1,0,0,1,0], kickAmp:0.55,
|
||||
kickFreq:42, kickPitchAmt:2.4, kickDecay:0.5, kickDrive:1.3, kickClick:0.10,
|
||||
snareSteps:(0!16),
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.10,
|
||||
clapSteps:[0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0], clapAmp:0.32,
|
||||
percInst:\rim, percSteps:[0,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1], percAmp:0.22
|
||||
),
|
||||
\industrial: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.6,
|
||||
kickFreq:60, kickPitchAmt:5.0, kickDecay:0.28, kickDrive:3.5, kickClick:0.4,
|
||||
snareSteps:[0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0], snareAmp:0.55,
|
||||
snareFreq:260, snareNoiseAmt:0.8, snareDecay:0.10,
|
||||
hatSteps:[0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1], hatAmp:0.13,
|
||||
clapSteps:(0!16),
|
||||
percInst:\rim, percSteps:[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1], percAmp:0.4
|
||||
),
|
||||
\hardcore: (
|
||||
kickSteps:[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0], kickAmp:0.65,
|
||||
kickFreq:60, kickPitchAmt:5.0, kickDecay:0.20, kickDrive:4.0, kickClick:0.35,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1], snareAmp:0.55,
|
||||
snareFreq:240, snareNoiseAmt:0.85, snareDecay:0.10,
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.12,
|
||||
clapSteps:[0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0], clapAmp:0.42,
|
||||
percSteps:(0!16)
|
||||
),
|
||||
\detroitDeep: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0], kickAmp:0.5,
|
||||
kickFreq:52, kickPitchAmt:2.8, kickDecay:0.32, kickDrive:1.3, kickClick:0.16,
|
||||
snareSteps:(0!16),
|
||||
hatSteps:[0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1], hatAmp:0.13,
|
||||
clapSteps:[0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0], clapAmp:0.32,
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0], percAmp:0.18
|
||||
),
|
||||
\lofiHipHop: (
|
||||
kickSteps:[1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], kickAmp:0.45,
|
||||
kickFreq:45, kickPitchAmt:2.0, kickDecay:0.55, kickDrive:1.0, kickClick:0.04,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.40,
|
||||
snareFreq:190, snareNoiseAmt:0.45, snareDecay:0.15,
|
||||
hatSteps:[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0], hatAmp:0.08,
|
||||
clapSteps:(0!16),
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,0], percAmp:0.14
|
||||
),
|
||||
\tribalWorld: (
|
||||
kickSteps:[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], kickAmp:0.4,
|
||||
kickFreq:48, kickPitchAmt:2.2, kickDecay:0.4, kickDrive:1.0, kickClick:0.06,
|
||||
snareSteps:(0!16),
|
||||
hatSteps:[1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1], hatAmp:0.08,
|
||||
clapSteps:(0!16),
|
||||
percInst:\tom, tomFreq:95,
|
||||
percSteps:[1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0], percAmp:0.4
|
||||
)
|
||||
);
|
||||
|
||||
// --- GENRES (extraits de patterns_genre.scd) -----------------------
|
||||
~p[\genres] = (
|
||||
\hardTechno: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.6,
|
||||
kickFreq:60, kickPitchAmt:4.5, kickDecay:0.28, kickDrive:3.0, kickClick:0.32,
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.14,
|
||||
snareSteps:[0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0], snareAmp:0.5,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.4,
|
||||
percSteps:(0!16)
|
||||
),
|
||||
\acidHouse: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:50, kickPitchAmt:2.8, kickDecay:0.35, kickDrive:1.2, kickClick:0.12,
|
||||
hatSteps:[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1], hatAmp:0.13,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.35,
|
||||
snareSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\trance138: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:55, kickPitchAmt:3.2, kickDecay:0.28, kickDrive:1.5, kickClick:0.20,
|
||||
hatSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.16,
|
||||
snareSteps:(0!16),
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.35,
|
||||
percSteps:(0!16)
|
||||
),
|
||||
\psyTrance: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.6,
|
||||
kickFreq:55, kickPitchAmt:4.0, kickDecay:0.22, kickDrive:1.6, kickClick:0.28,
|
||||
hatSteps:[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1], hatAmp:0.14,
|
||||
snareSteps:(0!16),
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.30,
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], percAmp:0.20
|
||||
),
|
||||
\hardstyle: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.65,
|
||||
kickFreq:62, kickPitchAmt:5.0, kickDecay:0.32, kickDrive:3.8, kickClick:0.42,
|
||||
hatSteps:[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1], hatAmp:0.13,
|
||||
snareSteps:(0!16),
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.45,
|
||||
percSteps:(0!16)
|
||||
),
|
||||
\handsUp: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:58, kickPitchAmt:3.5, kickDecay:0.30, kickDrive:1.6, kickClick:0.25,
|
||||
hatSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.18,
|
||||
snareSteps:(0!16),
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.40,
|
||||
percSteps:(0!16)
|
||||
),
|
||||
\liquidDnB: (
|
||||
kickSteps:[1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0], kickAmp:0.5,
|
||||
kickFreq:50, kickPitchAmt:3.0, kickDecay:0.25, kickDrive:1.3, kickClick:0.20,
|
||||
hatSteps:[1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1], hatAmp:0.10,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.45,
|
||||
clapSteps:(0!16),
|
||||
percInst:\openHat, percSteps:[0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0], percAmp:0.18
|
||||
),
|
||||
\neurofunk: (
|
||||
kickSteps:[1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,1], kickAmp:0.6,
|
||||
kickFreq:58, kickPitchAmt:4.5, kickDecay:0.16, kickDrive:1.8, kickClick:0.4,
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.12,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,1], snareAmp:0.55,
|
||||
clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\jungle165: (
|
||||
kickSteps:[1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0], kickAmp:0.55,
|
||||
kickFreq:55, kickPitchAmt:3.5, kickDecay:0.20, kickDrive:1.6, kickClick:0.32,
|
||||
snareSteps:[0,0,0,0,1,0,1,0,0,0,0,1,1,0,0,1], snareAmp:0.55,
|
||||
hatSteps:[1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1], hatAmp:0.12,
|
||||
clapSteps:(0!16),
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0], percAmp:0.30
|
||||
),
|
||||
\dnbJumpup: (
|
||||
kickSteps:[1,0,0,0,0,0,1,1,0,0,1,0,1,0,0,0], kickAmp:0.6,
|
||||
kickFreq:55, kickPitchAmt:4.0, kickDecay:0.18, kickDrive:1.7, kickClick:0.35,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.55,
|
||||
hatSteps:[1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1], hatAmp:0.12,
|
||||
clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\futureBass: (
|
||||
kickSteps:[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], kickAmp:0.55,
|
||||
kickFreq:50, kickPitchAmt:3.0, kickDecay:0.4, kickDrive:1.3, kickClick:0.20,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], snareAmp:0.5,
|
||||
hatSteps:[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1], hatAmp:0.13,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.35,
|
||||
percSteps:(0!16)
|
||||
),
|
||||
\deepHouse: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.5,
|
||||
kickFreq:48, kickPitchAmt:2.5, kickDecay:0.40, kickDrive:1.2, kickClick:0.10,
|
||||
hatSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.12,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.30,
|
||||
snareSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\techHouse: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:52, kickPitchAmt:3.0, kickDecay:0.30, kickDrive:1.3, kickClick:0.18,
|
||||
hatSteps:[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1], hatAmp:0.13,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.35,
|
||||
snareSteps:(0!16),
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1], percAmp:0.20
|
||||
),
|
||||
\progHouse: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.5,
|
||||
kickFreq:50, kickPitchAmt:2.8, kickDecay:0.35, kickDrive:1.2, kickClick:0.15,
|
||||
hatSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.14,
|
||||
clapSteps:[0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], clapAmp:0.32,
|
||||
snareSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\tribalTechno: (
|
||||
kickSteps:[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], kickAmp:0.55,
|
||||
kickFreq:54, kickPitchAmt:3.0, kickDecay:0.30, kickDrive:1.4, kickClick:0.18,
|
||||
hatSteps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], hatAmp:0.10,
|
||||
snareSteps:(0!16), clapSteps:(0!16),
|
||||
percInst:\tom, tomFreq:90,
|
||||
percSteps:[1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0], percAmp:0.35
|
||||
),
|
||||
\industrialV2: (
|
||||
kickSteps:[1,0,0,0,1,0,0,1,1,0,0,0,1,0,1,0], kickAmp:0.6,
|
||||
kickFreq:62, kickPitchAmt:5.0, kickDecay:0.25, kickDrive:3.5, kickClick:0.40,
|
||||
hatSteps:[1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1], hatAmp:0.12,
|
||||
snareSteps:[0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,1], snareAmp:0.55,
|
||||
clapSteps:(0!16),
|
||||
percInst:\rim, percSteps:[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1], percAmp:0.4
|
||||
),
|
||||
\breakcore: (
|
||||
kickSteps:[1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1], kickAmp:0.6,
|
||||
kickFreq:60, kickPitchAmt:3.0, kickDecay:0.12, kickDrive:2.0, kickClick:0.5,
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.13,
|
||||
snareSteps:[0,1,0,1,1,0,1,0,0,1,1,0,1,1,0,1], snareAmp:0.55,
|
||||
clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\footwork: (
|
||||
kickSteps:[1,0,0,1,1,0,0,0,1,0,1,1,0,0,1,0], kickAmp:0.55,
|
||||
kickFreq:42, kickPitchAmt:2.4, kickDecay:0.5, kickDrive:1.3, kickClick:0.10,
|
||||
hatSteps:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], hatAmp:0.10,
|
||||
clapSteps:[0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0], clapAmp:0.32,
|
||||
snareSteps:(0!16),
|
||||
percInst:\rim, percSteps:[0,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1], percAmp:0.22
|
||||
),
|
||||
\idm: (
|
||||
kickSteps:[1,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0], kickAmp:0.5,
|
||||
kickFreq:55, kickPitchAmt:3.0, kickDecay:0.20, kickDrive:1.5, kickClick:0.30,
|
||||
hatSteps:[1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0], hatAmp:0.12,
|
||||
snareSteps:[0,0,1,0,1,0,0,1,0,0,1,0,1,0,1,0], snareAmp:0.45,
|
||||
clapSteps:(0!16), percSteps:(0!16)
|
||||
),
|
||||
\glitchHop: (
|
||||
kickSteps:[1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0], kickAmp:0.55,
|
||||
kickFreq:50, kickPitchAmt:2.8, kickDecay:0.32, kickDrive:1.3, kickClick:0.20,
|
||||
hatSteps:[1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0], hatAmp:0.11,
|
||||
snareSteps:[0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0], snareAmp:0.45,
|
||||
clapSteps:(0!16),
|
||||
percInst:\rim, percSteps:[0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,0], percAmp:0.18
|
||||
)
|
||||
);
|
||||
|
||||
// --- helper interne : applique un Event de variables sur env --------
|
||||
// Appele directement via [\key] (pas via pseudo-method), donc pas de self.
|
||||
~p[\applyVars] = { |vars|
|
||||
vars.keysValuesDo { |k, v| currentEnvironment[k] = v };
|
||||
~reload !? { ~reload.value };
|
||||
};
|
||||
|
||||
// --- API kit / genre / kick (appelees via ~p[\key].(args)) ----------
|
||||
~p[\kit] = { |name|
|
||||
var k = ~p[\kits][name];
|
||||
if (k.isNil) {
|
||||
("[p.kit] kit '" ++ name ++ "' inconnu. Liste : "
|
||||
++ ~p[\kits].keys.asArray.sort).postln;
|
||||
} {
|
||||
~p[\applyVars].(k);
|
||||
("[p.kit] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~p[\genre] = { |name|
|
||||
var g = ~p[\genres][name];
|
||||
if (g.isNil) {
|
||||
("[p.genre] genre '" ++ name ++ "' inconnu. Liste : "
|
||||
++ ~p[\genres].keys.asArray.sort).postln;
|
||||
} {
|
||||
~p[\applyVars].(g);
|
||||
("[p.genre] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~p[\kick] = { |name|
|
||||
if (~k.notNil) {
|
||||
if (name.isInteger) { ~k[\pat].(name) } { ~k[\go].(name) };
|
||||
} {
|
||||
"[p.kick] kicks.scd non charge".postln;
|
||||
};
|
||||
};
|
||||
|
||||
// --- HAT presets ----------------------------------------------------
|
||||
~p[\hatPresets] = (
|
||||
\off: (0!16),
|
||||
\four: [0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], // 2 & 4 (kick 4/4)
|
||||
\off2: [0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], // offbeat 8th
|
||||
\eighth: [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0], // 8ths
|
||||
\sixteen:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], // 16ths
|
||||
\shuffle:[1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0] // shuffle
|
||||
);
|
||||
~p[\hat] = { |name = \off2|
|
||||
var h = ~p[\hatPresets][name];
|
||||
if (h.isNil) {
|
||||
("[p.hat] inconnu : " ++ ~p[\hatPresets].keys.asArray.sort).postln;
|
||||
} {
|
||||
~hatSteps = h; ~reload !? { ~reload.value };
|
||||
("[p.hat] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// --- SNARE presets --------------------------------------------------
|
||||
~p[\snarePresets] = (
|
||||
\off: (0!16),
|
||||
\two4: [0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
|
||||
\roll: [0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1],
|
||||
\ghost: [0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1]
|
||||
);
|
||||
~p[\snare] = { |name = \two4|
|
||||
var s = ~p[\snarePresets][name];
|
||||
if (s.isNil) {
|
||||
("[p.snare] inconnu : " ++ ~p[\snarePresets].keys.asArray.sort).postln;
|
||||
} {
|
||||
~snareSteps = s; ~reload !? { ~reload.value };
|
||||
("[p.snare] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// --- CLAP presets ---------------------------------------------------
|
||||
~p[\clapPresets] = (
|
||||
\off: (0!16),
|
||||
\two4: [0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
|
||||
\offbeat: [0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0],
|
||||
\dub: [0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1],
|
||||
\trance: [0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0]
|
||||
);
|
||||
~p[\clap] = { |name = \two4|
|
||||
var c = ~p[\clapPresets][name];
|
||||
if (c.isNil) {
|
||||
("[p.clap] inconnu : " ++ ~p[\clapPresets].keys.asArray.sort).postln;
|
||||
} {
|
||||
~clapSteps = c; ~reload !? { ~reload.value };
|
||||
("[p.clap] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// --- PERC presets (steps + percInst) -------------------------------
|
||||
~p[\percPresets] = (
|
||||
\off: ( steps:(0!16), inst: \rim ),
|
||||
\rim: ( steps:[0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0], inst: \rim ),
|
||||
\tom: ( steps:[1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0], inst: \tom ),
|
||||
\cowbell:( steps:[0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0], inst: \cowbell ),
|
||||
\openHat:( steps:[0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0], inst: \openHat )
|
||||
);
|
||||
~p[\perc] = { |name = \rim|
|
||||
var pp = ~p[\percPresets][name];
|
||||
if (pp.isNil) {
|
||||
("[p.perc] inconnu : " ++ ~p[\percPresets].keys.asArray.sort).postln;
|
||||
} {
|
||||
~percSteps = pp[\steps]; ~percInst = pp[\inst];
|
||||
~reload !? { ~reload.value };
|
||||
("[p.perc] " ++ name ++ " (inst=" ++ pp[\inst] ++ ")").postln;
|
||||
};
|
||||
};
|
||||
|
||||
// --- LISTE ----------------------------------------------------------
|
||||
~p[\list] = {
|
||||
"=== ~p -- RHYTHM PRESETS ===".postln;
|
||||
" kits : ".post; ~p[\kits].keys.asArray.sort.postln;
|
||||
" genres : ".post; ~p[\genres].keys.asArray.sort.postln;
|
||||
" hat : ".post; ~p[\hatPresets].keys.asArray.sort.postln;
|
||||
" snare : ".post; ~p[\snarePresets].keys.asArray.sort.postln;
|
||||
" clap : ".post; ~p[\clapPresets].keys.asArray.sort.postln;
|
||||
" perc : ".post; ~p[\percPresets].keys.asArray.sort.postln;
|
||||
" USAGE : ~pKit.(\\techno) | ~pGenre.(\\hardTechno) | ~pHat.(\\eighth)".postln;
|
||||
};
|
||||
|
||||
// --- API utilisateur : variables d'env top-level --------------------
|
||||
~pKit = { |name| ~p[\kit].(name) };
|
||||
~pGenre = { |name| ~p[\genre].(name) };
|
||||
~pKick = { |name| ~p[\kick].(name) };
|
||||
~pHat = { |name = \off2| ~p[\hat].(name) };
|
||||
~pSnare = { |name = \two4| ~p[\snare].(name) };
|
||||
~pClap = { |name = \two4| ~p[\clap].(name) };
|
||||
~pPerc = { |name = \rim| ~p[\perc].(name) };
|
||||
~pList = { ~p[\list].() };
|
||||
|
||||
"=== ~p pret -- ~pKit.(\\techno) | ~pGenre.(\\hardTechno) | ~pList.() ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES (Cmd+Entree)
|
||||
// =====================================================================
|
||||
|
||||
// --- KITS complets ---
|
||||
// ( ~pKit.(\techno); )
|
||||
// ( ~pKit.(\dubstep); )
|
||||
// ( ~pKit.(\dnb); )
|
||||
// ( ~pKit.(\trap); )
|
||||
// ( ~pKit.(\house); )
|
||||
// ( ~pKit.(\hardstyle); )
|
||||
// ( ~pKit.(\jungle); )
|
||||
// ( ~pKit.(\garage); )
|
||||
// ( ~pKit.(\trap808); )
|
||||
// ( ~pKit.(\phonk); )
|
||||
// ( ~pKit.(\footwork); )
|
||||
// ( ~pKit.(\industrial); )
|
||||
// ( ~pKit.(\hardcore); )
|
||||
// ( ~pKit.(\detroitDeep); )
|
||||
// ( ~pKit.(\lofiHipHop); )
|
||||
// ( ~pKit.(\tribalWorld); )
|
||||
|
||||
// --- GENRES rythmiques ---
|
||||
// ( ~pGenre.(\hardTechno); )
|
||||
// ( ~pGenre.(\acidHouse); )
|
||||
// ( ~pGenre.(\trance138); )
|
||||
// ( ~pGenre.(\psyTrance); )
|
||||
// ( ~pGenre.(\hardstyle); )
|
||||
// ( ~pGenre.(\handsUp); )
|
||||
// ( ~pGenre.(\liquidDnB); )
|
||||
// ( ~pGenre.(\neurofunk); )
|
||||
// ( ~pGenre.(\jungle165); )
|
||||
// ( ~pGenre.(\dnbJumpup); )
|
||||
// ( ~pGenre.(\futureBass); )
|
||||
// ( ~pGenre.(\deepHouse); )
|
||||
// ( ~pGenre.(\techHouse); )
|
||||
// ( ~pGenre.(\progHouse); )
|
||||
// ( ~pGenre.(\tribalTechno); )
|
||||
// ( ~pGenre.(\industrialV2); )
|
||||
// ( ~pGenre.(\breakcore); )
|
||||
// ( ~pGenre.(\footwork); )
|
||||
// ( ~pGenre.(\idm); )
|
||||
// ( ~pGenre.(\glitchHop); )
|
||||
|
||||
// --- KICK seul (raccourci kicks.scd) ---
|
||||
// ( ~pKick.(\techno); )
|
||||
// ( ~pKick.(7); )
|
||||
|
||||
// --- composants individuels ---
|
||||
// ( ~pHat.(\eighth); )
|
||||
// ( ~pHat.(\sixteen); )
|
||||
// ( ~pHat.(\off); )
|
||||
// ( ~pSnare.(\two4); )
|
||||
// ( ~pSnare.(\ghost); )
|
||||
// ( ~pClap.(\trance); )
|
||||
// ( ~pClap.(\off); )
|
||||
// ( ~pPerc.(\rim); )
|
||||
// ( ~pPerc.(\tom); )
|
||||
|
||||
// --- liste ---
|
||||
// ( ~pList.(); )
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
// =====================================================================
|
||||
// scenes.scd -- Save / Recall scenes (snapshot etat global)
|
||||
//
|
||||
// Capture l'etat des variables (~kickAmp, ~melodyNotes, ~melodyInst, etc.)
|
||||
// dans un dictionnaire. Recall = restaure tout + reload Pdef.
|
||||
//
|
||||
// USAGE :
|
||||
// 1. Cmd+Entree sur SETUP (charge les helpers)
|
||||
// 2. Pendant qu'une track tourne, Cmd+Entree sur SAVE -> nom au choix
|
||||
// 3. Plus tard, Cmd+Entree sur RECALL -> reapplique tout
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- SETUP -- definit ~scenes (Dictionary global) + helpers --------
|
||||
(
|
||||
~scenes = ~scenes ?? { Dictionary.new };
|
||||
|
||||
// Liste des cles d'etat a snapshotter
|
||||
~sceneKeys = [
|
||||
\bpm,
|
||||
\kickSteps, \kickAmp, \kickFreq, \kickPitchAmt, \kickDecay, \kickDrive, \kickClick,
|
||||
\hatSteps, \hatAmp,
|
||||
\snareSteps, \snareAmp, \snareFreq, \snareNoiseAmt, \snareDecay,
|
||||
\clapSteps, \clapAmp,
|
||||
\percSteps, \percAmp, \percInst, \tomFreq, \cowbellFreq,
|
||||
\acidNotes, \acidAccents, \acidSlides,
|
||||
\acidCutoff, \acidRq, \acidCutoffEnv, \acidDrive, \acidAmp,
|
||||
\melodyNotes, \melodyInst, \melodyBoost,
|
||||
\melodyCutoff, \melodyRq, \melodyAmp, \melodyDrive,
|
||||
\melodyAttack, \melodyRelease,
|
||||
\melodySawAmt, \melodyDetune,
|
||||
\melodyWobbleRate, \melodyWobbleDepth, \melodyWobbleShape, \melodySubAmt,
|
||||
\harmonyInst, \harmonyNotes, \harmonyAmp, \harmonyDur,
|
||||
\harmonyCutoff, \harmonyRq, \harmonyAttack, \harmonyDecay,
|
||||
\harmonySustain, \harmonyRelease, \harmonyDrive,
|
||||
\harmonySawAmt, \harmonyDetune,
|
||||
\acidScAmt, \leadScAmt, \kickScShape,
|
||||
];
|
||||
|
||||
// Sauvegarde l'etat courant sous un nom
|
||||
~saveScene = { |name|
|
||||
var scene = Dictionary.new;
|
||||
~sceneKeys.do { |k|
|
||||
var val = currentEnvironment[k];
|
||||
if (val.notNil) { scene.put(k, val) };
|
||||
};
|
||||
scene.put(\bpm, TempoClock.default.tempo * 60);
|
||||
~scenes.put(name, scene);
|
||||
("[scene saved] " ++ name ++ " -- " ++ scene.size ++ " keys").postln;
|
||||
};
|
||||
|
||||
// Recharge un scene par nom
|
||||
~loadScene = { |name|
|
||||
var scene = ~scenes[name];
|
||||
if (scene.isNil) {
|
||||
("!! scene '" ++ name ++ "' inexistante. Disponibles : " ++
|
||||
~scenes.keys.asArray).postln;
|
||||
} {
|
||||
scene.keysValuesDo { |k, v|
|
||||
if (k == \bpm) {
|
||||
TempoClock.default.tempo = v / 60;
|
||||
} {
|
||||
currentEnvironment.put(k, v);
|
||||
};
|
||||
};
|
||||
~reload.value;
|
||||
("[scene loaded] " ++ name).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// Liste des scenes
|
||||
~listScenes = {
|
||||
"=== SCENES ===".postln;
|
||||
if (~scenes.size == 0) {
|
||||
" (aucune scene sauvegardee)".postln;
|
||||
} {
|
||||
~scenes.keysValuesDo { |k, v|
|
||||
(" " ++ k ++ " (" ++ v.size ++ " keys)").postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Supprime un scene
|
||||
~deleteScene = { |name|
|
||||
if (~scenes.includesKey(name)) {
|
||||
~scenes.removeAt(name);
|
||||
("[scene deleted] " ++ name).postln;
|
||||
} { ("scene '" ++ name ++ "' inexistante").postln };
|
||||
};
|
||||
|
||||
// Sauvegarde toutes les scenes sur disque (en JSON-like)
|
||||
~saveScenesToDisk = { |path|
|
||||
var p = path ?? { ~base ++ "scenes_saved.scd" };
|
||||
var f = File(p, "w");
|
||||
f.write("// Scenes sauvegardees " ++ Date.localtime.asString ++ "\n");
|
||||
f.write("(\n~scenes = ~scenes ?? { Dictionary.new };\n");
|
||||
~scenes.keysValuesDo { |name, scene|
|
||||
f.write("~scenes.put('" ++ name ++ "', Dictionary[\n");
|
||||
scene.keysValuesDo { |k, v|
|
||||
f.write(" '" ++ k ++ "' -> " ++ v.asCompileString ++ ",\n");
|
||||
};
|
||||
f.write("]);\n");
|
||||
};
|
||||
f.write(")\n");
|
||||
f.close;
|
||||
("[scenes saved to] " ++ p).postln;
|
||||
};
|
||||
|
||||
// Recharge depuis disque
|
||||
~loadScenesFromDisk = { |path|
|
||||
var p = path ?? { ~base ++ "scenes_saved.scd" };
|
||||
if (File.exists(p)) {
|
||||
p.load;
|
||||
("[scenes loaded from] " ++ p).postln;
|
||||
} { ("Pas de fichier " ++ p).postln };
|
||||
};
|
||||
|
||||
"=== ~saveScene / ~loadScene / ~listScenes / ~deleteScene prets ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES D'USAGE -- Cmd+Entree pendant qu'une track tourne
|
||||
// =====================================================================
|
||||
|
||||
// --- Sauvegarder l'etat courant -----------------------------------
|
||||
( ~saveScene.(\drop1); )
|
||||
( ~saveScene.(\verseA); )
|
||||
( ~saveScene.(\breakdown); )
|
||||
( ~saveScene.(\dropFinal); )
|
||||
( ~saveScene.(\favorite); )
|
||||
|
||||
// --- Rappeler une scene -------------------------------------------
|
||||
( ~loadScene.(\drop1); )
|
||||
( ~loadScene.(\breakdown); )
|
||||
( ~loadScene.(\favorite); )
|
||||
|
||||
// --- Lister scenes / supprimer ------------------------------------
|
||||
( ~listScenes.value; )
|
||||
( ~deleteScene.(\favorite); )
|
||||
|
||||
// --- Persistence sur disque ---------------------------------------
|
||||
( ~saveScenesToDisk.value; ) // sauvegarde dans scenes_saved.scd
|
||||
( ~loadScenesFromDisk.value; ) // recharge depuis scenes_saved.scd
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
// =====================================================================
|
||||
// tweaks.scd -- Tweaks live (cutoff, drive, mute, tempo, sidechain,
|
||||
// wobble dubstep, sub, melody boost, randomize, sweep)
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue + PLAY actif (ou une track en cours).
|
||||
// USAGE : Cmd+Entree sur la ligne du tweak.
|
||||
// =====================================================================
|
||||
|
||||
// 6. TWEAKS LIVE -- modifie une seule chose
|
||||
// =====================================================================
|
||||
|
||||
// --- Cutoff acid ----------------------------------------
|
||||
( ~acidCutoff = 200; ~reload.value; )
|
||||
( ~acidCutoff = 600; ~reload.value; )
|
||||
( ~acidCutoff = 1200; ~reload.value; )
|
||||
( ~acidCutoff = 2500; ~reload.value; )
|
||||
|
||||
// --- Resonance acid -------------------------------------
|
||||
( ~acidRq = 0.05; ~reload.value; ) // EXTREME
|
||||
( ~acidRq = 0.15; ~reload.value; ) // normal
|
||||
( ~acidRq = 0.4; ~reload.value; ) // doux
|
||||
|
||||
// --- Drive acid -----------------------------------------
|
||||
( ~acidDrive = 1.0; ~reload.value; )
|
||||
( ~acidDrive = 2.5; ~reload.value; )
|
||||
( ~acidDrive = 4.5; ~reload.value; )
|
||||
|
||||
// --- Tempo en live --------------------------------------
|
||||
( TempoClock.default.tempo = 110/60; )
|
||||
( TempoClock.default.tempo = 132/60; )
|
||||
( TempoClock.default.tempo = 145/60; )
|
||||
|
||||
// --- Boost global du volume melodie (multiplicateur) ----
|
||||
( ~melodyBoost = 1.0; ~reload.value; "melody boost x1.0".postln; )
|
||||
( ~melodyBoost = 1.6; ~reload.value; "melody boost x1.6 (defaut)".postln; )
|
||||
( ~melodyBoost = 2.2; ~reload.value; "melody boost x2.2 (en avant)".postln; )
|
||||
( ~melodyBoost = 3.0; ~reload.value; "melody boost x3.0 (devant tout)".postln; )
|
||||
|
||||
// --- Niveau du kick (le rendre plus / moins present) ---
|
||||
( ~kickAmp = 0.3; ~reload.value; ) // discret
|
||||
( ~kickAmp = 0.5; ~reload.value; ) // normal
|
||||
( ~kickAmp = 0.7; ~reload.value; ) // fort
|
||||
|
||||
// --- Mute / Unmute par piste ---------------------------
|
||||
( ~kickAmp = 0; ~reload.value; )
|
||||
( ~kickAmp = 0.5; ~reload.value; )
|
||||
( ~hatAmp = 0; ~reload.value; )
|
||||
( ~hatAmp = 0.18; ~reload.value; )
|
||||
( ~acidAmp = 0; ~reload.value; )
|
||||
( ~acidAmp = 0.32; ~reload.value; )
|
||||
( ~melodyAmp = 0; ~reload.value; )
|
||||
( ~melodyAmp = 0.16; ~reload.value; )
|
||||
|
||||
// --- Sidechain : amount de pompage par voix --------------
|
||||
( ~acidScAmt = 0; ~reload.value; ) // pas de duck acid
|
||||
( ~acidScAmt = 0.4; ~reload.value; ) // duck leger
|
||||
( ~acidScAmt = 0.7; ~reload.value; ) // duck normal (default)
|
||||
( ~acidScAmt = 0.95; ~reload.value; ) // duck extreme (acid disparait sur kick)
|
||||
( ~leadScAmt = 0; ~reload.value; ) // pas de duck lead
|
||||
( ~leadScAmt = 0.5; ~reload.value; ) // duck normal (default)
|
||||
( ~leadScAmt = 0.85; ~reload.value; ) // duck fort
|
||||
|
||||
// --- Sidechain : duree de la queue de duck ---------------
|
||||
( ~kickScShape = 0.08; ~reload.value; ) // tres court (peu perceptible)
|
||||
( ~kickScShape = 0.18; ~reload.value; ) // normal
|
||||
( ~kickScShape = 0.35; ~reload.value; ) // long (style french touch)
|
||||
|
||||
// --- ALEATOIRE -- regenere les patterns sans toucher au tempo --------
|
||||
( ~melodyNotes = ~genMelody.(0.55, ~scaleMinorPent); ~reload.value; "melody random".postln; )
|
||||
( ~melodyNotes = ~genMelody.(0.35, ~scaleMinor); ~reload.value; "melody sparse".postln; )
|
||||
( ~acidNotes = ~genAcidNotes.value;
|
||||
~acidAccents = ~genAcidAccents.(0.4);
|
||||
~acidSlides = ~genAcidSlides.(0.3);
|
||||
~reload.value; "acid random".postln; )
|
||||
( ~kickSteps = ~genKickPattern.(0.3); ~reload.value; "kick random ghosts".postln; )
|
||||
( ~hatSteps = ~genKickPattern.(0.6); ~reload.value; "hat random".postln; )
|
||||
|
||||
// --- TOUT random d'un coup -----------------------------------------
|
||||
(
|
||||
~melodyNotes = ~genMelody.(0.55);
|
||||
~acidNotes = ~genAcidNotes.value;
|
||||
~acidAccents = ~genAcidAccents.(0.4);
|
||||
~acidSlides = ~genAcidSlides.(0.3);
|
||||
~kickSteps = ~genKickPattern.(0.25);
|
||||
~hatSteps = ~genKickPattern.(0.5);
|
||||
~acidCutoff = rrand(500, 2000);
|
||||
~acidRq = rrand(0.08, 0.25);
|
||||
~melodyCutoff = rrand(1500, 3500);
|
||||
~reload.value;
|
||||
"=== TOUT randomise ===".postln;
|
||||
)
|
||||
|
||||
// --- Boucle de tweaks aleatoires (toutes les 4s) -------------------
|
||||
(
|
||||
~randomLoop !? { ~randomLoop.stop };
|
||||
~randomLoop = Routine({
|
||||
inf.do {
|
||||
~randomTweak.(0.35);
|
||||
4.wait;
|
||||
};
|
||||
}).play;
|
||||
"random tweaks ON".postln;
|
||||
)
|
||||
( ~randomLoop !? { ~randomLoop.stop }; "random tweaks OFF".postln; )
|
||||
|
||||
// --- Filtre sweep auto sur l'acid (Routine 8s) ----------
|
||||
(
|
||||
~filterSweep !? { ~filterSweep.stop };
|
||||
~filterSweep = Routine({
|
||||
inf.do { |k|
|
||||
var x = ((k / 32) * 2 * pi).sin.abs;
|
||||
~acidCutoff = 200 + (x * 2300);
|
||||
~reload.value;
|
||||
0.25.wait;
|
||||
};
|
||||
}).play;
|
||||
"sweep auto demarre".postln;
|
||||
)
|
||||
( ~filterSweep !? { ~filterSweep.stop }; "sweep stoppe".postln; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// RECORDING -- enregistre la sortie audio dans ~/Music/SuperCollider Recordings/
|
||||
// =====================================================================
|
||||
( s.record; "=== RECORDING ===".postln; )
|
||||
( s.stopRecording; "=== RECORD STOP ===".postln; )
|
||||
( s.recordPaused = true; "=== PAUSE record ===".postln; )
|
||||
( s.recordPaused = false; "=== RESUME record ===".postln; )
|
||||
|
||||
// Path du recording courant
|
||||
( s.recHeaderFormat = "WAV"; s.recSampleFormat = "int24"; "format WAV 24bit".postln; )
|
||||
@@ -0,0 +1,43 @@
|
||||
# palette/ — Generators & banques
|
||||
|
||||
Source de verite pour scales, melodies, harmonies, rythmes, timbres,
|
||||
chords, FX genre. Charge automatiquement par `00_load.scd`.
|
||||
|
||||
## Structure
|
||||
|
||||
| Sous-dossier | Charge via |
|
||||
| --- | --- |
|
||||
| `palette/scales.scd` | direct (avant melodies + harmonics) |
|
||||
| `palette/melodies/` | `melodies/index.scd` |
|
||||
| `palette/harmonics/` | `harmonics/index.scd` |
|
||||
| `palette/rhythm/` | `rhythm/fills.scd` (auto), reste manuel |
|
||||
| `palette/{timbres,styles,chords_progressions,fx_genre}.scd` | manuel |
|
||||
|
||||
## Conventions de nommage
|
||||
|
||||
- Scales : `~scaleMinor`, `~scaleHijaz`, `~scaleVietnamMaj`, ...
|
||||
(toutes basees sur C/60, octaves +/-)
|
||||
- Melodies : `~m{N}` (32 pas), `~ml{N}` (64), `~mxl{N}` (96), `~mepic{N}` (128)
|
||||
- Generators : verb-first (`~genMelody`, `~mutate`, `~enableHarmony`)
|
||||
- Banques exposees via `live/melodies.scd` et `live/patterns.scd`
|
||||
|
||||
## Patterns generators
|
||||
|
||||
```supercollider
|
||||
~genMelody = { |density = 0.55, scale, len = 32|
|
||||
var s = scale ?? { ~scaleMinorPent };
|
||||
len.collect { if (density.coin) { s.choose } { 0 } };
|
||||
};
|
||||
```
|
||||
|
||||
- Generators retournent toujours un Array de notes MIDI (0 = silence)
|
||||
- Density = 0..1 (0 = vide, 1 = plein)
|
||||
- Scale par defaut via `??` fallback, jamais nil
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Ne pas dupliquer une scale qui existe deja dans `scales.scd`
|
||||
- Ne pas creer de generator qui mute `~xxx` directement -- retourner la valeur
|
||||
- Ne pas indexer une scale hors bornes (utiliser `.wrapAt` ou `.choose`)
|
||||
- Ne pas creer de fichier `index.scd` qui charge en dehors de `palette/`
|
||||
- Ne pas charger `palette/melodies/*` avant `palette/scales.scd`
|
||||
@@ -0,0 +1,533 @@
|
||||
// =====================================================================
|
||||
// chords_progressions.scd -- Progressions d'accords authentiques
|
||||
// (issus de la deep recherche)
|
||||
//
|
||||
// Cm = i, Eb = III, Ab = VI, Bb = VII (degres mineur naturel)
|
||||
// =====================================================================
|
||||
|
||||
// --- Trance i-VII-VI-VII (Am-G-F-G classique) ---------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 64, 0, 67, 0, // Am
|
||||
55, 0, 59, 0, 62, 0, 67, 0, // G
|
||||
53, 0, 57, 0, 60, 0, 65, 0, // F
|
||||
55, 0, 59, 0, 62, 0, 67, 0 // G
|
||||
];
|
||||
~reload.value; "trance i-VII-VI-VII".postln;
|
||||
)
|
||||
|
||||
// --- Detroit Cm-Eb-Ab-Bb (mineur naturel, soulful) ---------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 63, 0, 67, 0, 70, 0, // Cm
|
||||
63, 0, 65, 0, 67, 0, 72, 0, // Eb
|
||||
56, 0, 60, 0, 63, 0, 68, 0, // Ab (b6)
|
||||
58, 0, 62, 0, 65, 0, 70, 0 // Bb (b7)
|
||||
];
|
||||
~reload.value; "detroit Cm-Eb-Ab-Bb".postln;
|
||||
)
|
||||
|
||||
// --- Vocal trance i-VI-III-VII (Am-F-C-G emotional) ---------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 64, 0, 0, 0, // Am
|
||||
53, 0, 57, 0, 60, 0, 0, 0, // F
|
||||
60, 0, 64, 0, 67, 0, 0, 0, // C
|
||||
55, 0, 59, 0, 62, 0, 0, 0 // G
|
||||
];
|
||||
~reload.value; "vocal trance i-VI-III-VII".postln;
|
||||
)
|
||||
|
||||
// --- Synthwave i-bVI-bVII-i (Am-F-G-Am 80s) ----------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 64, 60, 0, 64, 67, // Am
|
||||
53, 0, 57, 60, 57, 0, 60, 65, // F
|
||||
55, 0, 59, 62, 59, 0, 62, 67, // G
|
||||
57, 0, 60, 64, 60, 64, 67, 72 // Am
|
||||
];
|
||||
~reload.value; "synthwave i-bVI-bVII-i".postln;
|
||||
)
|
||||
|
||||
// --- Phonk i-bVII-bVI dark loop ----------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
48, 0, 0, 0, 51, 0, 0, 0, // Cm root
|
||||
46, 0, 0, 0, 50, 0, 0, 0, // Bb (bVII)
|
||||
44, 0, 0, 0, 48, 0, 0, 0, // Ab (bVI)
|
||||
46, 0, 0, 0, 51, 0, 0, 0 // Bb
|
||||
];
|
||||
~reload.value; "phonk dark i-bVII-bVI".postln;
|
||||
)
|
||||
|
||||
// --- Dubstep mineur harmonique (Cm avec B natural) ---------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
36, 0, 0, 0, 36, 0, 39, 0, // C bass
|
||||
36, 0, 0, 0, 41, 0, 0, 0, // F
|
||||
36, 0, 0, 0, 39, 0, 41, 0, // C-Eb-F
|
||||
47, 0, 0, 0, 48, 0, 0, 0 // B-C (lead tone)
|
||||
];
|
||||
~reload.value; "dubstep harmonic minor".postln;
|
||||
)
|
||||
|
||||
// --- Acid trance phrygien dominant (E phryigien) -----------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
52, 53, 56, 59, 60, 59, 56, 53, // E F G# B C
|
||||
52, 53, 56, 59, 60, 64, 60, 59,
|
||||
52, 56, 59, 60, 64, 67, 64, 60,
|
||||
52, 53, 56, 59, 60, 59, 56, 52
|
||||
];
|
||||
~reload.value; "acid phrygien dominant".postln;
|
||||
)
|
||||
|
||||
// --- Drum'n'Bass liquid (Em mélodique) ---------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
64, 0, 67, 0, 71, 0, 67, 64, // Em
|
||||
62, 0, 65, 0, 69, 0, 67, 0, // D
|
||||
60, 0, 64, 0, 67, 0, 71, 0, // C
|
||||
59, 0, 62, 0, 67, 0, 71, 0 // B
|
||||
];
|
||||
~reload.value; "liquid dnb Em melodic".postln;
|
||||
)
|
||||
|
||||
// --- Detroit Cm7 jazz comping ------------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 63, 67, 70, 67, 63, 60, 67, // Cm7
|
||||
55, 60, 63, 65, 60, 55, 0, 0,
|
||||
58, 62, 65, 68, 65, 62, 58, 65, // Bb7
|
||||
60, 63, 67, 70, 0, 0, 0, 0
|
||||
];
|
||||
~reload.value; "detroit Cm7 jazz".postln;
|
||||
)
|
||||
|
||||
// --- Asian pentatonique majeure (Do Re Mi Sol La) ----------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 62, 0, 65, 0, 67, 0,
|
||||
69, 0, 67, 0, 65, 0, 62, 0,
|
||||
72, 0, 69, 0, 67, 0, 65, 0,
|
||||
62, 0, 60, 0, 65, 0, 67, 0
|
||||
];
|
||||
~reload.value; "asian penta majeure".postln;
|
||||
)
|
||||
|
||||
// --- Hirajoshi (gamme japonaise 1, 2, b3, 5, b6) -----------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 62, 63, 0, 67, 68, 0,
|
||||
72, 0, 68, 67, 63, 62, 60, 0,
|
||||
60, 0, 62, 63, 67, 68, 72, 0,
|
||||
74, 75, 72, 68, 67, 63, 62, 60
|
||||
];
|
||||
~reload.value; "hirajoshi japonais".postln;
|
||||
)
|
||||
|
||||
// --- Industrial : atonal/cluster (chromatique sombre) -----------
|
||||
(
|
||||
~melodyNotes = [
|
||||
36, 37, 0, 39, 36, 0, 38, 37,
|
||||
36, 37, 38, 40, 0, 39, 37, 36,
|
||||
36, 0, 39, 0, 41, 0, 39, 0,
|
||||
36, 37, 0, 36, 0, 38, 36, 0
|
||||
];
|
||||
~reload.value; "industrial atonal cluster".postln;
|
||||
)
|
||||
|
||||
// --- Drone doom : quintes ouvertes (power chords) ---------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
36, 0, 0, 0, 0, 0, 0, 0,
|
||||
43, 0, 0, 0, 0, 0, 0, 0, // 5te
|
||||
36, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 0, 0, 0, 0, 0, 0, 0 // b6
|
||||
];
|
||||
~reload.value; "drone doom power chords".postln;
|
||||
)
|
||||
|
||||
// --- Tribal : modal hijaz (gamme arabe) -------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 61, 0, 64, 0, 65, 0, // 1, b2, 3, 4
|
||||
67, 0, 68, 0, 71, 0, 72, 0, // 5, b6, 7, 1
|
||||
72, 0, 71, 0, 68, 0, 67, 0,
|
||||
65, 0, 64, 0, 61, 0, 60, 0
|
||||
];
|
||||
~reload.value; "tribal hijaz arabe".postln;
|
||||
)
|
||||
|
||||
// --- Glitch IDM : intervalles dissonants --------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 73, 67, 0, 72, 65, 0, 71,
|
||||
63, 0, 76, 67, 0, 60, 73, 0,
|
||||
65, 0, 72, 79, 65, 0, 71, 60,
|
||||
73, 67, 0, 80, 64, 71, 65, 0
|
||||
];
|
||||
~reload.value; "glitch IDM dissonant".postln;
|
||||
)
|
||||
|
||||
// --- Hardcore : mineur harmonique distordu ------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
36, 0, 0, 0, 39, 0, 0, 0,
|
||||
41, 0, 0, 0, 47, 0, 0, 0, // 7e majeure caracteristique mineur harmonique
|
||||
48, 0, 0, 0, 47, 0, 41, 0,
|
||||
39, 0, 0, 0, 36, 0, 0, 0
|
||||
];
|
||||
~reload.value; "hardcore mineur harmonique".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ===== TABLEAUX D'ACCORDS (~progXxx) ==============================
|
||||
//
|
||||
// Format compact : ~progXxx = [[c1n1, c1n2, c1n3], [c2n1, c2n2, c2n3], ...]
|
||||
// chaque sous-array = 1 accord (3 ou 4 notes MIDI).
|
||||
// A utiliser depuis melodies/harmony helpers ou pour generer
|
||||
// ~melodyNotes/~harmonyNotes en deroulant les accords.
|
||||
//
|
||||
// Helper : ~chordsToMelody.(progArr, stepsPerChord) deroule un tableau
|
||||
// d'accords en ligne melodique (top note de chaque accord, espacee).
|
||||
// =====================================================================
|
||||
(
|
||||
// --- Helper : deroule progression en ligne melodique 32 steps ---------
|
||||
~chordsToMelody = { |prog, stepsPerChord = 8|
|
||||
var n = prog.size;
|
||||
var notes = Array.fill(n * stepsPerChord, { 0 });
|
||||
prog.do { |chord, ci|
|
||||
// place tonique sur premier step, top sur step central
|
||||
notes[ci * stepsPerChord] = chord[0];
|
||||
if (chord.size > 1) {
|
||||
notes[ci * stepsPerChord + (stepsPerChord/2).asInteger] = chord.last;
|
||||
};
|
||||
};
|
||||
notes;
|
||||
};
|
||||
|
||||
// --- Helper : deroule prog en harmonie (toutes notes empilees) -------
|
||||
~chordsToHarmony = { |prog, stepsPerChord = 8|
|
||||
var n = prog.size;
|
||||
var notes = Array.fill(n * stepsPerChord, { 0 });
|
||||
// mode simple : tonique de chaque accord en debut
|
||||
prog.do { |chord, ci|
|
||||
notes[ci * stepsPerChord] = chord[0];
|
||||
};
|
||||
notes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// --- Jazz ii-V-I (en C : Dm7 G7 Cmaj7) -------------------------------
|
||||
~progIIVI = [ [62, 65, 69, 72], [55, 59, 62, 65], [60, 64, 67, 71] ];
|
||||
|
||||
// --- Rock/Blues I-IV-V (en C) ---------------------------------------
|
||||
~progIIVV = [ [60, 64, 67], [65, 69, 72], [67, 71, 74] ];
|
||||
|
||||
// --- Pop I-V-vi-IV (en C) -- "axis of awesome" ----------------------
|
||||
~progPop = [ [60, 64, 67], [67, 71, 74], [69, 72, 76], [65, 69, 72] ];
|
||||
|
||||
// --- Sad pop vi-IV-I-V (en C) ---------------------------------------
|
||||
~progSadPop = [ [69, 72, 76], [65, 69, 72], [60, 64, 67], [67, 71, 74] ];
|
||||
|
||||
// --- Epique mineur i-iv-VII-III (en Am) -----------------------------
|
||||
~progEpicMin = [ [57, 60, 64], [62, 65, 69], [67, 71, 74], [64, 67, 71] ];
|
||||
|
||||
// --- Andalouse i-VI-III-VII (en Am) ---------------------------------
|
||||
~progAndalou = [ [57, 60, 64], [65, 69, 72], [60, 64, 67], [67, 71, 74] ];
|
||||
|
||||
// --- Rock mineur i-bVII-bVI-bVII (en Am) ----------------------------
|
||||
~progRockMin = [ [57, 60, 64], [55, 59, 62], [53, 57, 60], [55, 59, 62] ];
|
||||
|
||||
// --- Flamenco i-bVII-bVI-V (en Am) ----------------------------------
|
||||
~progFlamenco = [ [57, 60, 64], [55, 59, 62], [53, 57, 60], [52, 56, 59] ];
|
||||
|
||||
// --- Jazz turn-around I-vi-ii-V (en C) ------------------------------
|
||||
~progTurnArnd = [ [60, 64, 67, 71], [69, 72, 76, 79], [62, 65, 69, 72], [55, 59, 62, 65] ];
|
||||
|
||||
// --- Modal interchange (bIII, bVI, bVII en C major) ------------------
|
||||
~progModal = [ [60, 64, 67], [63, 67, 70], [68, 72, 75], [70, 74, 77] ];
|
||||
|
||||
// --- Tritone substitution (Dm7 - Db7 - Cmaj7) ------------------------
|
||||
~progTritone = [ [62, 65, 69, 72], [49, 53, 56, 59], [60, 64, 67, 71] ];
|
||||
|
||||
// --- Minor 7th progressions (Cm7-Fm7-Bb7-Ebmaj7) --------------------
|
||||
~progMin7 = [ [60, 63, 67, 70], [65, 68, 72, 75], [58, 62, 65, 68], [63, 67, 70, 74] ];
|
||||
|
||||
// --- Coltrane changes (B-D-Eb-Gb-G-Bb-B) augmente -------------------
|
||||
~progColtrane = [ [59, 63, 66], [50, 54, 57], [51, 55, 58],
|
||||
[54, 58, 61], [55, 59, 62], [58, 62, 65], [59, 63, 66] ];
|
||||
|
||||
// --- Phrygien i-bII-bVII-bVI (en E phrygien) ------------------------
|
||||
~progPhrygien = [ [52, 55, 59], [53, 56, 60], [50, 53, 57], [48, 51, 55] ];
|
||||
|
||||
// --- Lydien I-II-vii (en C lydien) ----------------------------------
|
||||
~progLydien = [ [60, 64, 67], [62, 66, 69], [71, 74, 77] ];
|
||||
|
||||
// --- Dorien (i-IV en D dorien) --------------------------------------
|
||||
~progDorien = [ [62, 65, 69], [67, 71, 74] ];
|
||||
|
||||
// --- Hungarian minor (Am avec quartes augmentees -- D#) -------------
|
||||
~progHungar = [ [57, 60, 64], [62, 65, 68], [55, 58, 62], [57, 60, 64] ];
|
||||
|
||||
// --- Hijaz Arabic I-bII-iii-IV (en C hijaz) -------------------------
|
||||
~progHijaz = [ [60, 61, 64], [61, 64, 68], [64, 67, 71], [65, 69, 72] ];
|
||||
|
||||
// --- Vietnamese pentatonique (oan : C-Db-F-G-Ab) --------------------
|
||||
~progVietnam = [ [60, 65, 67], [61, 65, 68], [60, 67, 72], [60, 65, 67] ];
|
||||
|
||||
// --- Hirajoshi (gamme japonaise : 1-2-b3-5-b6) -----------------------
|
||||
~progHirajoshi = [ [60, 62, 63], [60, 67, 68], [62, 63, 67] ];
|
||||
|
||||
// --- Detroit techno standard i-bIII-bVI-bVII (en Am) ----------------
|
||||
~progDetroit = [ [57, 60, 64], [60, 63, 67], [65, 69, 72], [67, 71, 74] ];
|
||||
|
||||
// --- Trance i-VI-VII-i (en Am) --------------------------------------
|
||||
~progTrance = [ [57, 60, 64], [65, 69, 72], [67, 71, 74], [57, 60, 64] ];
|
||||
|
||||
// --- Drum'n'bass 2 chord vamp (Em-Cmaj7) -----------------------------
|
||||
~progDnB = [ [64, 67, 71], [60, 64, 67, 71] ];
|
||||
|
||||
// --- Dubstep wobble bass (1 accord drone Cm) ------------------------
|
||||
~progDubstep = [ [48, 51, 55] ];
|
||||
|
||||
// --- Synthwave I-V-vi-iii (en C) ------------------------------------
|
||||
~progSynthwave = [ [60, 64, 67], [67, 71, 74], [69, 72, 76], [64, 67, 71] ];
|
||||
|
||||
// --- Ambient drone (cluster Cmaj7add9) -------------------------------
|
||||
~progAmbient = [ [60, 62, 64, 67, 71] ];
|
||||
|
||||
"=== Progressions tabulaires (~progXxx) chargees ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ===== PROGRESSIONS AUTO-APPLICANTES (~melodyNotes 32 steps) ======
|
||||
// =====================================================================
|
||||
|
||||
// --- Jazz ii-V-I (Dm7-G7-Cmaj7) -- 8 steps par accord ---------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
62, 0, 65, 0, 69, 0, 72, 0,
|
||||
55, 0, 59, 0, 62, 0, 65, 0,
|
||||
60, 0, 64, 0, 67, 0, 71, 0,
|
||||
60, 0, 64, 0, 67, 0, 71, 0
|
||||
];
|
||||
~reload.value; "jazz ii-V-I".postln;
|
||||
)
|
||||
|
||||
// --- Rock/Blues I-IV-V (C-F-G) -------------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 64, 0, 67, 0, 60, 0,
|
||||
65, 0, 69, 0, 72, 0, 65, 0,
|
||||
67, 0, 71, 0, 74, 0, 67, 0,
|
||||
60, 0, 64, 0, 67, 0, 60, 0
|
||||
];
|
||||
~reload.value; "rock blues I-IV-V".postln;
|
||||
)
|
||||
|
||||
// --- Pop I-V-vi-IV (C-G-Am-F) -- "axis of awesome" -----------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 64, 0, 67, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0,
|
||||
60, 0, 64, 0, 67, 0, 60, 0,
|
||||
65, 0, 69, 0, 72, 0, 65, 0,
|
||||
67, 0, 71, 0, 74, 0, 67, 0,
|
||||
60, 0, 64, 0, 67, 0, 60, 0,
|
||||
69, 0, 72, 0, 76, 0, 0, 0,
|
||||
65, 0, 69, 0, 72, 0, 0, 0,
|
||||
69, 0, 72, 0, 76, 0, 0, 0,
|
||||
65, 0, 69, 0, 72, 0, 0, 0,
|
||||
60, 0, 64, 0, 67, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0,
|
||||
60, 0, 64, 0, 67, 0, 60, 0,
|
||||
65, 0, 69, 0, 72, 0, 65, 0,
|
||||
67, 0, 71, 0, 74, 0, 67, 0,
|
||||
60, 0, 64, 0, 67, 0, 60, 0
|
||||
];
|
||||
~reload.value; "pop I-V-vi-IV".postln;
|
||||
)
|
||||
|
||||
// --- Sad pop vi-IV-I-V (Am-F-C-G) ----------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
69, 0, 72, 0, 76, 0, 0, 0,
|
||||
65, 0, 69, 0, 72, 0, 0, 0,
|
||||
60, 0, 64, 0, 67, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0
|
||||
];
|
||||
~reload.value; "sad pop vi-IV-I-V".postln;
|
||||
)
|
||||
|
||||
// --- Epique mineur i-iv-VII-III (Am-Dm-G-C) ------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 64, 0, 0, 0,
|
||||
62, 0, 65, 0, 69, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0,
|
||||
64, 0, 67, 0, 71, 0, 0, 0
|
||||
];
|
||||
~reload.value; "epique mineur i-iv-VII-III".postln;
|
||||
)
|
||||
|
||||
// --- Andalouse i-VI-III-VII (Am-F-C-G) -----------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 64, 0, 0, 0,
|
||||
65, 0, 69, 0, 72, 0, 0, 0,
|
||||
60, 0, 64, 0, 67, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0
|
||||
];
|
||||
~reload.value; "andalouse i-VI-III-VII".postln;
|
||||
)
|
||||
|
||||
// --- Rock mineur i-bVII-bVI-bVII (Am-G-F-G) ------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 64, 0, 0, 0,
|
||||
55, 0, 59, 0, 62, 0, 0, 0,
|
||||
53, 0, 57, 0, 60, 0, 0, 0,
|
||||
55, 0, 59, 0, 62, 0, 0, 0
|
||||
];
|
||||
~reload.value; "rock mineur i-bVII-bVI-bVII".postln;
|
||||
)
|
||||
|
||||
// --- Flamenco i-bVII-bVI-V (Am-G-F-E) ------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 64, 0, 0, 0,
|
||||
55, 0, 59, 0, 62, 0, 0, 0,
|
||||
53, 0, 57, 0, 60, 0, 0, 0,
|
||||
52, 0, 56, 0, 59, 0, 0, 0
|
||||
];
|
||||
~reload.value; "flamenco i-bVII-bVI-V".postln;
|
||||
)
|
||||
|
||||
// --- Jazz turn-around I-vi-ii-V (C-Am-Dm-G7) -----------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 64, 0, 67, 0, 71, 0,
|
||||
69, 0, 72, 0, 76, 0, 79, 0,
|
||||
62, 0, 65, 0, 69, 0, 72, 0,
|
||||
55, 0, 59, 0, 62, 0, 65, 0
|
||||
];
|
||||
~reload.value; "jazz turn-around I-vi-ii-V".postln;
|
||||
)
|
||||
|
||||
// --- Modal interchange (C-Eb-Ab-Bb -- emprunts mineur naturel) -----
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 64, 0, 67, 0, 0, 0,
|
||||
63, 0, 67, 0, 70, 0, 0, 0,
|
||||
68, 0, 72, 0, 75, 0, 0, 0,
|
||||
70, 0, 74, 0, 77, 0, 0, 0
|
||||
];
|
||||
~reload.value; "modal interchange bIII-bVI-bVII".postln;
|
||||
)
|
||||
|
||||
// --- Tritone subst (Dm7-Db7-Cmaj7) ---------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
62, 0, 65, 0, 69, 0, 72, 0,
|
||||
62, 0, 65, 0, 69, 0, 72, 0,
|
||||
49, 0, 53, 0, 56, 0, 59, 0,
|
||||
60, 0, 64, 0, 67, 0, 71, 0
|
||||
];
|
||||
~reload.value; "tritone substitution".postln;
|
||||
)
|
||||
|
||||
// --- Minor 7th progression (Cm7-Fm7-Bb7-Ebmaj7) --------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 63, 0, 67, 0, 70, 0,
|
||||
65, 0, 68, 0, 72, 0, 75, 0,
|
||||
58, 0, 62, 0, 65, 0, 68, 0,
|
||||
63, 0, 67, 0, 70, 0, 74, 0
|
||||
];
|
||||
~reload.value; "minor 7th progression".postln;
|
||||
)
|
||||
|
||||
// --- Coltrane changes (B-Eb-G augmente classique Giant Steps) ------
|
||||
(
|
||||
~melodyNotes = [
|
||||
59, 63, 66, 0, 50, 54, 57, 0,
|
||||
55, 59, 62, 0, 51, 55, 58, 0,
|
||||
54, 58, 61, 0, 59, 63, 66, 0,
|
||||
55, 59, 62, 0, 60, 64, 67, 0
|
||||
];
|
||||
~reload.value; "Coltrane changes".postln;
|
||||
)
|
||||
|
||||
// --- Phrygien i-bII-bVII-bVI (E-F-D-C en E phrygien) ---------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
52, 0, 55, 0, 59, 0, 0, 0,
|
||||
53, 0, 56, 0, 60, 0, 0, 0,
|
||||
50, 0, 53, 0, 57, 0, 0, 0,
|
||||
48, 0, 51, 0, 55, 0, 0, 0
|
||||
];
|
||||
~reload.value; "phrygien i-bII-bVII-bVI".postln;
|
||||
)
|
||||
|
||||
// --- Lydien I-II-vii (C-D-Bm en C lydien) --------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 64, 0, 67, 0, 0, 0,
|
||||
62, 0, 66, 0, 69, 0, 0, 0,
|
||||
71, 0, 74, 0, 77, 0, 0, 0,
|
||||
60, 0, 64, 0, 67, 0, 0, 0
|
||||
];
|
||||
~reload.value; "lydien I-II-vii".postln;
|
||||
)
|
||||
|
||||
// --- Dorien (i-IV en D dorien : Dm-G) ------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
62, 0, 65, 0, 69, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0,
|
||||
62, 0, 65, 0, 69, 0, 0, 0,
|
||||
67, 0, 71, 0, 74, 0, 0, 0
|
||||
];
|
||||
~reload.value; "dorien i-IV".postln;
|
||||
)
|
||||
|
||||
// --- Hungarian minor (Am avec D# quarte aug) -----------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
57, 0, 60, 0, 63, 0, 66, 0, // Am avec note hongroise
|
||||
62, 0, 65, 0, 68, 0, 0, 0,
|
||||
55, 0, 58, 0, 62, 0, 0, 0,
|
||||
57, 0, 60, 0, 64, 0, 0, 0
|
||||
];
|
||||
~reload.value; "hungarian minor".postln;
|
||||
)
|
||||
|
||||
// --- Hijaz Arabic I-bII-iii-IV (C-Db-Em-F) -------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 61, 0, 64, 0, 0, 0,
|
||||
61, 0, 64, 0, 68, 0, 0, 0,
|
||||
64, 0, 67, 0, 71, 0, 0, 0,
|
||||
65, 0, 69, 0, 72, 0, 0, 0
|
||||
];
|
||||
~reload.value; "hijaz arabic I-bII-iii-IV".postln;
|
||||
)
|
||||
|
||||
// --- Vietnamese pentatonique oan ------------------------------------
|
||||
(
|
||||
~melodyNotes = [
|
||||
60, 0, 65, 0, 67, 0, 0, 0,
|
||||
61, 0, 65, 0, 68, 0, 0, 0,
|
||||
60, 0, 67, 0, 72, 0, 0, 0,
|
||||
65, 0, 67, 0, 60, 0, 0, 0
|
||||
];
|
||||
~reload.value; "vietnamese pentatonique".postln;
|
||||
)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// =====================================================================
|
||||
// fx.scd
|
||||
// FX oneshot : riser / sweep / impact / crash / vinyl
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur un bloc pour l'appliquer.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
|
||||
( Synth(\riser, [\dur, 4, \startCutoff, 200, \endCutoff, 8000, \amp, 0.25]); )
|
||||
( Synth(\riser, [\dur, 8, \startCutoff, 300, \endCutoff, 10000, \amp, 0.30]); )
|
||||
( Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.35]); )
|
||||
|
||||
( Synth(\sweep, [\dur, 4, \startCutoff, 8000, \endCutoff, 200, \amp, 0.25]); )
|
||||
|
||||
( Synth(\impact, [\freq, 45, \decay, 1.5, \amp, 0.7]); )
|
||||
( Synth(\impact, [\freq, 35, \decay, 2.5, \amp, 0.8]); )
|
||||
|
||||
( Synth(\crash, [\decay, 2.0, \amp, 0.3]); )
|
||||
( Synth(\crash, [\decay, 4.0, \amp, 0.4]); )
|
||||
|
||||
( ~vinyl !? { ~vinyl.free }; ~vinyl = Synth(\vinyl, [\amp, 0.05]); "vinyl ON".postln; )
|
||||
( ~vinyl !? { ~vinyl.free; ~vinyl = nil }; "vinyl OFF".postln; )
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// =====================================================================
|
||||
// fx_genre.scd -- FX signature par genre
|
||||
// (combinaisons riser+impact+sweep+gong+scratch)
|
||||
//
|
||||
// Chaque preset = une transition prete a l'emploi.
|
||||
// Cmd+Entree pour declencher.
|
||||
// =====================================================================
|
||||
|
||||
// --- TRANCE BUILD-UP -- snare roll + riser long + impact ---------
|
||||
(
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.35]);
|
||||
~snareFill.(32, 16, 0.2, 0.55);
|
||||
fork {
|
||||
16.wait;
|
||||
Synth(\impact, [\freq, 35, \decay, 3, \amp, 0.7]);
|
||||
Synth(\crash, [\decay, 4, \amp, 0.4]);
|
||||
};
|
||||
"=== TRANCE BUILD 16s ===".postln;
|
||||
)
|
||||
|
||||
// --- DUBSTEP DROP -- impact + crash + riser court -----------------
|
||||
(
|
||||
Synth(\riser, [\dur, 4, \startCutoff, 500, \endCutoff, 11000, \amp, 0.4]);
|
||||
fork {
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 30, \decay, 3.5, \amp, 0.85]);
|
||||
Synth(\crash, [\decay, 3, \amp, 0.5]);
|
||||
};
|
||||
"=== DUBSTEP DROP 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- HARDCORE GABBER DROP -- impact massif + double crash --------
|
||||
(
|
||||
Synth(\impact, [\freq, 25, \decay, 4, \amp, 0.9]);
|
||||
Synth(\crash, [\decay, 5, \amp, 0.6]);
|
||||
fork { 0.5.wait; Synth(\crash, [\decay, 3, \amp, 0.4]); };
|
||||
"=== HARDCORE DROP ===".postln;
|
||||
)
|
||||
|
||||
// --- DnB BUILD -- snare roll accelerando + drop --------------------
|
||||
(
|
||||
~snareFill.(16, 4, 0.3, 0.6);
|
||||
fork {
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 40, \decay, 2.5, \amp, 0.65]);
|
||||
};
|
||||
"=== DnB BUILD 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- ASIAN CINEMATIC FX -- gong cascade ---------------------------
|
||||
(
|
||||
[40, 50, 60, 70].do { |f, i|
|
||||
fork { (i * 0.8).wait; Synth(\gong, [\freq, f, \decay, 8 - (i * 0.5), \amp, 0.45]); };
|
||||
};
|
||||
"=== GONG CASCADE 3s ===".postln;
|
||||
)
|
||||
|
||||
// --- DUB TECHNO ECHO -- clap dub avec delay ------------------------
|
||||
(
|
||||
fork {
|
||||
5.do { |i|
|
||||
Synth(\clap, [\amp, 0.4 - (i * 0.06), \decay, 0.3]);
|
||||
0.4.wait;
|
||||
};
|
||||
};
|
||||
"=== DUB ECHO CLAP ===".postln;
|
||||
)
|
||||
|
||||
// --- DETROIT FILTER SWEEP DOWN ------------------------------------
|
||||
( Synth(\sweep, [\dur, 8, \startCutoff, 12000, \endCutoff, 200, \amp, 0.35]); )
|
||||
|
||||
// --- INDUSTRIAL TENSION -- sweep slow + drone --------------------
|
||||
(
|
||||
Synth(\sweep, [\dur, 16, \startCutoff, 8000, \endCutoff, 100, \amp, 0.4]);
|
||||
~vinyl !? { ~vinyl.free };
|
||||
~vinyl = Synth(\vinyl, [\amp, 0.12]);
|
||||
fork { 16.wait; ~vinyl !? { ~vinyl.free }; };
|
||||
"=== INDUSTRIAL TENSION 16s ===".postln;
|
||||
)
|
||||
|
||||
// --- GLITCH IDM -- scratch + impacts random --------------------
|
||||
(
|
||||
fork {
|
||||
8.do {
|
||||
if (0.6.coin) { Synth(\scratch, [\dur, rrand(0.1, 0.4), \freq, rrand(400, 2000), \sweepDir, [-1, 1].choose, \amp, 0.3]) };
|
||||
if (0.3.coin) { Synth(\impact, [\freq, rrand(40, 80), \decay, rrand(0.5, 1.5), \amp, 0.4]) };
|
||||
rrand(0.15, 0.5).wait;
|
||||
};
|
||||
};
|
||||
"=== GLITCH 8 hits 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- VOCAL TRANCE SWELL -- riser + crash + impact ----------------
|
||||
(
|
||||
Synth(\riser, [\dur, 12, \startCutoff, 600, \endCutoff, 13000, \amp, 0.4]);
|
||||
fork {
|
||||
12.wait;
|
||||
Synth(\impact, [\freq, 38, \decay, 3, \amp, 0.7]);
|
||||
Synth(\crash, [\decay, 5, \amp, 0.45]);
|
||||
};
|
||||
"=== VOCAL TRANCE SWELL 12s ===".postln;
|
||||
)
|
||||
|
||||
// --- TRIBAL TOM ROLL DESCENDANT ----------------------------------
|
||||
(
|
||||
[180, 140, 110, 85, 70, 55, 40].do { |f, i|
|
||||
fork { (i * 0.12).wait; Synth(\taiko, [\freq, f, \decay, 0.6, \amp, 0.5]); };
|
||||
};
|
||||
"=== TRIBAL TOM ROLL ===".postln;
|
||||
)
|
||||
|
||||
// --- DRONE DOOM -- gong tres profond + reverb infinie ------------
|
||||
(
|
||||
Synth(\gong, [\freq, 25, \decay, 30, \amp, 0.95]);
|
||||
fork { 5.wait; Synth(\gong, [\freq, 30, \decay, 25, \amp, 0.7]); };
|
||||
"=== DRONE DOOM gong massif 30s ===".postln;
|
||||
)
|
||||
|
||||
// --- HARDSTYLE BUILD -- kick reverse + snare roll + impact -----
|
||||
(
|
||||
Synth(\sweep, [\dur, 4, \startCutoff, 200, \endCutoff, 8000, \amp, 0.45]);
|
||||
fork {
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 30, \decay, 3.5, \amp, 0.85]);
|
||||
Synth(\kickGabber, [\amp, 0.7]);
|
||||
};
|
||||
"=== HARDSTYLE BUILD 4s ===".postln;
|
||||
)
|
||||
|
||||
// --- PHONK -- vinyl + cowbell + 808 sub --------------------------
|
||||
(
|
||||
~vinyl !? { ~vinyl.free };
|
||||
~vinyl = Synth(\vinyl, [\amp, 0.15]);
|
||||
fork {
|
||||
4.do {
|
||||
Synth(\cowbell, [\freq, 800, \decay, 0.2, \amp, 0.4]);
|
||||
0.5.wait;
|
||||
};
|
||||
Synth(\kick808, [\freq, 35, \decay, 1.2, \amp, 0.7]);
|
||||
};
|
||||
"=== PHONK VINYL 2.5s ===".postln;
|
||||
)
|
||||
|
||||
// --- FUTURE GARAGE -- vocal-like swell + sub ---------------------
|
||||
(
|
||||
Synth(\sweep, [\dur, 6, \startCutoff, 6000, \endCutoff, 800, \amp, 0.3]);
|
||||
fork { 5.wait; Synth(\impact, [\freq, 40, \decay, 2.5, \amp, 0.55]); };
|
||||
"=== FUTURE GARAGE SWELL 6s ===".postln;
|
||||
)
|
||||
|
||||
// --- SCRATCH FX -- 4 scratches rapides ---------------------------
|
||||
(
|
||||
4.do { |i|
|
||||
fork {
|
||||
(i * 0.15).wait;
|
||||
Synth(\scratch, [\dur, 0.2, \freq, 800 + (i * 200), \sweepDir, [-1, 1].choose, \amp, 0.4]);
|
||||
};
|
||||
};
|
||||
"=== SCRATCH x4 ===".postln;
|
||||
)
|
||||
|
||||
// --- GLITCH STUTTER -- impacts rapides ---------------------------
|
||||
(
|
||||
fork {
|
||||
16.do { |i|
|
||||
Synth(\impact, [\freq, rrand(35, 60), \decay, 0.15, \amp, 0.4]);
|
||||
rrand(0.06, 0.15).wait;
|
||||
};
|
||||
};
|
||||
"=== GLITCH STUTTER 2s ===".postln;
|
||||
)
|
||||
|
||||
// --- ASIAN MELODIC FILL (guzheng arpege descendant) -------------
|
||||
(
|
||||
[79, 77, 75, 72, 70, 67, 65, 63, 60].do { |n, i|
|
||||
fork {
|
||||
(i * 0.15).wait;
|
||||
Synth(\guzheng, [\freq, n.midicps, \amp, 0.18, \release, 1.0]);
|
||||
};
|
||||
};
|
||||
"=== ASIAN GUZHENG FILL ===".postln;
|
||||
)
|
||||
|
||||
// --- DROP CUT -- coupe tout brutalement + impact 2s plus tard ----
|
||||
(
|
||||
Routine({
|
||||
var oldKick = ~kickAmp; var oldHat = ~hatAmp; var oldClap = ~clapAmp;
|
||||
~kickAmp = 0; ~hatAmp = 0; ~clapAmp = 0; ~reload.value;
|
||||
Synth(\sweep, [\dur, 2, \startCutoff, 8000, \endCutoff, 200, \amp, 0.4]);
|
||||
2.wait;
|
||||
Synth(\impact, [\freq, 30, \decay, 3, \amp, 0.85]);
|
||||
Synth(\crash, [\decay, 3, \amp, 0.4]);
|
||||
~kickAmp = oldKick; ~hatAmp = oldHat; ~clapAmp = oldClap; ~reload.value;
|
||||
}).play;
|
||||
"=== DROP CUT 2s ===".postln;
|
||||
)
|
||||
|
||||
// --- VINYL ON / OFF ----------------------------------------------
|
||||
(~vinyl !? { ~vinyl.free }; ~vinyl = Synth(\vinyl, [\amp, 0.10]); "vinyl ON".postln;)
|
||||
(~vinyl !? { ~vinyl.free; ~vinyl = nil }; "vinyl OFF".postln;)
|
||||
@@ -0,0 +1,70 @@
|
||||
// =====================================================================
|
||||
// palette/harmonics/helpers.scd
|
||||
// Helpers de generation harmonique a partir d'une melodie source.
|
||||
//
|
||||
// ~genThirdHarmony tierce sup au-dessus
|
||||
// ~genFifthHarmony quinte sup au-dessus
|
||||
// ~genCounterMelody contre-melodie inversee autour d'un pivot
|
||||
// ~genArpFromChords arpege sur progression d'accords
|
||||
// ~genBassFromMelody bassline 2 octaves sous la melodie
|
||||
// ~genOctaveHarmony octave sup
|
||||
// ~genSixthHarmony sixte mineure (3 demi-tons sous l'octave)
|
||||
//
|
||||
// Source unique pour ces helpers d'harmonisation (un seul bloc
|
||||
// top-level, compatible .load).
|
||||
// =====================================================================
|
||||
(
|
||||
// --- Tierce harmonisee (3M par defaut) ------------------------------
|
||||
~genThirdHarmony = { |melody, semitones = 4|
|
||||
melody.collect { |n| if (n > 0) { n + semitones } { 0 } };
|
||||
};
|
||||
|
||||
// --- Quinte harmonisee ----------------------------------------------
|
||||
~genFifthHarmony = { |melody|
|
||||
melody.collect { |n| if (n > 0) { n + 7 } { 0 } };
|
||||
};
|
||||
|
||||
// --- Sixte mineure / harmonisation douce ----------------------------
|
||||
~genSixthHarmony = { |melody|
|
||||
melody.collect { |n| if (n > 0) { n + 9 } { 0 } };
|
||||
};
|
||||
|
||||
// --- Octave haute (layer trance) ------------------------------------
|
||||
~genOctaveHarmony = { |melody, octaves = 1|
|
||||
melody.collect { |n| if (n > 0) { n + (12 * octaves) } { 0 } };
|
||||
};
|
||||
|
||||
// --- Counter-melody (inverse autour d'un pivot) --------------------
|
||||
~genCounterMelody = { |melody, rootInversion = 132|
|
||||
melody.collect { |n|
|
||||
if (n > 0) { (rootInversion - n).max(36).min(96) } { 0 };
|
||||
};
|
||||
};
|
||||
|
||||
// --- Bassline -- 2 octaves sous la melodie --------------------------
|
||||
~genBassFromMelody = { |melody, octavesDown = 2|
|
||||
melody.collect { |n|
|
||||
if (n > 0) { (n - (12 * octavesDown)).max(24) } { 0 };
|
||||
};
|
||||
};
|
||||
|
||||
// --- Arpege sur progression d'accords -------------------------------
|
||||
// ~genArpFromChords.([root list], [chord shape], steps_par_accord, octaves)
|
||||
~genArpFromChords = { |roots, shape, stepsPerChord = 8, octRange = 1|
|
||||
var notes = List.new;
|
||||
var sh = shape ?? { [0, 3, 7, 10] }; // defaut : minor 7
|
||||
roots.do { |r|
|
||||
stepsPerChord.do { |i|
|
||||
var chord = sh.collect(_ + r);
|
||||
chord = chord ++ chord.collect(_ + 12);
|
||||
if (octRange > 1) {
|
||||
chord = chord ++ chord.collect(_ + 12);
|
||||
};
|
||||
notes.add(chord.choose);
|
||||
};
|
||||
};
|
||||
notes.asArray;
|
||||
};
|
||||
|
||||
"[harmonics/helpers] genThirdHarmony / genFifthHarmony / genSixthHarmony / genOctaveHarmony / genCounterMelody / genBassFromMelody / genArpFromChords prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
// =====================================================================
|
||||
// palette/harmonics/index.scd -- loader du module harmonics
|
||||
//
|
||||
// Charge :
|
||||
// helpers.scd genThirdHarmony / genFifthHarmony / genCounter / ...
|
||||
// presets.scd ~enableHarmony.(\preset) (10 presets)
|
||||
//
|
||||
// Usage : (~base ++ "palette/harmonics/index.scd").load;
|
||||
// Un seul bloc top-level (compatible .load depuis 00_load.scd).
|
||||
// =====================================================================
|
||||
(
|
||||
var dir = thisProcess.nowExecutingPath.dirname;
|
||||
(dir +/+ "helpers.scd").load;
|
||||
(dir +/+ "presets.scd").load;
|
||||
"=== harmonics module loaded ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,104 @@
|
||||
// =====================================================================
|
||||
// palette/harmonics/presets.scd
|
||||
// ~enableHarmony.(\preset) -- 10 presets pour la 2e voix harmonique.
|
||||
//
|
||||
// Presets : \off, \counter, \third, \fifth, \bassline, \arp, \chord,
|
||||
// \tranceLayer, \dubBass, \cinematic
|
||||
//
|
||||
// Source unique de ~enableHarmony (engine.scd ne le definit plus).
|
||||
// Charge par index.scd. Un seul bloc top-level (compatible .load).
|
||||
//
|
||||
// PREREQUIS : ~melodyNotes, ~reload definis (engine.scd evalue).
|
||||
// =====================================================================
|
||||
(
|
||||
~enableHarmony = { |preset = \off|
|
||||
switch (preset,
|
||||
\off, {
|
||||
~harmonyAmp = 0;
|
||||
},
|
||||
// Counter-melody : inverse de la melodie principale
|
||||
\counter, {
|
||||
~harmonyInst = \pluck;
|
||||
~harmonyAttack = 0.005; ~harmonyRelease = 0.4;
|
||||
~harmonyCutoff = 4500; ~harmonyAmp = 0.13;
|
||||
~harmonyDur = 0.25;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n|
|
||||
if (n > 0) { (132 - n).max(48).min(96) } { 0 };
|
||||
};
|
||||
},
|
||||
// Tierce harmonisee
|
||||
\third, {
|
||||
~harmonyInst = \warmPad;
|
||||
~harmonyAttack = 0.3; ~harmonyRelease = 1.2;
|
||||
~harmonyCutoff = 2500; ~harmonyAmp = 0.12;
|
||||
~harmonyDur = 0.25;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n| if(n > 0) {n + 4} {0} };
|
||||
},
|
||||
// Quinte harmonisee
|
||||
\fifth, {
|
||||
~harmonyInst = \warmPad;
|
||||
~harmonyAttack = 0.3; ~harmonyRelease = 1.2;
|
||||
~harmonyCutoff = 2500; ~harmonyAmp = 0.12;
|
||||
~harmonyDur = 0.25;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n| if(n > 0) {n + 7} {0} };
|
||||
},
|
||||
// Bassline 2 octaves sous la melodie
|
||||
\bassline, {
|
||||
~harmonyInst = \subBoom;
|
||||
~harmonyAttack = 0.005; ~harmonyRelease = 0.6;
|
||||
~harmonyAmp = 0.30;
|
||||
~harmonyDur = 0.5;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n|
|
||||
if (n > 0) { (n - 24).max(24) } { 0 };
|
||||
};
|
||||
},
|
||||
// Arpege rapide en 1/32 sur les memes notes
|
||||
\arp, {
|
||||
~harmonyInst = \pluck;
|
||||
~harmonyAttack = 0.001; ~harmonyRelease = 0.2;
|
||||
~harmonyCutoff = 5500; ~harmonyAmp = 0.13;
|
||||
~harmonyDur = 0.125;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n|
|
||||
if (n > 0) { n + 12 } { 0 };
|
||||
};
|
||||
},
|
||||
// Chord stabs (quinte sup avec dur plus lente)
|
||||
\chord, {
|
||||
~harmonyInst = \warmPad;
|
||||
~harmonyAttack = 0.05; ~harmonyRelease = 1.5;
|
||||
~harmonyCutoff = 2200; ~harmonyAmp = 0.13;
|
||||
~harmonyDur = 0.5;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n| if(n > 0) {n + 7} {0} };
|
||||
},
|
||||
// Layer trance : organLead octave +1
|
||||
\tranceLayer, {
|
||||
~harmonyInst = \organLead;
|
||||
~harmonyAttack = 0.005; ~harmonyRelease = 0.2;
|
||||
~harmonyCutoff = 5000; ~harmonyAmp = 0.12;
|
||||
~harmonyDur = 0.25;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n| if(n > 0) {n + 12} {0} };
|
||||
},
|
||||
// Dub bass : sub avec long sustain
|
||||
\dubBass, {
|
||||
~harmonyInst = \subBoom;
|
||||
~harmonyAttack = 0.01; ~harmonyRelease = 1.0;
|
||||
~harmonyAmp = 0.32;
|
||||
~harmonyDur = 1.0;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n|
|
||||
if (n > 0) { (n - 24).max(24) } { 0 };
|
||||
};
|
||||
},
|
||||
// Cinematic strings layer
|
||||
\cinematic, {
|
||||
~harmonyInst = \strings;
|
||||
~harmonyAttack = 0.4; ~harmonyRelease = 1.5;
|
||||
~harmonyCutoff = 3500; ~harmonyAmp = 0.14;
|
||||
~harmonyDur = 0.5;
|
||||
~harmonyNotes = ~melodyNotes.collect { |n| if(n > 0) {n + 7} {0} };
|
||||
}
|
||||
);
|
||||
~reload.value;
|
||||
};
|
||||
|
||||
"[harmonics/presets] ~enableHarmony pret (10 presets : off counter third fifth bassline arp chord tranceLayer dubBass cinematic)".postln;
|
||||
)
|
||||
@@ -0,0 +1,102 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/bank.scd
|
||||
// Bibliotheque par genre (~melodyBank) + selecteurs aleatoires.
|
||||
//
|
||||
// ~melodyBank dictionnaire genre -> [\m1, \ml3, ...]
|
||||
// ~useMelody.(\m50) applique une melodie nommee a ~melodyNotes
|
||||
// ~melodyByGenre.(\acid)
|
||||
// ~randomLong.() ml aleatoire (64 pas)
|
||||
// ~randomXLong.() mxl aleatoire (96 pas)
|
||||
// ~randomEpic.() mepic aleatoire(128 pas)
|
||||
//
|
||||
// Le bank stocke des SYMBOLES, l'evaluation lit currentEnvironment a
|
||||
// la volee : si l'utilisateur reevalue ~m29, le selecteur utilise
|
||||
// toujours la version a jour. Charge par index.scd. Un seul bloc.
|
||||
// =====================================================================
|
||||
(
|
||||
~melodyBank = (
|
||||
\acid: [\m29, \m30, \m70, \ml1, \mxl5, \mepic5],
|
||||
\dub: [\m65, \ml26],
|
||||
\trance: [\m8, \m24, \m28, \ml2, \mxl1, \mepic1, \mxl15, \mepic6, \ml15],
|
||||
\detroit: [\m3, \m23, \m69, \m71, \ml3, \ml18, \mxl2, \mepic3],
|
||||
\dnb: [\m63, \ml4, \ml22],
|
||||
\ambient: [\m33, \m34, \m72, \m73, \ml5, \mxl3],
|
||||
\world: [\m17, \m48, \m74, \ml9, \ml25, \mxl11, \mepic9],
|
||||
\retro: [\m61, \m75, \m77, \ml7, \ml13, \mxl6],
|
||||
\dark: [\m14, \m38, \m53, \ml8, \ml28, \mxl8, \mepic8],
|
||||
\asian: [\m17, \m40, \m48, \m74, \ml9, \ml25, \mxl11, \mepic9],
|
||||
\oriental: [\m15, \m20, \m39, \m41, \m44, \m60, \ml6, \ml17, \mxl4, \mxl14, \mepic4],
|
||||
\tribal: [\m45, \m46, \ml10, \mxl12],
|
||||
\industrial: [\m67, \m68, \ml11, \ml24, \mxl9, \mepic7],
|
||||
\synthwave: [\m61, \ml7, \mxl6],
|
||||
\chiptune: [\m62, \ml20, \mxl13],
|
||||
\phonk: [\m66, \ml19],
|
||||
\hardcore: [\m67, \ml24, \mxl9, \mepic7],
|
||||
\pop: [\m35, \m36, \m49, \m50, \ml14, \mxl10],
|
||||
\jazz: [\m51, \m52, \ml16, \ml27],
|
||||
\blues: [\m16, \m47],
|
||||
\hypnotic: [\m2, \m11, \m27, \m54, \m55, \m56, \ml12, \mxl7],
|
||||
\pad: [\m33, \m34, \ml5, \mxl3],
|
||||
\pluck: [\m32],
|
||||
\sub: [\m5, \m31, \m37, \m63, \ml4],
|
||||
\drone: [\m37, \m38],
|
||||
\tension: [\m53, \m59, \ml28, \m58, \ml30],
|
||||
\chromatic: [\m57, \ml29],
|
||||
\cinematic: [\m73, \mxl3, \mepic2, \mepic10]
|
||||
);
|
||||
|
||||
// ---------- Selecteurs ----------------------------------------------
|
||||
~useMelody = { |name|
|
||||
var notes = currentEnvironment[name];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
~melodyNotes = notes.copy;
|
||||
~reload.value;
|
||||
("useMelody : " ++ name).postln;
|
||||
} {
|
||||
("useMelody : " ++ name ++ " inconnue").postln;
|
||||
};
|
||||
};
|
||||
|
||||
~randomLong = {
|
||||
var key = (1..30).collect { |i| ("ml" ++ i).asSymbol }.choose;
|
||||
var notes = currentEnvironment[key];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
~melodyNotes = notes.copy; ~reload.value;
|
||||
("randomLong : " ++ key).postln;
|
||||
} { ("randomLong : " ++ key ++ " inconnue").postln };
|
||||
};
|
||||
|
||||
~randomXLong = {
|
||||
var key = (1..15).collect { |i| ("mxl" ++ i).asSymbol }.choose;
|
||||
var notes = currentEnvironment[key];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
~melodyNotes = notes.copy; ~reload.value;
|
||||
("randomXLong : " ++ key).postln;
|
||||
} { ("randomXLong : " ++ key ++ " inconnue").postln };
|
||||
};
|
||||
|
||||
~randomEpic = {
|
||||
var key = (1..10).collect { |i| ("mepic" ++ i).asSymbol }.choose;
|
||||
var notes = currentEnvironment[key];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
~melodyNotes = notes.copy; ~reload.value;
|
||||
("randomEpic : " ++ key).postln;
|
||||
} { ("randomEpic : " ++ key ++ " inconnue").postln };
|
||||
};
|
||||
|
||||
~melodyByGenre = { |genre|
|
||||
var pool = ~melodyBank[genre];
|
||||
if (pool.notNil and: { pool.size > 0 }) {
|
||||
var key = pool.choose;
|
||||
var notes = currentEnvironment[key];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
~melodyNotes = notes.copy; ~reload.value;
|
||||
("melodyByGenre : " ++ genre ++ " -> " ++ key).postln;
|
||||
} { ("melodyByGenre : " ++ key ++ " inconnue (defini ?)").postln };
|
||||
} {
|
||||
("melodyByGenre : " ++ genre ++ " inconnu ou vide").postln;
|
||||
};
|
||||
};
|
||||
|
||||
"[melodies/bank] melodyBank + useMelody/randomLong/randomXLong/randomEpic/melodyByGenre prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,119 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/epic.scd
|
||||
// ~mepic1..~mepic10 -- 10 patterns melodiques de 128 pas (8 mesures)
|
||||
//
|
||||
// Charge par palette/melodies/index.scd. Un seul bloc top-level.
|
||||
// =====================================================================
|
||||
(
|
||||
~mepic1 = [
|
||||
60, 0, 0, 0, 67, 0, 0, 0, 72, 0, 0, 0, 70, 0, 0, 0,
|
||||
60, 0, 0, 0, 67, 0, 70, 0, 72, 0, 75, 0, 72, 0, 70, 67,
|
||||
60, 67, 72, 67, 65, 67, 70, 72, 75, 72, 70, 67, 70, 72, 75, 79,
|
||||
60, 67, 72, 75, 72, 67, 60, 67, 65, 72, 77, 79, 77, 72, 65, 72,
|
||||
79, 77, 75, 72, 79, 77, 75, 72, 82, 79, 77, 75, 84, 82, 79, 77,
|
||||
84, 82, 79, 77, 84, 82, 79, 84, 87, 84, 82, 79, 89, 87, 84, 82,
|
||||
79, 0, 77, 0, 75, 0, 72, 0, 70, 0, 67, 0, 65, 0, 63, 0,
|
||||
60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic2 = [
|
||||
60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
60, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
60, 0, 63, 0, 67, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
60, 63, 67, 70, 72, 70, 67, 63, 65, 67, 70, 72, 75, 72, 70, 67,
|
||||
65, 70, 72, 75, 77, 75, 72, 70, 72, 75, 77, 79, 82, 79, 77, 75,
|
||||
72, 75, 77, 79, 82, 79, 77, 79, 84, 82, 79, 77, 79, 82, 84, 87,
|
||||
79, 82, 84, 87, 84, 82, 79, 77, 75, 77, 79, 82, 79, 77, 75, 72,
|
||||
70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic3 = [
|
||||
63, 0, 70, 0, 65, 0, 72, 0, 63, 0, 70, 0, 65, 0, 72, 75,
|
||||
65, 0, 72, 0, 67, 0, 75, 0, 65, 0, 72, 0, 67, 0, 75, 79,
|
||||
63, 70, 65, 72, 67, 75, 70, 77, 72, 79, 75, 82, 77, 84, 79, 86,
|
||||
65, 72, 67, 75, 70, 77, 72, 79, 75, 82, 77, 84, 79, 86, 82, 89,
|
||||
79, 86, 82, 89, 84, 91, 86, 93, 82, 89, 84, 91, 86, 93, 88, 95,
|
||||
84, 0, 82, 0, 79, 0, 77, 0, 75, 0, 72, 0, 70, 0, 67, 0,
|
||||
65, 0, 63, 0, 60, 0, 65, 0, 67, 0, 63, 0, 65, 0, 60, 0,
|
||||
63, 0, 65, 67, 65, 63, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic4 = [
|
||||
60, 61, 0, 64, 65, 0, 67, 68, 71, 0, 68, 67, 65, 64, 0, 61,
|
||||
60, 0, 64, 65, 67, 68, 71, 72, 71, 68, 67, 65, 64, 61, 60, 0,
|
||||
63, 64, 67, 68, 70, 71, 0, 73, 75, 73, 71, 70, 68, 67, 64, 63,
|
||||
60, 61, 64, 65, 67, 68, 71, 72, 75, 72, 71, 68, 67, 64, 61, 60,
|
||||
65, 67, 68, 71, 72, 73, 76, 75, 76, 75, 73, 72, 71, 68, 67, 65,
|
||||
72, 73, 76, 75, 73, 72, 71, 68, 76, 79, 80, 83, 84, 83, 80, 79,
|
||||
79, 80, 83, 84, 87, 84, 83, 80, 76, 75, 73, 72, 71, 68, 67, 65,
|
||||
72, 71, 68, 67, 65, 64, 61, 60, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic5 = [
|
||||
36, 0, 48, 0, 36, 39, 0, 48, 36, 0, 51, 39, 0, 36, 48, 0,
|
||||
36, 0, 48, 51, 36, 39, 48, 51, 39, 0, 36, 48, 0, 39, 0, 36,
|
||||
36, 51, 48, 36, 39, 0, 51, 48, 36, 0, 51, 53, 39, 36, 48, 0,
|
||||
36, 53, 51, 48, 39, 0, 36, 48, 36, 0, 51, 0, 48, 39, 36, 0,
|
||||
39, 0, 51, 0, 39, 41, 0, 51, 39, 0, 53, 41, 0, 39, 51, 0,
|
||||
36, 39, 41, 43, 41, 39, 36, 0, 41, 39, 36, 0, 39, 36, 0, 0,
|
||||
48, 0, 60, 0, 48, 51, 0, 60, 48, 0, 63, 51, 0, 48, 60, 0,
|
||||
36, 39, 41, 43, 46, 43, 41, 39, 36, 0, 48, 0, 36, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic6 = [
|
||||
72, 0, 70, 0, 67, 70, 0, 65, 63, 0, 65, 67, 70, 0, 72, 75,
|
||||
77, 0, 75, 0, 72, 75, 0, 70, 67, 0, 70, 72, 75, 0, 77, 79,
|
||||
75, 0, 77, 0, 75, 72, 0, 70, 67, 0, 65, 67, 70, 0, 75, 72,
|
||||
79, 0, 82, 0, 79, 77, 0, 75, 72, 0, 70, 75, 77, 0, 82, 79,
|
||||
84, 0, 87, 0, 84, 82, 0, 79, 77, 0, 79, 82, 84, 0, 87, 89,
|
||||
87, 0, 84, 0, 82, 0, 79, 0, 77, 0, 75, 0, 72, 0, 70, 0,
|
||||
75, 0, 72, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 65, 67,
|
||||
65, 0, 63, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic7 = [
|
||||
60, 0, 0, 0, 60, 0, 60, 0, 73, 0, 0, 0, 73, 0, 73, 0,
|
||||
60, 60, 0, 73, 73, 0, 60, 73, 79, 0, 73, 0, 60, 0, 0, 0,
|
||||
65, 0, 0, 0, 65, 0, 65, 0, 78, 0, 0, 0, 78, 0, 78, 0,
|
||||
65, 65, 0, 78, 78, 0, 65, 78, 84, 0, 78, 0, 65, 0, 0, 0,
|
||||
67, 0, 0, 0, 67, 0, 80, 0, 80, 67, 80, 67, 80, 84, 80, 67,
|
||||
72, 84, 72, 84, 72, 84, 72, 84, 85, 0, 0, 0, 85, 0, 97, 0,
|
||||
85, 97, 85, 97, 85, 97, 85, 97, 84, 96, 84, 96, 84, 96, 84, 96,
|
||||
72, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic8 = [
|
||||
60, 61, 63, 0, 65, 63, 61, 60, 0, 67, 65, 0, 68, 67, 65, 63,
|
||||
60, 61, 63, 0, 65, 63, 61, 60, 67, 65, 63, 61, 60, 0, 0, 0,
|
||||
63, 65, 67, 0, 68, 67, 65, 63, 0, 70, 68, 0, 72, 70, 68, 67,
|
||||
65, 67, 68, 0, 70, 68, 67, 65, 0, 72, 70, 0, 73, 72, 70, 68,
|
||||
67, 68, 70, 0, 72, 70, 68, 67, 72, 73, 75, 0, 77, 75, 73, 72,
|
||||
73, 75, 77, 0, 79, 77, 75, 73, 75, 77, 79, 0, 80, 79, 77, 75,
|
||||
73, 72, 70, 68, 67, 65, 63, 61, 60, 0, 67, 0, 65, 0, 63, 0,
|
||||
61, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic9 = [
|
||||
72, 0, 0, 67, 0, 65, 0, 62, 60, 0, 62, 0, 65, 0, 67, 72,
|
||||
74, 0, 0, 69, 0, 67, 0, 65, 62, 0, 65, 0, 67, 0, 72, 0,
|
||||
74, 0, 77, 0, 79, 0, 77, 74, 72, 0, 69, 0, 67, 0, 65, 62,
|
||||
77, 0, 79, 0, 81, 0, 79, 77, 74, 0, 72, 0, 69, 0, 67, 65,
|
||||
79, 81, 84, 86, 84, 81, 79, 77, 74, 72, 69, 67, 65, 62, 60, 0,
|
||||
81, 84, 86, 89, 91, 89, 86, 84, 81, 79, 77, 74, 72, 69, 67, 65,
|
||||
72, 0, 74, 0, 77, 0, 79, 0, 77, 0, 74, 0, 72, 0, 69, 0,
|
||||
67, 0, 65, 0, 62, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mepic10 = [
|
||||
48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0,
|
||||
48, 0, 51, 0, 55, 0, 58, 0, 60, 0, 0, 0, 0, 0, 0, 0,
|
||||
60, 63, 67, 70, 72, 70, 67, 63, 65, 67, 70, 72, 75, 72, 70, 67,
|
||||
65, 70, 72, 75, 77, 75, 72, 70, 72, 75, 77, 79, 82, 79, 77, 75,
|
||||
79, 82, 84, 87, 89, 87, 84, 82, 84, 87, 89, 91, 94, 91, 89, 87,
|
||||
91, 89, 87, 84, 82, 79, 77, 75, 72, 70, 67, 65, 63, 60, 58, 55,
|
||||
51, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
"[melodies/epic] mepic1..mepic10 (128 steps) prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,112 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/helpers.scd
|
||||
// Helpers de generation/manipulation de patterns longs
|
||||
//
|
||||
// ~stretchPattern, ~chainPatterns, ~mirror, ~sequenceUp,
|
||||
// ~callResponse, ~aabaForm, ~buildArc, ~rhythmicMotif,
|
||||
// ~melodyFromChords
|
||||
//
|
||||
// Charge par palette/melodies/index.scd. Un seul bloc top-level.
|
||||
// =====================================================================
|
||||
(
|
||||
// --- ~stretchPattern.(notes, factor) : etend un pattern court -----
|
||||
// factor=2 -> chaque note tenue 2x plus longtemps (silences ajoutes)
|
||||
~stretchPattern = { |notes, factor = 2|
|
||||
var out = List.new;
|
||||
notes.do { |n|
|
||||
out.add(n);
|
||||
(factor - 1).do { out.add(0) };
|
||||
};
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
// --- ~chainPatterns.([p1, p2, p3]) : enchaine plusieurs patterns ---
|
||||
~chainPatterns = { |patterns|
|
||||
var out = List.new;
|
||||
patterns.do { |p| p.do { |n| out.add(n) } };
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
// --- ~mirror.(notes) : palindrome (pattern + miroir) --------------
|
||||
~mirror = { |notes|
|
||||
notes ++ notes.reverse;
|
||||
};
|
||||
|
||||
// --- ~sequenceUp.(notes, steps, transpose) : Krautrock seq style --
|
||||
// steps = nombre de repetitions, transpose = decalage par rep
|
||||
~sequenceUp = { |notes, steps = 4, transpose = 2|
|
||||
var out = List.new;
|
||||
steps.do { |i|
|
||||
notes.do { |n|
|
||||
out.add(if (n > 0) { n + (transpose * i) } { 0 });
|
||||
};
|
||||
};
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
// --- ~callResponse.(call, response, n) : alterne call/response ----
|
||||
~callResponse = { |call, response, n = 2|
|
||||
var out = List.new;
|
||||
n.do {
|
||||
call.do { |x| out.add(x) };
|
||||
response.do { |x| out.add(x) };
|
||||
};
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
// --- ~aabaForm.(intro, dev, climax) : structure AABA --------------
|
||||
// AABA = intro - intro - developpement - climax (defaut: dev)
|
||||
~aabaForm = { |intro, dev, climax|
|
||||
var c = climax ?? { dev };
|
||||
intro ++ intro ++ dev ++ c;
|
||||
};
|
||||
|
||||
// --- ~buildArc.(scale, len, lowOct, highOct) : arc montee/descente
|
||||
~buildArc = { |scale, len = 32, lowOct = 4, highOct = 6|
|
||||
var out = List.new, half = len / 2, range = highOct - lowOct;
|
||||
half.do { |i|
|
||||
var oct = lowOct + (range * i / half);
|
||||
var deg = (i % scale.size);
|
||||
out.add(scale[deg] + (12 * oct.floor.asInteger));
|
||||
};
|
||||
half.do { |i|
|
||||
var oct = highOct - (range * i / half);
|
||||
var deg = ((scale.size - 1) - (i % scale.size)).max(0);
|
||||
out.add(scale[deg] + (12 * oct.floor.asInteger));
|
||||
};
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
// --- ~rhythmicMotif.(motif, scale, len) : motif rythmique repete --
|
||||
// motif = pattern de 0/1 (silence/note), scale = liste degres MIDI
|
||||
~rhythmicMotif = { |motif, scale, len = 32|
|
||||
var out = List.new, idx = 0;
|
||||
len.do { |i|
|
||||
var hit = motif.wrapAt(i);
|
||||
if (hit > 0) {
|
||||
out.add(scale.wrapAt(idx));
|
||||
idx = idx + 1;
|
||||
} {
|
||||
out.add(0);
|
||||
};
|
||||
};
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
// --- ~melodyFromChords.(chordRoots, len, octaveRange) -------------
|
||||
// genere mel qui suit une progression d'accords
|
||||
~melodyFromChords = { |chordRoots, len = 32, octRange = 1|
|
||||
var out = List.new;
|
||||
var stepsPerChord = (len / chordRoots.size).floor.asInteger;
|
||||
chordRoots.do { |r|
|
||||
stepsPerChord.do { |i|
|
||||
var pool = [r, r + 4, r + 7, r + 12, r + 11, r + 14];
|
||||
var oct = (octRange.rand2 * 12);
|
||||
if (0.7.coin) { out.add(pool.choose + oct) } { out.add(0) };
|
||||
};
|
||||
};
|
||||
out.asArray;
|
||||
};
|
||||
|
||||
"[melodies/helpers] stretch/chain/mirror/sequenceUp/callResponse/aabaForm/buildArc/rhythmicMotif/melodyFromChords prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/index.scd -- loader du module melodies (split)
|
||||
//
|
||||
// NOTE : les scales et helpers genMelody/mutate/octavate/transpose
|
||||
// /retrograde/densify/sparsify/jitter/genAcidNotes/genAcidAccents
|
||||
// /genAcidSlides/genKickPattern/randomTweak ont ete deplaces dans
|
||||
// palette/scales.scd (un cran au-dessus). 00_load.scd les charge
|
||||
// AVANT ce module via CHARGER TOUT.
|
||||
//
|
||||
// Charge dans l'ordre :
|
||||
// helpers.scd stretch/chain/mirror/sequenceUp/callResponse/...
|
||||
// short.scd ~m1..~m78 (32 pas)
|
||||
// long.scd ~ml1..~ml30 (64 pas)
|
||||
// xlong.scd ~mxl1..~mxl15(96 pas)
|
||||
// epic.scd ~mepic1..~mepic10 (128 pas)
|
||||
// bank.scd ~melodyBank + selecteurs
|
||||
// tracks.scd systeme multi-pistes (charge en DERNIER)
|
||||
//
|
||||
// Usage : (~base ++ "palette/melodies/index.scd").load;
|
||||
// Un seul bloc top-level (compatible .load).
|
||||
// =====================================================================
|
||||
(
|
||||
var dir = thisProcess.nowExecutingPath.dirname;
|
||||
(dir +/+ "helpers.scd").load;
|
||||
(dir +/+ "short.scd").load;
|
||||
(dir +/+ "long.scd").load;
|
||||
(dir +/+ "xlong.scd").load;
|
||||
(dir +/+ "epic.scd").load;
|
||||
(dir +/+ "bank.scd").load;
|
||||
(dir +/+ "tracks.scd").load;
|
||||
"=== melodies module loaded ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,219 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/long.scd
|
||||
// ~ml1..~ml30 -- 30 patterns melodiques de 64 pas (4 mesures)
|
||||
//
|
||||
// Charge par palette/melodies/index.scd. Un seul bloc top-level.
|
||||
// =====================================================================
|
||||
(
|
||||
~ml1 = [
|
||||
36, 0, 48, 0, 36, 39, 0, 48, 36, 0, 51, 39, 0, 36, 48, 0,
|
||||
36, 0, 48, 51, 36, 39, 48, 51, 39, 0, 36, 48, 0, 39, 0, 36,
|
||||
36, 51, 48, 36, 39, 0, 51, 48, 36, 0, 51, 53, 39, 36, 48, 0,
|
||||
36, 53, 51, 48, 39, 0, 36, 48, 36, 0, 51, 0, 48, 39, 36, 0
|
||||
];
|
||||
|
||||
~ml2 = [
|
||||
60, 0, 0, 0, 67, 0, 0, 0, 72, 0, 0, 0, 70, 0, 0, 0,
|
||||
60, 67, 72, 67, 65, 67, 70, 72, 75, 72, 70, 67, 70, 72, 75, 79,
|
||||
60, 67, 72, 75, 72, 67, 60, 67, 65, 72, 77, 79, 77, 72, 65, 72,
|
||||
79, 77, 75, 72, 70, 67, 65, 63, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml3 = [
|
||||
63, 0, 70, 0, 65, 0, 72, 0, 63, 0, 70, 0, 65, 0, 72, 75,
|
||||
65, 0, 72, 0, 67, 0, 75, 0, 65, 0, 72, 0, 67, 0, 75, 79,
|
||||
63, 70, 65, 72, 67, 75, 70, 77, 72, 79, 75, 82, 77, 84, 79, 86,
|
||||
72, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 65, 0, 67, 0
|
||||
];
|
||||
|
||||
~ml4 = [
|
||||
36, 0, 0, 36, 0, 39, 0, 36, 41, 0, 0, 36, 0, 41, 0, 39,
|
||||
36, 0, 0, 41, 0, 39, 0, 36, 43, 0, 0, 41, 0, 36, 0, 39,
|
||||
34, 0, 0, 36, 0, 39, 0, 41, 36, 0, 0, 39, 0, 41, 0, 43,
|
||||
36, 0, 39, 0, 41, 0, 39, 0, 36, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml5 = [
|
||||
60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0,
|
||||
65, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
67, 0, 0, 0, 70, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml6 = [
|
||||
60, 61, 0, 64, 65, 0, 67, 68, 71, 0, 68, 67, 65, 64, 0, 61,
|
||||
60, 0, 64, 65, 67, 68, 71, 72, 71, 68, 67, 65, 64, 61, 60, 0,
|
||||
63, 64, 67, 68, 70, 71, 0, 73, 75, 73, 71, 70, 68, 67, 64, 63,
|
||||
60, 61, 64, 65, 67, 68, 71, 72, 75, 72, 71, 68, 67, 64, 61, 60
|
||||
];
|
||||
|
||||
~ml7 = [
|
||||
67, 0, 72, 0, 70, 0, 67, 65, 63, 0, 67, 0, 70, 0, 72, 75,
|
||||
75, 0, 72, 0, 70, 0, 67, 65, 63, 0, 60, 0, 65, 0, 67, 70,
|
||||
72, 0, 75, 0, 79, 0, 75, 72, 70, 0, 75, 0, 72, 0, 70, 67,
|
||||
72, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml8 = [
|
||||
60, 61, 63, 0, 65, 63, 61, 60, 0, 67, 65, 0, 68, 67, 65, 63,
|
||||
60, 61, 63, 0, 65, 63, 61, 60, 67, 65, 63, 61, 60, 0, 0, 0,
|
||||
63, 65, 67, 0, 68, 67, 65, 63, 0, 70, 68, 0, 72, 70, 68, 67,
|
||||
65, 0, 63, 0, 61, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml9 = [
|
||||
72, 0, 0, 67, 0, 65, 0, 62, 60, 0, 62, 0, 65, 0, 67, 72,
|
||||
74, 0, 0, 69, 0, 67, 0, 65, 62, 0, 65, 0, 67, 0, 72, 0,
|
||||
74, 0, 77, 0, 79, 0, 77, 74, 72, 0, 69, 0, 67, 0, 65, 62,
|
||||
60, 62, 65, 67, 69, 72, 74, 77, 74, 72, 69, 67, 65, 62, 60, 0
|
||||
];
|
||||
|
||||
~ml10 = [
|
||||
48, 0, 54, 0, 48, 0, 54, 0, 60, 0, 54, 0, 48, 0, 54, 0,
|
||||
48, 54, 60, 54, 48, 0, 54, 0, 60, 54, 48, 54, 60, 54, 48, 0,
|
||||
36, 0, 42, 0, 36, 0, 42, 0, 48, 0, 42, 0, 36, 0, 42, 0,
|
||||
48, 54, 60, 66, 60, 54, 48, 42, 36, 42, 48, 54, 60, 54, 48, 36
|
||||
];
|
||||
|
||||
~ml11 = [
|
||||
36, 0, 36, 0, 36, 0, 36, 0, 39, 0, 39, 0, 39, 0, 39, 0,
|
||||
36, 0, 36, 39, 36, 0, 39, 0, 41, 0, 39, 0, 36, 0, 41, 0,
|
||||
34, 0, 34, 0, 36, 0, 39, 0, 41, 0, 39, 36, 41, 39, 36, 0,
|
||||
36, 39, 41, 43, 41, 39, 36, 34, 36, 0, 39, 0, 41, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml12 = [
|
||||
60, 67, 65, 0, 60, 67, 65, 0, 60, 67, 65, 0, 60, 67, 65, 0,
|
||||
60, 67, 65, 70, 60, 67, 65, 0, 60, 67, 65, 70, 60, 67, 65, 72,
|
||||
63, 70, 67, 0, 63, 70, 67, 0, 63, 70, 67, 72, 63, 70, 67, 75,
|
||||
65, 72, 70, 0, 65, 72, 70, 75, 65, 72, 70, 77, 60, 67, 65, 0
|
||||
];
|
||||
|
||||
~ml13 = [
|
||||
60, 60, 67, 60, 65, 60, 67, 60, 62, 62, 69, 62, 67, 62, 69, 62,
|
||||
63, 63, 70, 63, 68, 63, 70, 63, 65, 65, 72, 65, 70, 65, 72, 65,
|
||||
67, 67, 74, 67, 72, 67, 74, 67, 65, 65, 72, 65, 70, 65, 72, 65,
|
||||
63, 63, 70, 63, 68, 63, 70, 63, 60, 60, 67, 60, 65, 60, 67, 60
|
||||
];
|
||||
|
||||
~ml14 = [
|
||||
67, 67, 0, 70, 72, 0, 70, 67, 65, 0, 67, 0, 0, 0, 0, 0,
|
||||
67, 67, 0, 70, 72, 0, 75, 72, 70, 0, 67, 0, 0, 0, 0, 0,
|
||||
72, 75, 0, 77, 79, 0, 77, 75, 72, 0, 70, 0, 67, 0, 65, 0,
|
||||
67, 0, 70, 0, 72, 0, 75, 0, 72, 70, 67, 65, 67, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml15 = [
|
||||
72, 0, 70, 0, 67, 70, 0, 65, 63, 0, 65, 67, 70, 0, 72, 75,
|
||||
77, 0, 75, 0, 72, 75, 0, 70, 67, 0, 70, 72, 75, 0, 77, 79,
|
||||
75, 0, 77, 0, 75, 72, 0, 70, 67, 0, 65, 67, 70, 0, 75, 72,
|
||||
70, 0, 67, 0, 65, 67, 0, 63, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml16 = [
|
||||
60, 62, 0, 65, 67, 0, 69, 70, 67, 65, 62, 60, 0, 65, 67, 70,
|
||||
62, 0, 65, 67, 69, 0, 70, 72, 69, 67, 65, 62, 0, 60, 65, 67,
|
||||
65, 67, 69, 70, 72, 70, 69, 67, 65, 62, 60, 0, 62, 65, 67, 69,
|
||||
72, 70, 69, 67, 65, 62, 60, 0, 65, 67, 69, 70, 72, 0, 70, 0
|
||||
];
|
||||
|
||||
~ml17 = [
|
||||
60, 61, 0, 64, 65, 0, 67, 68, 71, 0, 68, 67, 65, 64, 0, 61,
|
||||
60, 0, 64, 65, 67, 0, 68, 71, 72, 71, 68, 67, 65, 64, 61, 60,
|
||||
65, 67, 0, 68, 71, 0, 72, 73, 76, 0, 73, 72, 71, 68, 0, 67,
|
||||
72, 73, 76, 73, 72, 71, 68, 67, 65, 64, 61, 60, 64, 65, 67, 68
|
||||
];
|
||||
|
||||
~ml18 = [
|
||||
60, 0, 0, 0, 63, 0, 0, 0, 65, 0, 0, 0, 67, 0, 0, 0,
|
||||
60, 0, 0, 0, 67, 0, 0, 0, 60, 0, 0, 0, 65, 0, 0, 0,
|
||||
63, 0, 0, 0, 67, 0, 0, 0, 65, 0, 0, 0, 70, 0, 0, 0,
|
||||
60, 0, 67, 0, 63, 0, 70, 0, 65, 0, 67, 0, 60, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml19 = [
|
||||
48, 0, 51, 0, 53, 0, 48, 0, 46, 0, 51, 0, 53, 0, 55, 0,
|
||||
48, 0, 51, 53, 51, 0, 48, 0, 46, 0, 53, 0, 55, 0, 51, 48,
|
||||
44, 0, 48, 0, 51, 0, 48, 0, 53, 0, 55, 0, 51, 0, 48, 0,
|
||||
48, 51, 53, 51, 48, 0, 46, 48, 55, 53, 51, 48, 46, 44, 0, 0
|
||||
];
|
||||
|
||||
~ml20 = [
|
||||
60, 64, 67, 72, 60, 64, 67, 72, 62, 65, 69, 74, 62, 65, 69, 74,
|
||||
63, 67, 70, 75, 63, 67, 70, 75, 60, 64, 67, 72, 65, 67, 70, 72,
|
||||
65, 69, 72, 77, 65, 69, 72, 77, 67, 71, 74, 79, 67, 71, 74, 79,
|
||||
72, 76, 79, 84, 72, 76, 79, 84, 60, 64, 67, 72, 60, 64, 67, 72
|
||||
];
|
||||
|
||||
~ml21 = [
|
||||
60, 0, 0, 63, 0, 65, 0, 67, 0, 70, 0, 67, 65, 63, 0, 60,
|
||||
0, 65, 0, 67, 0, 70, 0, 72, 0, 70, 0, 67, 0, 65, 0, 63,
|
||||
65, 0, 0, 67, 0, 70, 0, 72, 0, 75, 0, 72, 70, 67, 0, 65,
|
||||
0, 67, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml22 = [
|
||||
36, 0, 0, 0, 39, 0, 36, 0, 41, 0, 0, 0, 39, 0, 41, 36,
|
||||
34, 0, 0, 0, 39, 0, 41, 0, 43, 0, 41, 0, 39, 0, 36, 0,
|
||||
36, 0, 41, 0, 43, 0, 41, 0, 46, 0, 43, 0, 41, 0, 39, 0,
|
||||
36, 39, 41, 43, 46, 43, 41, 39, 36, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml23 = [
|
||||
67, 0, 70, 0, 0, 67, 0, 65, 67, 0, 70, 72, 0, 70, 0, 67,
|
||||
65, 0, 67, 0, 0, 65, 0, 63, 65, 0, 67, 70, 0, 72, 0, 70,
|
||||
72, 0, 75, 0, 0, 72, 0, 70, 72, 0, 75, 77, 0, 75, 0, 72,
|
||||
70, 0, 72, 0, 0, 70, 0, 67, 65, 0, 67, 0, 70, 0, 72, 0
|
||||
];
|
||||
|
||||
~ml24 = [
|
||||
60, 0, 0, 0, 60, 0, 60, 0, 73, 0, 0, 0, 73, 0, 73, 0,
|
||||
60, 60, 0, 73, 73, 0, 60, 73, 79, 0, 73, 0, 60, 0, 0, 0,
|
||||
65, 0, 0, 0, 65, 0, 65, 0, 78, 0, 0, 0, 78, 0, 78, 0,
|
||||
65, 65, 0, 78, 78, 0, 65, 78, 84, 0, 78, 0, 65, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml25 = [
|
||||
60, 67, 72, 64, 67, 71, 60, 67, 62, 65, 69, 62, 65, 69, 60, 67,
|
||||
64, 67, 71, 64, 67, 71, 60, 67, 65, 69, 72, 65, 69, 72, 60, 67,
|
||||
67, 72, 76, 67, 71, 74, 60, 67, 65, 69, 72, 65, 69, 76, 65, 67,
|
||||
64, 67, 71, 64, 67, 71, 62, 65, 60, 67, 72, 64, 60, 64, 67, 60
|
||||
];
|
||||
|
||||
~ml26 = [
|
||||
0, 67, 0, 70, 0, 67, 0, 65, 0, 67, 0, 72, 0, 70, 0, 67,
|
||||
0, 70, 0, 72, 0, 70, 0, 67, 0, 65, 0, 67, 0, 70, 0, 72,
|
||||
0, 72, 0, 75, 0, 72, 0, 70, 0, 72, 0, 77, 0, 75, 0, 72,
|
||||
0, 75, 0, 77, 0, 75, 0, 72, 0, 70, 0, 67, 0, 70, 0, 72
|
||||
];
|
||||
|
||||
~ml27 = [
|
||||
36, 0, 38, 0, 39, 0, 41, 0, 43, 0, 44, 0, 43, 0, 41, 0,
|
||||
39, 0, 41, 0, 43, 0, 44, 0, 46, 0, 48, 0, 46, 0, 43, 0,
|
||||
44, 0, 46, 0, 48, 0, 50, 0, 51, 0, 50, 0, 48, 0, 46, 0,
|
||||
43, 0, 46, 0, 48, 0, 51, 0, 46, 0, 43, 0, 41, 0, 39, 36
|
||||
];
|
||||
|
||||
~ml28 = [
|
||||
60, 61, 0, 70, 0, 73, 0, 67, 61, 0, 73, 0, 67, 70, 0, 76,
|
||||
60, 61, 0, 70, 0, 73, 0, 67, 73, 76, 0, 70, 67, 61, 60, 0,
|
||||
63, 64, 0, 73, 0, 76, 0, 70, 64, 0, 76, 0, 70, 73, 0, 79,
|
||||
63, 64, 73, 76, 79, 76, 73, 70, 67, 64, 63, 61, 60, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml29 = [
|
||||
72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 0, 0, 0,
|
||||
72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
|
||||
75, 73, 71, 69, 67, 65, 63, 61, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~ml30 = [
|
||||
60, 0, 62, 0, 64, 0, 66, 0, 68, 0, 70, 0, 72, 0, 0, 0,
|
||||
72, 0, 70, 0, 68, 0, 66, 0, 64, 0, 62, 0, 60, 0, 0, 0,
|
||||
66, 0, 68, 0, 70, 0, 72, 0, 74, 0, 76, 0, 78, 0, 0, 0,
|
||||
78, 0, 76, 0, 74, 0, 72, 0, 70, 0, 68, 0, 66, 0, 0, 0
|
||||
];
|
||||
|
||||
"[melodies/long] ml1..ml30 (64 steps) prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,91 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/short.scd
|
||||
// ~m1..~m78 -- 78 patterns melodiques de 32 pas
|
||||
//
|
||||
// Charge par palette/melodies/index.scd. Un seul bloc top-level.
|
||||
// =====================================================================
|
||||
(
|
||||
// ---------- M1-M28 (premiere serie historique) ----------------------
|
||||
~m1 = [60,0,67,0,70,0,67,65, 63,0,60,0,0,67,70,72, 75,0,72,70,67,0,0,65, 63,60,0,67,70,0,72,0];
|
||||
~m2 = [60,0,0,67,0,70,0,67, 60,0,0,67,0,70,0,72, 60,0,0,67,0,70,0,67, 63,0,0,70,0,72,0,75];
|
||||
~m3 = [63,0,0,0,70,0,67,0, 65,0,0,0,70,0,72,0, 63,0,0,0,67,0,70,0, 65,0,60,0,67,0,0,0];
|
||||
~m4 = [60,63,67,70,72,70,67,63, 60,63,67,70,75,72,70,67, 65,67,70,72,75,72,70,65, 63,67,70,75,79,75,70,63];
|
||||
~m5 = [60,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0, 60,0,0,0,0,0,0,0, 65,0,0,0,0,0,0,0];
|
||||
~m6 = [60,0,63,0,65,67,0,70, 72,0,75,79,0,75,72,70, 67,0,65,63,0,60,0,63, 65,0,67,0,70,0,72,0];
|
||||
~m7 = [36,0,36,39,0,41,36,0, 38,0,36,39,0,43,41,0, 36,0,36,39,0,41,36,0, 38,0,41,39,36,0,41,0];
|
||||
~m8 = [60,67,72,67,60,67,72,75, 60,67,72,67,65,72,77,72, 60,67,72,67,60,67,72,79, 65,72,77,72,60,67,72,67];
|
||||
~m9 = [60,0,63,0,67,0,0,0, 0,0,0,0,0,0,0,0, 65,0,67,0,70,0,72,0, 0,0,0,0,0,0,0,0];
|
||||
~m10 = [60,0,63,0,67,0,70,0, 66,0,69,0,73,0,76,0, 60,0,63,0,67,0,70,0, 66,0,69,0,76,0,73,0];
|
||||
~m11 = [60,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0, 60,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0];
|
||||
~m12 = [60,63,67,70,60,63,67,70, 60,63,67,72,60,63,67,75, 60,63,67,72,65,67,70,75, 65,70,72,79,67,72,75,79];
|
||||
~m13 = [60,0,63,65,0,67,0,69, 0,65,0,63,65,0,60,0, 67,0,65,63,0,67,69,0, 65,63,0,60,0,63,65,67];
|
||||
~m14 = [60,61,63,0,65,63,61,60, 0,67,65,0,68,67,65,63, 60,61,63,0,65,63,61,60, 67,65,63,61,60,0,0,0];
|
||||
~m15 = [60,0,63,0,65,0,68,71, 72,0,71,0,68,65,63,0, 60,0,63,65,0,68,71,0, 72,0,68,65,63,60,0,0];
|
||||
~m16 = [48,0,51,53,54,0,55,0, 58,0,55,0,53,51,48,0, 48,0,51,53,54,0,55,58, 60,0,58,55,53,51,48,0];
|
||||
~m17 = [72,0,0,67,0,65,0,62, 60,0,62,0,65,0,67,72, 74,0,0,69,0,67,0,65, 62,0,65,0,67,0,72,0];
|
||||
~m18 = [60,0,67,0,70,67,60,0, 67,0,70,60,0,67,70,75, 60,0,67,0,70,67,60,65, 67,0,70,0,75,70,67,60];
|
||||
~m19 = [60,63,65,67,70,67,65,63, 60,63,67,70,72,70,67,63, 65,67,70,72,75,72,70,67, 65,70,72,75,77,75,72,70, 63,65,67,70,72,70,67,65, 63,67,70,72,75,72,70,67, 60,63,67,70,72,75,72,70, 67,65,63,67,65,63,60,0];
|
||||
~m20 = [60,0,61,0,63,65,0,67, 68,0,67,65,63,61,0,60, 63,0,65,0,67,68,0,70, 72,0,70,68,67,65,0,63, 65,0,67,0,68,70,0,72, 74,0,72,70,68,67,0,65, 72,0,70,68,67,65,63,61, 60,65,63,65,61,60,0,0];
|
||||
~m21 = [60,62,0,65,67,0,69,70, 67,65,62,60,0,65,67,70, 62,0,65,67,69,0,70,72, 69,67,65,62,0,60,65,67, 65,67,69,70,72,70,69,67, 65,62,60,0,62,65,67,69, 72,70,69,67,65,62,60,0, 65,67,69,70,72,0,70,0];
|
||||
~m22 = [60,63,65,67,70,67,65,63, 60,67,65,63,65,70,65,67, 63,65,67,70,72,70,67,65, 63,70,67,65,67,72,67,70, 65,67,68,70,72,70,68,67, 65,72,70,67,70,72,70,72, 67,68,70,72,74,72,70,68, 67,74,72,70,72,75,72,75];
|
||||
~m23 = [63,70,67,70,65,72,70,72, 63,70,67,70,65,72,75,72, 65,72,70,72,67,75,72,75, 65,72,70,72,60,67,65,67, 63,70,67,70,65,72,70,72, 63,67,65,67,65,72,75,79, 65,72,70,72,67,75,72,75, 60,67,65,67,63,70,67,70];
|
||||
~m24 = [60,67,72,75,72,67,60,67, 63,70,75,77,75,70,63,70, 65,72,77,79,77,72,65,72, 67,74,79,82,79,74,67,74, 79,77,75,72,70,67,65,63, 72,75,77,79,82,79,77,75, 65,72,77,79,84,82,79,77, 72,70,67,65,63,60,0,0];
|
||||
~m25 = [72,0,70,0,67,0,65,0, 63,0,65,0,67,0,70,0, 72,0,75,0,77,0,75,0, 72,0,70,0,67,0,65,0, 77,0,75,0,72,0,70,0, 67,0,65,0,63,0,65,0, 79,0,77,0,75,0,72,0, 77,0,75,0,70,0,67,0];
|
||||
~m26 = [60,63,67,70,72,75,79,82, 79,75,72,70,67,63,60,63, 67,70,72,75,79,82,84,87, 84,82,79,75,72,70,67,63, 65,67,70,72,75,79,82,84, 82,79,75,72,70,67,65,67, 63,65,67,70,72,75,77,79, 77,75,72,70,67,65,63,60];
|
||||
~m27 = [60,0,67,0,70,0,67,60, 60,0,67,0,70,0,72,75, 63,0,70,0,72,0,70,63, 63,0,70,0,72,0,75,77, 65,0,72,0,75,0,72,65, 65,0,72,0,75,0,77,79, 63,0,70,0,72,0,70,63, 60,0,67,0,65,0,63,60];
|
||||
~m28 = [72,0,70,0,67,70,0,65, 63,0,65,67,70,0,72,75, 77,0,75,0,72,75,0,70, 67,0,70,72,75,0,77,79, 75,0,77,0,75,72,0,70, 67,0,65,67,70,0,75,72, 70,0,67,0,65,67,0,63, 60,0,0,0,0,0,0,0];
|
||||
|
||||
// ---------- M29-M78 (genres et timbres varies) ----------------------
|
||||
~m29 = [36,0,48,0,36,39,0,48, 36,0,51,39,0,36,48,0, 36,0,48,0,36,39,0,51, 39,0,36,48,0,39,0,36];
|
||||
~m30 = [36,36,48,0,36,0,39,48, 36,51,0,36,39,0,48,0, 36,0,48,51,36,0,39,48, 36,36,51,0,36,48,39,0];
|
||||
~m31 = [36,0,0,0,39,0,0,0, 41,0,0,0,36,0,0,0, 34,0,0,0,39,0,0,0, 41,0,0,0,43,0,0,0];
|
||||
~m32 = [72,0,75,0,72,0,70,0, 67,0,70,0,72,0,75,0, 77,0,75,0,72,0,70,0, 75,0,72,0,70,0,67,0];
|
||||
~m33 = [60,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 63,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0];
|
||||
~m34 = [60,0,0,0,67,0,0,0, 70,0,0,0,0,0,0,0, 63,0,0,0,70,0,0,0, 72,0,0,0,0,0,0,0];
|
||||
~m35 = [67,67,0,70,72,0,70,67, 65,0,67,0,0,0,0,0, 67,67,0,70,72,0,75,72, 70,0,67,0,0,0,0,0];
|
||||
~m36 = [60,0,67,0,70,0,72,0, 72,70,67,70,72,0,0,0, 60,0,67,0,70,0,75,0, 75,72,70,72,75,0,0,0];
|
||||
~m37 = [48,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 48,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0];
|
||||
~m38 = [48,0,0,0,0,0,0,0, 54,0,0,0,0,0,0,0, 48,0,0,0,0,0,0,0, 54,0,0,0,0,0,0,0];
|
||||
~m39 = [60,61,0,64,65,0,67,68, 71,0,68,67,65,64,0,61, 60,0,64,65,67,0,68,71, 72,71,68,67,65,64,61,60];
|
||||
~m40 = [60,0,62,0,63,0,67,0, 68,0,67,63,0,62,60,0, 60,0,63,0,67,0,68,0, 72,0,68,67,63,62,60,0];
|
||||
~m41 = [60,0,65,0,67,0,70,0, 72,0,70,67,65,0,60,0, 65,0,67,0,70,0,72,0, 74,0,72,70,67,65,60,0];
|
||||
~m42 = [64,65,67,65,64,0,60,0, 64,65,67,68,67,65,64,0, 67,68,70,68,67,0,64,0, 67,68,70,72,70,68,67,65];
|
||||
~m43 = [60,61,64,65,67,65,64,61, 60,0,64,65,67,68,67,65, 64,61,60,61,64,65,67,68, 70,68,67,65,64,61,60,0];
|
||||
~m44 = [60,0,63,65,67,0,68,71, 72,71,68,67,65,63,0,60, 63,65,67,68,71,72,71,68, 67,65,63,60,63,65,67,68];
|
||||
~m45 = [48,0,54,0,48,0,54,0, 60,0,54,0,48,0,54,0, 48,54,60,54,48,0,54,0, 60,54,48,54,60,54,48,0];
|
||||
~m46 = [36,0,41,0,43,0,41,0, 36,0,43,41,36,0,41,0, 36,41,43,41,48,0,43,41, 36,0,43,41,36,41,36,0];
|
||||
~m47 = [60,0,63,64,65,67,0,70, 67,65,64,63,60,0,67,70, 63,0,65,67,70,0,67,65, 63,60,63,65,67,65,60,0];
|
||||
~m48 = [60,0,62,0,64,0,67,0, 69,0,67,64,62,60,0,0, 62,0,64,0,67,0,69,0, 72,0,69,67,64,62,60,0];
|
||||
~m49 = [60,0,64,0,67,0,0,0, 67,0,71,0,74,0,0,0, 69,0,72,0,76,0,0,0, 65,0,69,0,72,0,0,0];
|
||||
~m50 = [69,0,72,76,72,0,69,0, 65,0,69,72,69,0,65,0, 60,0,64,67,64,0,60,0, 67,0,71,74,71,0,67,0];
|
||||
~m51 = [36,0,38,0,39,0,41,0, 43,0,44,0,43,0,41,0, 39,0,41,0,43,0,44,0, 46,0,48,0,46,0,43,0];
|
||||
~m52 = [38,41,45,41,38,0,45,41, 43,47,50,47,43,0,50,47, 48,52,55,52,48,0,55,52, 50,47,43,41,38,0,0,0];
|
||||
~m53 = [60,61,0,70,0,73,0,67, 61,0,73,0,67,70,0,76, 60,61,0,70,0,73,0,67, 73,76,0,70,67,61,60,0];
|
||||
~m54 = [60,67,65,0,60,67,65,0, 60,67,65,0,60,67,65,0, 63,70,67,0,63,70,67,0, 60,67,65,0,60,67,65,0];
|
||||
~m55 = [60,63,67,70,60,63,67,70, 60,63,67,70,60,63,67,70, 60,63,67,72,60,63,67,72, 60,63,67,75,60,63,67,70];
|
||||
~m56 = [60,67,60,67,60,67,60,67, 60,67,60,67,60,67,60,67, 60,65,60,65,60,65,60,65, 60,67,60,67,60,70,60,70];
|
||||
~m57 = [72,71,70,69,68,67,66,65, 64,63,62,61,60,0,0,0, 72,71,70,69,68,67,66,65, 64,63,62,61,60,59,58,57];
|
||||
~m58 = [60,0,62,0,64,0,66,0, 68,0,70,0,72,0,0,0, 72,0,70,0,68,0,66,0, 64,0,62,0,60,0,0,0];
|
||||
~m59 = [60,0,66,0,60,0,66,0, 72,0,66,0,60,0,66,0, 60,66,60,66,72,66,72,66, 60,0,66,0,72,0,66,60];
|
||||
~m60 = [60,61,60,64,65,64,67,68, 67,65,64,61,60,64,65,0, 67,68,67,71,72,71,68,67, 65,64,61,60,61,64,65,67];
|
||||
~m61 = [67,0,72,0,70,0,67,65, 63,0,67,0,70,0,72,75, 75,0,72,0,70,0,67,65, 63,0,60,0,65,0,67,70];
|
||||
~m62 = [60,64,67,72,60,64,67,72, 62,65,69,74,62,65,69,74, 63,67,70,75,63,67,70,75, 60,64,67,72,65,67,70,72];
|
||||
~m63 = [36,0,36,0,39,0,36,0, 41,0,36,0,39,0,41,0, 34,0,34,0,39,0,41,0, 43,0,41,0,39,0,36,0];
|
||||
~m64 = [67,0,70,0,0,67,0,65, 67,0,70,72,0,70,0,67, 65,0,67,0,0,65,0,63, 65,0,67,70,0,72,0,70];
|
||||
~m65 = [0,67,0,70,0,67,0,65, 0,67,0,72,0,70,0,67, 0,70,0,72,0,70,0,67, 0,65,0,67,0,70,0,72];
|
||||
~m66 = [48,0,51,0,53,0,48,0, 46,0,51,0,53,0,55,0, 48,0,51,53,51,0,48,0, 46,0,53,0,55,0,51,48];
|
||||
~m67 = [60,0,0,0,60,0,60,0, 73,0,0,0,73,0,73,0, 60,60,0,73,73,0,60,73, 79,0,73,0,60,0,0,0];
|
||||
~m68 = [36,0,36,0,36,0,36,0, 39,0,39,0,39,0,39,0, 36,0,36,39,36,0,39,0, 41,0,39,0,36,0,41,0];
|
||||
~m69 = [60,0,0,0,0,0,0,0, 63,0,0,0,0,0,0,0, 65,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0];
|
||||
~m70 = [36,0,39,36,48,0,36,39, 41,0,39,36,48,0,41,39, 36,39,41,39,36,0,48,36, 43,41,39,36,39,0,41,39];
|
||||
~m71 = [60,63,67,70,0,0,0,0, 60,63,67,70,0,0,0,0, 58,62,65,68,0,0,0,0, 60,63,67,70,0,0,0,0];
|
||||
~m72 = [60,0,0,63,0,0,67,0, 0,70,0,0,0,67,0,0, 65,0,0,67,0,0,70,0, 0,72,0,0,0,70,0,0];
|
||||
~m73 = [72,0,0,0,0,0,70,0, 0,0,67,0,0,0,65,0, 0,0,67,0,0,0,70,0, 0,0,72,0,0,0,75,0];
|
||||
~m74 = [60,67,72,64,67,71,60,67, 62,65,69,62,65,69,60,67, 64,67,71,64,67,71,60,67, 65,69,72,65,69,72,60,67];
|
||||
~m75 = [72,75,79,75,72,75,79,84, 79,75,72,75,72,70,67,65, 67,70,72,75,79,75,72,70, 67,65,67,70,72,70,67,60];
|
||||
~m76 = [67,0,70,67,0,65,67,0, 63,0,67,0,70,65,67,0, 75,0,72,70,0,67,65,0, 67,0,70,0,72,75,70,67];
|
||||
~m77 = [60,60,67,60,65,60,67,60, 62,62,69,62,67,62,69,62, 63,63,70,63,68,63,70,63, 65,65,72,65,70,65,72,65];
|
||||
~m78 = [0,67,0,70,67,0,70,0, 72,0,70,0,67,70,0,65, 0,67,0,70,67,0,75,0, 72,70,0,67,65,0,70,0];
|
||||
|
||||
"[melodies/short] m1..m78 (32 steps) prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,322 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/tracks.scd
|
||||
// Systeme multi-pistes melodiques -- jusqu'a N voix simultanees.
|
||||
//
|
||||
// Le legacy \melodySeq de engine.scd continue a fonctionner ; ce
|
||||
// systeme s'AJOUTE en parallele. Chaque piste a son propre Pdef
|
||||
// (\<name>Seq) construit a partir d'un Event de parametres stocke
|
||||
// dans ~mel[\name].
|
||||
//
|
||||
// HELPERS EXPOSES
|
||||
// ~melTrackAdd.(\name, params) cree une piste + Pdef
|
||||
// ~melTrackRemove.(\name) stop + remove
|
||||
// ~melTrackOn.(\name) / Off play / stop
|
||||
// ~melTrackSet.(\name, key, val) edite un param + reload Pdef
|
||||
// ~melTrackSetAll.(\name, params) edite plusieurs params en bloc
|
||||
// ~melTrackList.() etat de toutes les pistes
|
||||
// ~melTrackSolo.(\name) / Unsolo mute toutes sauf une
|
||||
// ~melTrackChoke.() stop toutes
|
||||
// ~melTrackReload.(\name) / All
|
||||
// ~melTrackHarm.(\src, \dst, \pres) ajoute une harmonie auto
|
||||
// ~melTrackByGenre.(\name, \genre) melodie aleatoire du melodyBank
|
||||
//
|
||||
// PARAMS d'une piste (Event) :
|
||||
// notes inst cutoff rq attack release drive amp dur boost pan octave
|
||||
//
|
||||
// Charge en DERNIER par index.scd (apres scales/short/long/.../bank).
|
||||
// Un seul bloc top-level (compatible .load).
|
||||
// =====================================================================
|
||||
(
|
||||
// ---------- Etat global ---------------------------------------------
|
||||
~mel = ~mel ?? { () }; // dict des pistes melodiques (Event)
|
||||
~melSoloed = ~melSoloed ?? { nil }; // backup amp pendant un solo
|
||||
|
||||
// ---------- Builder : construit (ou rebuild) le Pdef d'une piste ----
|
||||
~melTrackBuildPdef = { |name|
|
||||
var t = ~mel[name];
|
||||
var sym = (name.asString ++ "Seq").asSymbol; // ex: \m1Seq
|
||||
if (t.isNil) {
|
||||
("[melTrack] " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
// Defaults par champ : on guarantit que rien ne plante
|
||||
var notes = (t[\notes] ?? { (0 ! 32) });
|
||||
var inst = (t[\inst] ?? \pad);
|
||||
var cutoff = (t[\cutoff] ?? 2400);
|
||||
var rq = (t[\rq] ?? 0.5);
|
||||
var attack = (t[\attack] ?? 0.01);
|
||||
var release = (t[\release] ?? 0.3);
|
||||
var drive = (t[\drive] ?? 1.2);
|
||||
var amp = (t[\amp] ?? 0.14);
|
||||
var dur = (t[\dur] ?? 0.25);
|
||||
var boost = (t[\boost] ?? 1.0);
|
||||
var pan = (t[\pan] ?? 0);
|
||||
var octave = (t[\octave] ?? 0);
|
||||
var sawAmt = (t[\sawAmt] ?? 0.6);
|
||||
var detune = (t[\detune] ?? 0.006);
|
||||
var subAmt = (t[\subAmt] ?? 0.4);
|
||||
if (notes.isEmpty) { notes = (0 ! 32) };
|
||||
Pdef(sym, Pbind(
|
||||
\instrument, inst, \dur, dur,
|
||||
\legato, 0.9,
|
||||
\type, Pseq(notes.collect { |n| if(n > 0) { \note } { \rest } }, inf),
|
||||
\midinote, Pseq(notes.collect { |n| if(n > 0) { n + (octave * 12) } { 60 } }, inf),
|
||||
\cutoff, cutoff,
|
||||
\rq, rq,
|
||||
\attack, attack,
|
||||
\release, release,
|
||||
\drive, drive,
|
||||
\sawAmt, sawAmt,
|
||||
\detune, detune,
|
||||
\subAmt, subAmt,
|
||||
\pan, pan,
|
||||
\amp, amp * boost,
|
||||
\scBus, if (~scBus.notNil) { ~scBus.index } { 0 },
|
||||
\scAmt, (~leadScAmt ?? 0.5),
|
||||
));
|
||||
sym
|
||||
};
|
||||
};
|
||||
|
||||
// ---------- ADD : enregistre (ou met a jour) une piste --------------
|
||||
~melTrackAdd = { |name, params|
|
||||
var existing = ~mel[name];
|
||||
var p = params ?? { () };
|
||||
if (existing.isNil) {
|
||||
~mel[name] = p;
|
||||
} {
|
||||
// Merge : on garde l'ancien et on ecrase avec les nouveaux champs
|
||||
p.keysValuesDo { |k, v| existing[k] = v };
|
||||
~mel[name] = existing;
|
||||
};
|
||||
~melTrackBuildPdef.(name);
|
||||
("[melTrack] add " ++ name).postln;
|
||||
name
|
||||
};
|
||||
|
||||
// ---------- REMOVE : stop + supprime du dict ------------------------
|
||||
~melTrackRemove = { |name|
|
||||
var sym = (name.asString ++ "Seq").asSymbol;
|
||||
Pdef(sym).stop;
|
||||
Pdef(sym).clear;
|
||||
~mel[name] = nil;
|
||||
("[melTrack] remove " ++ name).postln;
|
||||
};
|
||||
|
||||
// ---------- ON / OFF -----------------------------------------------
|
||||
~melTrackOn = { |name|
|
||||
var sym = (name.asString ++ "Seq").asSymbol;
|
||||
if (~mel[name].isNil) {
|
||||
("[melTrack] " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
~melTrackBuildPdef.(name);
|
||||
Pdef(sym).play;
|
||||
("[melTrack] ON " ++ name).postln;
|
||||
};
|
||||
};
|
||||
~melTrackOff = { |name|
|
||||
var sym = (name.asString ++ "Seq").asSymbol;
|
||||
Pdef(sym).stop;
|
||||
("[melTrack] OFF " ++ name).postln;
|
||||
};
|
||||
|
||||
// ---------- SET / SETALL : edition + rebuild ------------------------
|
||||
~melTrackSet = { |name, key, val|
|
||||
var t = ~mel[name];
|
||||
if (t.isNil) {
|
||||
("[melTrack] " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
t[key] = val;
|
||||
~melTrackBuildPdef.(name);
|
||||
("[melTrack] " ++ name ++ " ." ++ key ++ " = " ++ val).postln;
|
||||
};
|
||||
};
|
||||
~melTrackSetAll = { |name, params|
|
||||
var t = ~mel[name];
|
||||
if (t.isNil) {
|
||||
("[melTrack] " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
params.keysValuesDo { |k, v| t[k] = v };
|
||||
~melTrackBuildPdef.(name);
|
||||
("[melTrack] " ++ name ++ " setAll " ++ params.keys.asArray).postln;
|
||||
};
|
||||
};
|
||||
|
||||
// ---------- LIST ----------------------------------------------------
|
||||
~melTrackList = {
|
||||
"=== melodic tracks ===".postln;
|
||||
if (~mel.isEmpty) {
|
||||
" (aucune piste)".postln;
|
||||
} {
|
||||
~mel.keysValuesDo { |k, v|
|
||||
var sym = (k.asString ++ "Seq").asSymbol;
|
||||
// Pdef.player vaut nil si jamais joue, sinon a un EventStreamPlayer.
|
||||
var pl = Pdef(sym).player;
|
||||
var st = if (pl.notNil and: { pl.isPlaying }) { "ON " } { "off" };
|
||||
(" [" ++ st ++ "] " ++ k
|
||||
++ " inst=" ++ (v[\inst] ? \unknown)
|
||||
++ " amp=" ++ (v[\amp] ? \unknown)
|
||||
++ " oct=" ++ (v[\octave] ? 0)
|
||||
++ " notes=" ++ (v[\notes].notNil.if({v[\notes].size}, {0})) ++ "n"
|
||||
).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// ---------- SOLO / UNSOLO ------------------------------------------
|
||||
~melTrackSolo = { |name|
|
||||
if (~mel[name].isNil) {
|
||||
("[melTrack] solo : " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
// Backup amp courant avant le solo (si pas deja en solo)
|
||||
if (~melSoloed.isNil) {
|
||||
~melSoloed = ();
|
||||
~mel.keysValuesDo { |k, v| ~melSoloed[k] = (v[\amp] ? 0) };
|
||||
};
|
||||
~mel.keysValuesDo { |k, v|
|
||||
if (k != name) {
|
||||
v[\amp] = 0;
|
||||
~melTrackBuildPdef.(k);
|
||||
};
|
||||
};
|
||||
("[melTrack] solo " ++ name).postln;
|
||||
};
|
||||
};
|
||||
~melTrackUnsolo = {
|
||||
if (~melSoloed.isNil) {
|
||||
"[melTrack] pas de solo actif".postln;
|
||||
} {
|
||||
~melSoloed.keysValuesDo { |k, v|
|
||||
if (~mel[k].notNil) {
|
||||
~mel[k][\amp] = v;
|
||||
~melTrackBuildPdef.(k);
|
||||
};
|
||||
};
|
||||
~melSoloed = nil;
|
||||
"[melTrack] unsolo (amps restaures)".postln;
|
||||
};
|
||||
};
|
||||
|
||||
// ---------- CHOKE : stop tout ---------------------------------------
|
||||
~melTrackChoke = {
|
||||
~mel.keysDo { |k|
|
||||
var sym = (k.asString ++ "Seq").asSymbol;
|
||||
Pdef(sym).stop;
|
||||
};
|
||||
"[melTrack] choke (toutes les pistes off)".postln;
|
||||
};
|
||||
|
||||
// ---------- RELOAD --------------------------------------------------
|
||||
~melTrackReload = { |name|
|
||||
if (~mel[name].isNil) {
|
||||
("[melTrack] reload : " ++ name ++ " inconnue").postln;
|
||||
} {
|
||||
~melTrackBuildPdef.(name);
|
||||
("[melTrack] reload " ++ name).postln;
|
||||
};
|
||||
};
|
||||
~melTrackReloadAll = {
|
||||
~mel.keysDo { |k| ~melTrackBuildPdef.(k) };
|
||||
("[melTrack] reloadAll (" ++ ~mel.size ++ " pistes)").postln;
|
||||
};
|
||||
|
||||
// ---------- HARMONIE AUTO : derive une piste d'une autre -----------
|
||||
// ~melTrackHarm.(\src, \dst, \preset)
|
||||
// presets : \third \fifth \sixth \octave \counter \bassline \arp
|
||||
~melTrackHarm = { |srcName, dstName, preset = \third|
|
||||
var src = ~mel[srcName];
|
||||
if (src.isNil) {
|
||||
("[melTrack] harm : src " ++ srcName ++ " inconnue").postln;
|
||||
} {
|
||||
var srcNotes = src[\notes] ?? { (0 ! 32) };
|
||||
var dstNotes, dstInst, dstAmp, dstDur, dstAttack, dstRelease;
|
||||
switch (preset,
|
||||
\third, {
|
||||
dstNotes = (~genThirdHarmony ?? {{ |m, s = 4| m.collect { |n| if(n>0){n+s}{0} } }}).(srcNotes);
|
||||
dstInst = \warmPad; dstAmp = 0.12; dstDur = 0.25;
|
||||
dstAttack = 0.3; dstRelease = 1.2;
|
||||
},
|
||||
\fifth, {
|
||||
dstNotes = (~genFifthHarmony ?? {{ |m| m.collect { |n| if(n>0){n+7}{0} } }}).(srcNotes);
|
||||
dstInst = \warmPad; dstAmp = 0.12; dstDur = 0.25;
|
||||
dstAttack = 0.3; dstRelease = 1.2;
|
||||
},
|
||||
\sixth, {
|
||||
dstNotes = srcNotes.collect { |n| if (n > 0) { n + 9 } { 0 } };
|
||||
dstInst = \warmPad; dstAmp = 0.12; dstDur = 0.25;
|
||||
dstAttack = 0.3; dstRelease = 1.2;
|
||||
},
|
||||
\octave, {
|
||||
dstNotes = srcNotes.collect { |n| if (n > 0) { n + 12 } { 0 } };
|
||||
dstInst = \organLead; dstAmp = 0.12; dstDur = 0.25;
|
||||
dstAttack = 0.005; dstRelease = 0.2;
|
||||
},
|
||||
\counter, {
|
||||
dstNotes = (~genCounterMelody
|
||||
?? {{ |m, p = 132| m.collect { |n| if(n>0){(p-n).max(48).min(96)}{0} } }}
|
||||
).(srcNotes);
|
||||
dstInst = \pluck; dstAmp = 0.13; dstDur = 0.25;
|
||||
dstAttack = 0.005; dstRelease = 0.4;
|
||||
},
|
||||
\bassline, {
|
||||
dstNotes = srcNotes.collect { |n| if (n > 0) { (n - 24).max(24) } { 0 } };
|
||||
dstInst = \subBoom; dstAmp = 0.30; dstDur = 0.5;
|
||||
dstAttack = 0.005; dstRelease = 0.6;
|
||||
},
|
||||
\arp, {
|
||||
dstNotes = srcNotes.collect { |n| if (n > 0) { n + 12 } { 0 } };
|
||||
dstInst = \pluck; dstAmp = 0.13; dstDur = 0.125;
|
||||
dstAttack = 0.001; dstRelease = 0.2;
|
||||
}
|
||||
);
|
||||
~melTrackAdd.(dstName, (
|
||||
notes: dstNotes, inst: dstInst, amp: dstAmp, dur: dstDur,
|
||||
attack: dstAttack, release: dstRelease,
|
||||
cutoff: 2500, rq: 0.5, drive: 1.2, boost: 1.0, pan: 0, octave: 0
|
||||
));
|
||||
("[melTrack] harm " ++ srcName ++ " -> " ++ dstName ++ " (" ++ preset ++ ")").postln;
|
||||
};
|
||||
};
|
||||
|
||||
// ---------- LIEN MELODYBANK : tirage par genre ----------------------
|
||||
~melTrackByGenre = { |name, genre|
|
||||
var pool = ~melodyBank !? { ~melodyBank[genre] };
|
||||
if (pool.isNil or: { pool.size == 0 }) {
|
||||
("[melTrack] byGenre : " ++ genre ++ " inconnu / vide").postln;
|
||||
} {
|
||||
var key = pool.choose;
|
||||
var notes = currentEnvironment[key];
|
||||
if (notes.notNil and: { notes.isArray }) {
|
||||
if (~mel[name].isNil) {
|
||||
~melTrackAdd.(name, (notes: notes.copy));
|
||||
} {
|
||||
~mel[name][\notes] = notes.copy;
|
||||
~melTrackBuildPdef.(name);
|
||||
};
|
||||
("[melTrack] byGenre " ++ name ++ " <- " ++ genre ++ "/" ++ key).postln;
|
||||
} { ("[melTrack] byGenre : " ++ key ++ " inconnue").postln };
|
||||
};
|
||||
};
|
||||
|
||||
// ---------- 3 PISTES PAR DEFAUT (inactives) -------------------------
|
||||
// m1 = lead pad, m2 = counter pluck, m3 = sub boom
|
||||
~melTrackAdd.(\m1, (
|
||||
notes: (~m1 ?? { (0 ! 32) }).copy,
|
||||
inst: \pad, cutoff: 2400, rq: 0.5,
|
||||
attack: 0.4, release: 1.5, drive: 1.0,
|
||||
amp: 0.14, dur: 0.25, boost: 1.0, pan: 0, octave: 0
|
||||
));
|
||||
~melTrackAdd.(\m2, (
|
||||
notes: (~m25 ?? { (0 ! 32) }).copy,
|
||||
inst: \pluck, cutoff: 4500, rq: 0.5,
|
||||
attack: 0.005, release: 0.4, drive: 1.0,
|
||||
amp: 0.12, dur: 0.25, boost: 1.0, pan: -0.3, octave: 0
|
||||
));
|
||||
~melTrackAdd.(\m3, (
|
||||
notes: (~m31 ?? { (0 ! 32) }).copy,
|
||||
inst: \subBoom, cutoff: 800, rq: 0.4,
|
||||
attack: 0.005, release: 0.6, drive: 1.2,
|
||||
amp: 0.25, dur: 0.5, boost: 1.0, pan: 0, octave: -1
|
||||
));
|
||||
|
||||
"[melodies/tracks] systeme multi-pistes pret -- 3 pistes par defaut (m1 m2 m3, off). ~melTrackOn.(\\m1) pour lancer.".postln;
|
||||
)
|
||||
@@ -0,0 +1,144 @@
|
||||
// =====================================================================
|
||||
// palette/melodies/xlong.scd
|
||||
// ~mxl1..~mxl15 -- 15 patterns melodiques de 96 pas (6 mesures, AABA)
|
||||
//
|
||||
// Charge par palette/melodies/index.scd. Un seul bloc top-level.
|
||||
// =====================================================================
|
||||
(
|
||||
~mxl1 = [
|
||||
60, 0, 0, 0, 67, 0, 0, 0, 72, 0, 0, 0, 70, 0, 0, 0,
|
||||
60, 0, 0, 0, 67, 0, 70, 0, 72, 0, 0, 0, 75, 0, 72, 70,
|
||||
60, 67, 72, 67, 65, 67, 70, 72, 75, 72, 70, 67, 70, 72, 75, 79,
|
||||
60, 67, 72, 75, 72, 67, 60, 67, 65, 72, 77, 79, 77, 72, 65, 72,
|
||||
79, 77, 75, 72, 79, 77, 75, 72, 82, 79, 77, 75, 84, 82, 79, 77,
|
||||
72, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl2 = [
|
||||
63, 0, 70, 0, 65, 0, 72, 0, 63, 0, 70, 0, 65, 0, 72, 75,
|
||||
65, 0, 72, 0, 67, 0, 75, 0, 65, 0, 72, 0, 67, 0, 75, 79,
|
||||
63, 70, 65, 72, 67, 75, 70, 77, 72, 79, 75, 82, 77, 84, 79, 86,
|
||||
65, 72, 67, 75, 70, 77, 72, 79, 75, 82, 77, 84, 79, 86, 82, 89,
|
||||
72, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 65, 0, 67, 0,
|
||||
65, 67, 63, 65, 60, 63, 65, 67, 63, 65, 60, 63, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl3 = [
|
||||
60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0,
|
||||
65, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
67, 0, 0, 0, 70, 0, 0, 0, 72, 0, 0, 0, 75, 0, 0, 0,
|
||||
77, 0, 0, 0, 75, 0, 0, 0, 72, 0, 0, 0, 70, 0, 0, 0,
|
||||
67, 0, 0, 0, 65, 0, 0, 0, 63, 0, 0, 0, 60, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl4 = [
|
||||
60, 61, 0, 64, 65, 0, 67, 68, 71, 0, 68, 67, 65, 64, 0, 61,
|
||||
60, 0, 64, 65, 67, 68, 71, 72, 71, 68, 67, 65, 64, 61, 60, 0,
|
||||
63, 64, 67, 68, 70, 71, 0, 73, 75, 73, 71, 70, 68, 67, 64, 63,
|
||||
60, 61, 64, 65, 67, 68, 71, 72, 75, 72, 71, 68, 67, 64, 61, 60,
|
||||
65, 67, 68, 71, 72, 73, 76, 75, 76, 75, 73, 72, 71, 68, 67, 65,
|
||||
72, 73, 76, 75, 73, 72, 71, 68, 67, 65, 64, 61, 60, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl5 = [
|
||||
36, 0, 48, 0, 36, 39, 0, 48, 36, 0, 51, 39, 0, 36, 48, 0,
|
||||
36, 0, 48, 51, 36, 39, 48, 51, 39, 0, 36, 48, 0, 39, 0, 36,
|
||||
36, 51, 48, 36, 39, 0, 51, 48, 36, 0, 51, 53, 39, 36, 48, 0,
|
||||
36, 53, 51, 48, 39, 0, 36, 48, 36, 0, 51, 0, 48, 39, 36, 0,
|
||||
39, 0, 51, 0, 39, 41, 0, 51, 39, 0, 53, 41, 0, 39, 51, 0,
|
||||
36, 39, 41, 43, 41, 39, 36, 0, 36, 0, 48, 0, 36, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl6 = [
|
||||
67, 0, 72, 0, 70, 0, 67, 65, 63, 0, 67, 0, 70, 0, 72, 75,
|
||||
75, 0, 72, 0, 70, 0, 67, 65, 63, 0, 60, 0, 65, 0, 67, 70,
|
||||
72, 0, 75, 0, 79, 0, 75, 72, 70, 0, 75, 0, 72, 0, 70, 67,
|
||||
72, 0, 75, 0, 79, 0, 82, 79, 75, 0, 79, 0, 75, 0, 72, 70,
|
||||
79, 0, 75, 0, 72, 0, 70, 67, 65, 0, 67, 0, 70, 0, 72, 75,
|
||||
72, 0, 70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl7 = [
|
||||
60, 67, 65, 0, 60, 67, 65, 0, 60, 67, 65, 0, 60, 67, 65, 0,
|
||||
60, 67, 65, 0, 60, 67, 65, 0, 60, 67, 65, 0, 60, 67, 65, 70,
|
||||
63, 70, 67, 0, 63, 70, 67, 0, 65, 72, 70, 0, 65, 72, 70, 75,
|
||||
67, 74, 72, 0, 67, 74, 72, 77, 70, 77, 75, 0, 72, 79, 77, 82,
|
||||
63, 70, 67, 0, 63, 70, 67, 0, 60, 67, 65, 70, 60, 67, 65, 70,
|
||||
60, 67, 65, 0, 60, 67, 65, 0, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl8 = [
|
||||
60, 61, 63, 0, 65, 63, 61, 60, 0, 67, 65, 0, 68, 67, 65, 63,
|
||||
60, 61, 63, 0, 65, 63, 61, 60, 67, 65, 63, 61, 60, 0, 0, 0,
|
||||
63, 65, 67, 0, 68, 67, 65, 63, 0, 70, 68, 0, 72, 70, 68, 67,
|
||||
65, 67, 68, 0, 70, 68, 67, 65, 0, 72, 70, 0, 73, 72, 70, 68,
|
||||
67, 68, 70, 0, 72, 70, 68, 67, 65, 63, 61, 60, 61, 63, 65, 67,
|
||||
65, 0, 63, 0, 61, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl9 = [
|
||||
60, 0, 0, 0, 60, 0, 60, 0, 73, 0, 0, 0, 73, 0, 73, 0,
|
||||
60, 60, 0, 73, 73, 0, 60, 73, 79, 0, 73, 0, 60, 0, 0, 0,
|
||||
65, 0, 0, 0, 65, 0, 65, 0, 78, 0, 0, 0, 78, 0, 78, 0,
|
||||
65, 65, 0, 78, 78, 0, 65, 78, 84, 0, 78, 0, 65, 0, 0, 0,
|
||||
67, 0, 0, 0, 67, 0, 80, 0, 80, 67, 80, 67, 80, 84, 80, 67,
|
||||
72, 84, 72, 84, 72, 84, 72, 84, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl10 = [
|
||||
67, 67, 0, 70, 72, 0, 70, 67, 65, 0, 67, 0, 0, 0, 0, 0,
|
||||
67, 67, 0, 70, 72, 0, 75, 72, 70, 0, 67, 0, 0, 0, 0, 0,
|
||||
72, 75, 0, 77, 79, 0, 77, 75, 72, 0, 70, 0, 67, 0, 65, 0,
|
||||
77, 79, 0, 80, 79, 0, 77, 75, 72, 0, 75, 0, 77, 0, 79, 0,
|
||||
72, 75, 0, 77, 79, 0, 84, 79, 77, 0, 75, 0, 72, 0, 70, 0,
|
||||
67, 0, 70, 0, 72, 0, 75, 0, 72, 70, 67, 65, 67, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl11 = [
|
||||
72, 0, 0, 67, 0, 65, 0, 62, 60, 0, 62, 0, 65, 0, 67, 72,
|
||||
74, 0, 0, 69, 0, 67, 0, 65, 62, 0, 65, 0, 67, 0, 72, 0,
|
||||
74, 0, 77, 0, 79, 0, 77, 74, 72, 0, 69, 0, 67, 0, 65, 62,
|
||||
77, 0, 79, 0, 81, 0, 79, 77, 74, 0, 72, 0, 69, 0, 67, 65,
|
||||
79, 81, 84, 86, 84, 81, 79, 77, 74, 72, 69, 67, 65, 62, 60, 0,
|
||||
72, 0, 67, 0, 65, 0, 62, 0, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl12 = [
|
||||
48, 0, 54, 0, 48, 0, 54, 0, 60, 0, 54, 0, 48, 0, 54, 0,
|
||||
48, 54, 60, 54, 48, 0, 54, 0, 60, 54, 48, 54, 60, 54, 48, 0,
|
||||
36, 0, 42, 0, 36, 0, 42, 0, 48, 0, 42, 0, 36, 0, 42, 0,
|
||||
48, 54, 60, 66, 60, 54, 48, 42, 36, 42, 48, 54, 60, 54, 48, 36,
|
||||
48, 54, 60, 66, 72, 66, 60, 54, 48, 42, 36, 42, 48, 54, 60, 66,
|
||||
72, 0, 66, 0, 60, 0, 54, 0, 48, 0, 36, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
~mxl13 = [
|
||||
60, 64, 67, 72, 60, 64, 67, 72, 62, 65, 69, 74, 62, 65, 69, 74,
|
||||
63, 67, 70, 75, 63, 67, 70, 75, 60, 64, 67, 72, 65, 67, 70, 72,
|
||||
65, 69, 72, 77, 65, 69, 72, 77, 67, 71, 74, 79, 67, 71, 74, 79,
|
||||
72, 76, 79, 84, 72, 76, 79, 84, 75, 79, 82, 87, 75, 79, 82, 87,
|
||||
79, 83, 86, 91, 79, 83, 86, 91, 77, 81, 84, 89, 77, 81, 84, 89,
|
||||
72, 76, 79, 84, 65, 69, 72, 77, 60, 64, 67, 72, 60, 64, 67, 72
|
||||
];
|
||||
|
||||
~mxl14 = [
|
||||
60, 61, 0, 64, 65, 0, 67, 68, 71, 0, 68, 67, 65, 64, 0, 61,
|
||||
60, 0, 64, 65, 67, 0, 68, 71, 72, 71, 68, 67, 65, 64, 61, 60,
|
||||
65, 67, 0, 68, 71, 0, 72, 73, 76, 0, 73, 72, 71, 68, 0, 67,
|
||||
72, 73, 76, 73, 72, 71, 68, 67, 65, 64, 61, 60, 64, 65, 67, 68,
|
||||
71, 72, 73, 76, 79, 76, 73, 72, 71, 68, 67, 65, 64, 61, 60, 61,
|
||||
65, 67, 71, 72, 73, 76, 73, 72, 71, 68, 67, 65, 61, 60, 0, 0
|
||||
];
|
||||
|
||||
~mxl15 = [
|
||||
72, 0, 70, 0, 67, 70, 0, 65, 63, 0, 65, 67, 70, 0, 72, 75,
|
||||
77, 0, 75, 0, 72, 75, 0, 70, 67, 0, 70, 72, 75, 0, 77, 79,
|
||||
75, 0, 77, 0, 75, 72, 0, 70, 67, 0, 65, 67, 70, 0, 75, 72,
|
||||
79, 0, 82, 0, 79, 77, 0, 75, 72, 0, 70, 75, 77, 0, 82, 79,
|
||||
75, 0, 72, 0, 70, 67, 0, 65, 63, 0, 60, 0, 65, 0, 67, 0,
|
||||
70, 0, 67, 0, 65, 0, 63, 0, 60, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
"[melodies/xlong] mxl1..mxl15 (96 steps) prets".postln;
|
||||
)
|
||||
@@ -0,0 +1,268 @@
|
||||
// =====================================================================
|
||||
// drum_kits.scd
|
||||
// 21 drum kits complets :
|
||||
// Originaux : TECHNO / DUBSTEP / DnB / TRAP / HOUSE / BREAKBEAT
|
||||
// Nouveaux : HARDSTYLE / DRUM'N'BASS / JUNGLE / GARAGE 2-STEP /
|
||||
// TRAP808 / PHONK / FOOTWORK / LIQUID DnB / SYNTHWAVE /
|
||||
// INDUSTRIAL / TRIBAL WORLD / HARDCORE / LO-FI HIP-HOP /
|
||||
// FUTURE GARAGE / DETROIT DEEP
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur un bloc pour l'appliquer.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// KITS ORIGINAUX (conserves)
|
||||
// =====================================================================
|
||||
|
||||
// --- KIT TECHNO -----------------------------------------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.32; ~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~snareSteps = (0 ! 16); ~clapSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT TECHNO ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT DUBSTEP ----------------------------------------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 48; ~kickPitchAmt = 3.5; ~kickDecay = 0.5; ~kickDrive = 1.5; ~kickClick = 0.15;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5;
|
||||
~snareFreq = 220; ~snareNoiseAmt = 0.65; ~snareDecay = 0.16;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT DUBSTEP ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT DRUM'N'BASS -----------------------------------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 55; ~kickPitchAmt = 4.0; ~kickDecay = 0.18; ~kickDrive = 1.5; ~kickClick = 0.3;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~snareAmp = 0.5;
|
||||
~snareFreq = 240; ~snareNoiseAmt = 0.7; ~snareDecay = 0.10;
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1]; ~hatAmp = 0.12;
|
||||
~clapSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT DnB ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT TRAP ------------------------------------------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,1, 1,0,0,0, 0,1,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 42; ~kickPitchAmt = 2.5; ~kickDecay = 0.6; ~kickDrive = 1.2; ~kickClick = 0.08;
|
||||
~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~hatAmp = 0.10;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.3;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,1,0,0, 1,0,1,0, 0,1,0,1]; ~percAmp = 0.2;
|
||||
~snareSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT TRAP ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT HOUSE ------------------------------------------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 50; ~kickPitchAmt = 2.8; ~kickDecay = 0.35; ~kickDrive = 1.2; ~kickClick = 0.12;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.15;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.35;
|
||||
~snareSteps = (0 ! 16); ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT HOUSE ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT BREAKBEAT --------------------------------------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.3; ~kickDrive = 1.3; ~kickClick = 0.25;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~snareAmp = 0.45;
|
||||
~snareFreq = 200; ~snareNoiseAmt = 0.6;
|
||||
~hatSteps = [0,1,0,1, 1,1,0,1, 0,1,0,1, 1,1,0,1]; ~hatAmp = 0.10;
|
||||
~percInst = \openHat; ~percSteps = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0]; ~percAmp = 0.22;
|
||||
~clapSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT BREAKBEAT ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// NOUVEAUX KITS
|
||||
// =====================================================================
|
||||
|
||||
// --- KIT HARDSTYLE -- kick gabber + clap large + tail "reverse" -----
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,1, 1,0,0,0, 1,1,0,0]; ~kickAmp = 0.65;
|
||||
~kickFreq = 62; ~kickPitchAmt = 5.5; ~kickDecay = 0.30; ~kickDrive = 4.0; ~kickClick = 0.45;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.55;
|
||||
~snareFreq = 230; ~snareNoiseAmt = 0.7; ~snareDecay = 0.18;
|
||||
~hatSteps = [0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1]; ~hatAmp = 0.12;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.45;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,1]; ~percAmp = 0.22;
|
||||
~reload.value; "=== KIT HARDSTYLE ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT DRUM'N'BASS PUNCHY (alt) -- kick punchy + amen + hat fast --
|
||||
(
|
||||
~kickSteps = [1,0,0,1, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 58; ~kickPitchAmt = 4.5; ~kickDecay = 0.16; ~kickDrive = 1.8; ~kickClick = 0.4;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,1, 1,0,1,1]; ~snareAmp = 0.55;
|
||||
~snareFreq = 250; ~snareNoiseAmt = 0.75; ~snareDecay = 0.09;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.13;
|
||||
~clapSteps = (0 ! 16);
|
||||
~percInst = \openHat; ~percSteps = [0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.18;
|
||||
~reload.value; "=== KIT DRUM'N'BASS PUNCHY ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT JUNGLE -- chopped breakbeat + ragga rim --------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,1, 0,1,0,0, 1,0,0,1, 0,1,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.5; ~kickDecay = 0.20; ~kickDrive = 1.6; ~kickClick = 0.32;
|
||||
~snareSteps = [0,0,0,0, 1,0,1,0, 0,0,0,1, 1,0,0,1]; ~snareAmp = 0.55;
|
||||
~snareFreq = 220; ~snareNoiseAmt = 0.7; ~snareDecay = 0.10;
|
||||
~hatSteps = [1,1,0,1, 1,0,1,1, 1,1,0,1, 1,0,1,1]; ~hatAmp = 0.12;
|
||||
~clapSteps = (0 ! 16);
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,1,0,0, 0,0,1,0, 0,1,0,0]; ~percAmp = 0.30;
|
||||
~reload.value; "=== KIT JUNGLE ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT GARAGE 2-STEP -- clap shuffled + snare pad -----------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 50; ~kickPitchAmt = 2.8; ~kickDecay = 0.35; ~kickDrive = 1.2; ~kickClick = 0.15;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 0,1,0,0]; ~snareAmp = 0.4;
|
||||
~snareFreq = 200; ~snareNoiseAmt = 0.55; ~snareDecay = 0.20;
|
||||
~hatSteps = [0,1,1,0, 1,1,0,1, 0,1,1,0, 1,1,0,1]; ~hatAmp = 0.11;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.32;
|
||||
~percInst = \rim; ~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT GARAGE 2-STEP ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT TRAP808 -- 808 boom + clap + hi-hat trap rolls -------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,1, 1,0,0,0, 0,1,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 38; ~kickPitchAmt = 1.8; ~kickDecay = 0.85; ~kickDrive = 1.0; ~kickClick = 0.05;
|
||||
~snareSteps = (0 ! 16);
|
||||
~hatSteps = [1,1,1,0, 1,1,1,1, 1,1,1,0, 1,1,1,1]; ~hatAmp = 0.09;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.35;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,1, 0,1,0,0, 1,0,1,0, 0,1,1,0]; ~percAmp = 0.18;
|
||||
~reload.value; "=== KIT TRAP808 ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT PHONK -- cowbell + 808 + pitched snare --------------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,1, 1,0,0,0, 0,1,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 40; ~kickPitchAmt = 2.0; ~kickDecay = 0.7; ~kickDrive = 1.2; ~kickClick = 0.08;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.45;
|
||||
~snareFreq = 280; ~snareNoiseAmt = 0.65; ~snareDecay = 0.14;
|
||||
~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~hatAmp = 0.11;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.30;
|
||||
~percInst = \cowbell; ~cowbellFreq = 800;
|
||||
~percSteps = [0,0,1,0, 0,1,0,0, 1,0,0,1, 0,0,1,0]; ~percAmp = 0.32;
|
||||
~reload.value; "=== KIT PHONK ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT FOOTWORK -- rapid hat + 808 + clap stutter -----------------
|
||||
(
|
||||
~kickSteps = [1,0,0,1, 1,0,0,0, 1,0,1,1, 0,0,1,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 42; ~kickPitchAmt = 2.4; ~kickDecay = 0.5; ~kickDrive = 1.3; ~kickClick = 0.10;
|
||||
~snareSteps = (0 ! 16);
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = [0,0,0,1, 1,0,0,0, 0,0,0,1, 1,0,0,0]; ~clapAmp = 0.32;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,0,1]; ~percAmp = 0.22;
|
||||
~reload.value; "=== KIT FOOTWORK ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT LIQUID DnB -- subtle kick + breakbeat + smooth hat ---------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~kickAmp = 0.45;
|
||||
~kickFreq = 50; ~kickPitchAmt = 3.0; ~kickDecay = 0.28; ~kickDrive = 1.2; ~kickClick = 0.18;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.42;
|
||||
~snareFreq = 220; ~snareNoiseAmt = 0.55; ~snareDecay = 0.14;
|
||||
~hatSteps = [1,0,1,1, 0,1,0,1, 1,0,1,1, 0,1,0,1]; ~hatAmp = 0.09;
|
||||
~clapSteps = (0 ! 16);
|
||||
~percInst = \openHat; ~percSteps = [0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.18;
|
||||
~reload.value; "=== KIT LIQUID DnB ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT SYNTHWAVE -- kick 80s + reverb snare + hat soft ------------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.30; ~kickDrive = 1.2; ~kickClick = 0.18;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5;
|
||||
~snareFreq = 180; ~snareNoiseAmt = 0.55; ~snareDecay = 0.22;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.13;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.30;
|
||||
~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT SYNTHWAVE ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT INDUSTRIAL -- kick metal + snare reverse + perc clang ------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq = 60; ~kickPitchAmt = 5.0; ~kickDecay = 0.28; ~kickDrive = 3.5; ~kickClick = 0.4;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.55;
|
||||
~snareFreq = 260; ~snareNoiseAmt = 0.8; ~snareDecay = 0.10;
|
||||
~hatSteps = [0,1,0,1, 1,1,0,1, 0,1,0,1, 1,1,0,1]; ~hatAmp = 0.13;
|
||||
~clapSteps = (0 ! 16);
|
||||
~percInst = \rim; ~percSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,1]; ~percAmp = 0.4;
|
||||
~reload.value; "=== KIT INDUSTRIAL ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT TRIBAL WORLD -- perc layered + kick small + shaker ---------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.4;
|
||||
~kickFreq = 48; ~kickPitchAmt = 2.2; ~kickDecay = 0.4; ~kickDrive = 1.0; ~kickClick = 0.06;
|
||||
~snareSteps = (0 ! 16);
|
||||
~hatSteps = [1,1,0,1, 1,0,1,1, 0,1,1,1, 1,0,1,1]; ~hatAmp = 0.08;
|
||||
~clapSteps = (0 ! 16);
|
||||
~percInst = \tom; ~tomFreq = 95;
|
||||
~percSteps = [1,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0]; ~percAmp = 0.4;
|
||||
~reload.value; "=== KIT TRIBAL WORLD ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT HARDCORE -- kick sature + snare 909 distordu + claps -------
|
||||
(
|
||||
~kickSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~kickAmp = 0.65;
|
||||
~kickFreq = 60; ~kickPitchAmt = 5.0; ~kickDecay = 0.20; ~kickDrive = 4.0; ~kickClick = 0.35;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~snareAmp = 0.55;
|
||||
~snareFreq = 240; ~snareNoiseAmt = 0.85; ~snareDecay = 0.10;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.12;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~clapAmp = 0.42;
|
||||
~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT HARDCORE ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT LO-FI HIP-HOP -- kick muted + snare vinyl + perc dust ------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~kickAmp = 0.45;
|
||||
~kickFreq = 45; ~kickPitchAmt = 2.0; ~kickDecay = 0.55; ~kickDrive = 1.0; ~kickClick = 0.04;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.40;
|
||||
~snareFreq = 190; ~snareNoiseAmt = 0.45; ~snareDecay = 0.15;
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~hatAmp = 0.08;
|
||||
~clapSteps = (0 ! 16);
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,0,1, 0,0,1,0, 0,1,0,0]; ~percAmp = 0.14;
|
||||
~reload.value; "=== KIT LO-FI HIP-HOP ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT FUTURE GARAGE -- kick rolling + snare ghost + 16th hat -----
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 48; ~kickPitchAmt = 2.5; ~kickDecay = 0.5; ~kickDrive = 1.2; ~kickClick = 0.10;
|
||||
~snareSteps = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,1,0,0]; ~snareAmp = 0.30;
|
||||
~snareFreq = 210; ~snareNoiseAmt = 0.5; ~snareDecay = 0.15;
|
||||
~hatSteps = [0,1,1,0, 1,1,0,1, 0,1,1,0, 1,1,0,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~clapAmp = 0.32;
|
||||
~percSteps = (0 ! 16);
|
||||
~reload.value; "=== KIT FUTURE GARAGE ===".postln;
|
||||
)
|
||||
|
||||
// --- KIT DETROIT DEEP -- kick 909 + clap warm + perc minimal --------
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,1, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 52; ~kickPitchAmt = 2.8; ~kickDecay = 0.32; ~kickDrive = 1.3; ~kickClick = 0.16;
|
||||
~snareSteps = (0 ! 16);
|
||||
~hatSteps = [0,1,1,0, 1,1,0,1, 0,1,1,0, 1,1,0,1]; ~hatAmp = 0.13;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~clapAmp = 0.32;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.18;
|
||||
~reload.value; "=== KIT DETROIT DEEP ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// =====================================================================
|
||||
// fills.scd
|
||||
// Helpers rythmiques : ~snareFill / ~tomFill
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur le bloc pour l'appliquer.
|
||||
// Compatible avec .load (un seul bloc top-level).
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
// --- Snare fill (8 hits sur 1s, accelerando d'amp) -----------------
|
||||
~snareFill = { |hits = 8, dur = 1, ampStart = 0.3, ampEnd = 0.5|
|
||||
Routine({
|
||||
hits.do { |k|
|
||||
var a = ampStart + ((ampEnd - ampStart) * (k / hits.max(1)));
|
||||
Synth(\snare, [\amp, a, \decay, 0.06, \freq, 200 + (k * 10)]);
|
||||
(dur / hits).wait;
|
||||
};
|
||||
}).play;
|
||||
};
|
||||
|
||||
// --- Tom fill (descente sur 4 toms) -------------------------------
|
||||
~tomFill = {
|
||||
Routine({
|
||||
[180, 140, 110, 85].do { |f|
|
||||
Synth(\tom, [\freq, f, \decay, 0.25, \amp, 0.5]);
|
||||
0.15.wait;
|
||||
};
|
||||
}).play;
|
||||
};
|
||||
|
||||
"helpers ~snareFill / ~tomFill prets".postln;
|
||||
)
|
||||
|
||||
// Exemples manuels (Cmd+Entree, ne PAS evaluer au .load) :
|
||||
( ~snareFill.value; ) // fill standard 8 hits / 1s
|
||||
( ~snareFill.(16, 2, 0.2, 0.55); ) // fill long accelerando
|
||||
( ~tomFill.value; ) // descente 4 toms
|
||||
@@ -0,0 +1,223 @@
|
||||
// =====================================================================
|
||||
// kicks.scd
|
||||
// ~25 patterns kick (K1-K25) + ~12 timbres kick (T1-T12)
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur un bloc pour l'appliquer.
|
||||
//
|
||||
// En plus des blocs auto-applicants, chaque pattern est stocke dans
|
||||
// ~kK1..~kK25 (tableau 16 steps brut, sans appliquer). Util pour
|
||||
// ~seqPlay.([[16, { ~kickSteps = ~kK3; ~reload.value }], ...])
|
||||
// cf. palette/sequences.scd.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// STOCKAGE (variables ~kK1..~kK25) -- evaluer ce bloc une fois pour
|
||||
// enregistrer tous les patterns sous forme de variables reutilisables
|
||||
// par sequences.scd.
|
||||
// =====================================================================
|
||||
(
|
||||
// --- 4-on-floor classique -------------------------------------------
|
||||
~kK1 = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ];
|
||||
// --- techno syncope (8th deplaces) ----------------------------------
|
||||
~kK2 = [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0 ];
|
||||
// --- gabber double-temps (toutes 8th notes) -------------------------
|
||||
~kK3 = [ 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0 ];
|
||||
// --- dembow / latin (1 + 1+e + 3 + 3+e) -----------------------------
|
||||
~kK4 = [ 1,0,0,1, 0,0,1,0, 1,0,0,1, 0,0,1,0 ];
|
||||
// --- half-time (1 et 9 -- dubstep / phonk / hip-hop) ----------------
|
||||
~kK5 = [ 1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ];
|
||||
// --- breakbeat amen-like --------------------------------------------
|
||||
~kK6 = [ 1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0 ];
|
||||
// --- techno triplet feel (3 over 4) ---------------------------------
|
||||
~kK7 = [ 1,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,1 ];
|
||||
// --- minimal -- 1 kick par mesure (downtempo) -----------------------
|
||||
~kK8 = [ 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ];
|
||||
|
||||
// --- 4-on-floor + ghost offbeat (techno minimal) --------------------
|
||||
~kK9 = [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0 ];
|
||||
// --- 4-on-floor syncope avancee -------------------------------------
|
||||
~kK10 = [ 1,0,1,0, 1,0,0,1, 1,0,1,0, 1,0,1,1 ];
|
||||
// --- double-time (1, 5, 9, 13 + 3, 7, 11, 15) -----------------------
|
||||
~kK11 = [ 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0 ];
|
||||
// --- breakbeat (drum'n'bass / jungle base) --------------------------
|
||||
~kK12 = [ 1,0,0,1, 0,0,0,0, 0,0,1,0, 0,0,1,0 ];
|
||||
// --- amen break kick pattern (jungle origine) -----------------------
|
||||
~kK13 = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
|
||||
// --- gabber dense (kick sur tous 16th) ------------------------------
|
||||
~kK14 = [ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 ];
|
||||
// --- hardstyle (kick + reverse + tail simulee) ----------------------
|
||||
~kK15 = [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,1,0,0 ];
|
||||
// --- techno minimal kick fantome ------------------------------------
|
||||
~kK16 = [ 1,0,0,0, 1,0,0,0, 1,0,0,1, 1,0,0,0 ];
|
||||
// --- trance gros kick (4/4 punchy + ghost 16) -----------------------
|
||||
~kK17 = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,1 ];
|
||||
// --- house classique (kick 4/4 + offbeat hat impl) ------------------
|
||||
~kK18 = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ];
|
||||
// --- electro syncope ------------------------------------------------
|
||||
~kK19 = [ 1,0,0,1, 0,0,0,0, 1,0,0,0, 0,0,1,0 ];
|
||||
// --- trip-hop lazy --------------------------------------------------
|
||||
~kK20 = [ 1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0 ];
|
||||
// --- jungle rapid breakbeat -----------------------------------------
|
||||
~kK21 = [ 1,0,0,1, 0,1,0,0, 1,0,0,1, 0,1,0,0 ];
|
||||
// --- reggae / dub one-drop (kick sur 3) -----------------------------
|
||||
~kK22 = [ 0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ];
|
||||
// --- afrobeat (kick polyrhythmique) ---------------------------------
|
||||
~kK23 = [ 1,0,0,1, 0,1,0,0, 1,0,1,0, 0,1,0,0 ];
|
||||
// --- garage 2-step --------------------------------------------------
|
||||
~kK24 = [ 1,0,0,0, 0,0,1,0, 0,0,0,0, 1,0,0,0 ];
|
||||
// --- footwork / juke (160 BPM, kick triple) -------------------------
|
||||
~kK25 = [ 1,0,0,1, 1,0,0,0, 1,0,1,1, 0,0,1,0 ];
|
||||
"=== kicks : 25 patterns stockes dans ~kK1..~kK25 ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// PATTERNS RYTHMIQUES (blocs auto-applicants)
|
||||
// =====================================================================
|
||||
|
||||
// --- K1 : 4-on-the-floor (defaut) -----------------------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ]; ~reload.value; "K1 4/4".postln; )
|
||||
|
||||
// --- K2 : techno syncope (8th notes deplaces) -----------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0 ]; ~reload.value; "K2 syncope".postln; )
|
||||
|
||||
// --- K3 : gabber double-temps (toutes les 2 doubles-croches) --------
|
||||
( ~kickSteps = [ 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0 ]; ~reload.value; "K3 gabber".postln; )
|
||||
|
||||
// --- K4 : dembow / latin (1 + 1+e + 3 + 3+e) ------------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 0,0,1,0, 1,0,0,1, 0,0,1,0 ]; ~reload.value; "K4 dembow".postln; )
|
||||
|
||||
// --- K5 : half-time (kick 1 et 9 -- dubstep/phonk/hip-hop) ----------
|
||||
( ~kickSteps = [ 1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ]; ~reload.value; "K5 half-time".postln; )
|
||||
|
||||
// --- K6 : breakbeat (Amen-like) -------------------------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0 ]; ~reload.value; "K6 breakbeat".postln; )
|
||||
|
||||
// --- K7 : techno triplet feel (3 over 4) ----------------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,1 ]; ~reload.value; "K7 triplet feel".postln; )
|
||||
|
||||
// --- K8 : minimal -- 1 kick par mesure (downtempo) -----------------
|
||||
( ~kickSteps = [ 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ]; ~reload.value; "K8 minimal".postln; )
|
||||
|
||||
// --- K9 : 4-on-floor + ghost offbeat (techno minimaliste) ----------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0 ]; ~reload.value; "K9 minimal ghost".postln; )
|
||||
|
||||
// --- K10 : 4-on-floor syncope avance (drive +) ---------------------
|
||||
( ~kickSteps = [ 1,0,1,0, 1,0,0,1, 1,0,1,0, 1,0,1,1 ]; ~reload.value; "K10 syncope avance".postln; )
|
||||
|
||||
// --- K11 : double-time (8th sur tous les temps) --------------------
|
||||
( ~kickSteps = [ 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0 ]; ~reload.value; "K11 double-time".postln; )
|
||||
|
||||
// --- K12 : breakbeat irregulier (DnB / jungle) ---------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 0,0,0,0, 0,0,1,0, 0,0,1,0 ]; ~reload.value; "K12 breakbeat irreg".postln; )
|
||||
|
||||
// --- K13 : amen break kick pattern (jungle classique) --------------
|
||||
( ~kickSteps = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ]; ~reload.value; "K13 amen break".postln; )
|
||||
|
||||
// --- K14 : gabber tres dense (kick partout) ------------------------
|
||||
( ~kickSteps = [ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 ]; ~reload.value; "K14 gabber dense".postln; )
|
||||
|
||||
// --- K15 : hardstyle (kick + reverse + tail simulee) ---------------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,1, 1,0,0,0, 1,1,0,0 ]; ~reload.value; "K15 hardstyle".postln; )
|
||||
|
||||
// --- K16 : techno minimaliste avec kick fantome --------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,1, 1,0,0,0 ]; ~reload.value; "K16 techno minimal".postln; )
|
||||
|
||||
// --- K17 : trance kick gros + ghost 16 ------------------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,1 ]; ~reload.value; "K17 trance".postln; )
|
||||
|
||||
// --- K18 : house 4/4 classique --------------------------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ]; ~reload.value; "K18 house".postln; )
|
||||
|
||||
// --- K19 : electro syncope ------------------------------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 0,0,0,0, 1,0,0,0, 0,0,1,0 ]; ~reload.value; "K19 electro".postln; )
|
||||
|
||||
// --- K20 : trip-hop lazy kick ---------------------------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0 ]; ~reload.value; "K20 trip-hop".postln; )
|
||||
|
||||
// --- K21 : jungle rapid breakbeat -----------------------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 0,1,0,0, 1,0,0,1, 0,1,0,0 ]; ~reload.value; "K21 jungle".postln; )
|
||||
|
||||
// --- K22 : reggae / dub one-drop (kick sur 3) -----------------------
|
||||
( ~kickSteps = [ 0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ]; ~reload.value; "K22 one-drop".postln; )
|
||||
|
||||
// --- K23 : afrobeat polyrythmique -----------------------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 0,1,0,0, 1,0,1,0, 0,1,0,0 ]; ~reload.value; "K23 afrobeat".postln; )
|
||||
|
||||
// --- K24 : garage 2-step --------------------------------------------
|
||||
( ~kickSteps = [ 1,0,0,0, 0,0,1,0, 0,0,0,0, 1,0,0,0 ]; ~reload.value; "K24 2-step".postln; )
|
||||
|
||||
// --- K25 : footwork / juke (160 BPM, kick triple) -------------------
|
||||
( ~kickSteps = [ 1,0,0,1, 1,0,0,0, 1,0,1,1, 0,0,1,0 ]; ~reload.value; "K25 footwork".postln; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// VARIATIONS DE TIMBRE (T1..T12)
|
||||
// =====================================================================
|
||||
|
||||
// --- T1 : kick rond (defaut) -- techno classique --------------------
|
||||
( ~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.32;
|
||||
~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~reload.value; "T1 rond".postln; )
|
||||
|
||||
// --- T2 : kick claquant -- snare-like, drive plus haut --------------
|
||||
( ~kickFreq = 65; ~kickPitchAmt = 4.0; ~kickDecay = 0.18;
|
||||
~kickDrive = 1.8; ~kickClick = 0.45;
|
||||
~reload.value; "T2 claquant".postln; )
|
||||
|
||||
// --- T3 : kick boomy -- queue longue, sub fort, peu de click --------
|
||||
( ~kickFreq = 48; ~kickPitchAmt = 2.5; ~kickDecay = 0.6;
|
||||
~kickDrive = 1.2; ~kickClick = 0.08;
|
||||
~reload.value; "T3 boomy".postln; )
|
||||
|
||||
// --- T4 : kick distordu -- gabber/hardcore --------------------------
|
||||
( ~kickFreq = 60; ~kickPitchAmt = 5.0; ~kickDecay = 0.28;
|
||||
~kickDrive = 3.5; ~kickClick = 0.3;
|
||||
~reload.value; "T4 distordu".postln; )
|
||||
|
||||
// --- T5 : kick sub deep -- pour dub / techno minimal ----------------
|
||||
( ~kickFreq = 42; ~kickPitchAmt = 2.0; ~kickDecay = 0.5;
|
||||
~kickDrive = 1.0; ~kickClick = 0.05;
|
||||
~reload.value; "T5 sub deep".postln; )
|
||||
|
||||
// --- T6 : kick punchy -- tres tight, snappy attack ------------------
|
||||
( ~kickFreq = 70; ~kickPitchAmt = 3.5; ~kickDecay = 0.22;
|
||||
~kickDrive = 2.0; ~kickClick = 0.35;
|
||||
~reload.value; "T6 punchy".postln; )
|
||||
|
||||
// --- T7 : clap-style (melange kick + snare body) -------------------
|
||||
( ~kickFreq = 75; ~kickPitchAmt = 4.5; ~kickDecay = 0.16;
|
||||
~kickDrive = 1.5; ~kickClick = 0.55;
|
||||
~reload.value; "T7 clap-style".postln; )
|
||||
|
||||
// --- T8 : 909 vintage (long decay, soft click) ---------------------
|
||||
( ~kickFreq = 52; ~kickPitchAmt = 2.8; ~kickDecay = 0.45;
|
||||
~kickDrive = 1.1; ~kickClick = 0.12;
|
||||
~reload.value; "T8 909 vintage".postln; )
|
||||
|
||||
// --- T9 : 808 boom (ultra sub, decay tres long) --------------------
|
||||
( ~kickFreq = 38; ~kickPitchAmt = 1.8; ~kickDecay = 0.85;
|
||||
~kickDrive = 1.0; ~kickClick = 0.04;
|
||||
~reload.value; "T9 808 boom".postln; )
|
||||
|
||||
// --- T10 : gabber distorded (drive max + click) --------------------
|
||||
( ~kickFreq = 62; ~kickPitchAmt = 5.5; ~kickDecay = 0.22;
|
||||
~kickDrive = 4.5; ~kickClick = 0.5;
|
||||
~reload.value; "T10 gabber distorded".postln; )
|
||||
|
||||
// --- T11 : breakcore (tres court, metallique) ---------------------
|
||||
( ~kickFreq = 80; ~kickPitchAmt = 4.0; ~kickDecay = 0.10;
|
||||
~kickDrive = 2.5; ~kickClick = 0.6;
|
||||
~reload.value; "T11 breakcore".postln; )
|
||||
|
||||
// --- T12 : dub kick (long sub tail, peu de click) ------------------
|
||||
( ~kickFreq = 40; ~kickPitchAmt = 1.5; ~kickDecay = 0.95;
|
||||
~kickDrive = 1.0; ~kickClick = 0.03;
|
||||
~reload.value; "T12 dub kick".postln; )
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,579 @@
|
||||
// =====================================================================
|
||||
// patterns_genre.scd -- Patterns rythmiques signature par genre
|
||||
// (issus de la deep recherche musicologique)
|
||||
//
|
||||
// Chaque preset charge kick/hat/snare/clap/perc en alignement
|
||||
// authentique au genre. Cmd+Entree = applique le pattern complet.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ACID TECHNO (135-150) -- 4-on-floor + hihat shuffle 16ths
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=55;~kickPitchAmt=3.0;~kickDecay=0.32;~kickDrive=1.4;~kickClick=0.22;
|
||||
~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~hatAmp = 0.13; // shuffle
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.35; // discret
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.30;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== ACID TECHNO 135-150 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// HARD TECHNO (140-148) -- kick punchy distorted + hat 16ths rapide
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq=60;~kickPitchAmt=4.5;~kickDecay=0.28;~kickDrive=3.0;~kickClick=0.32;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.14;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.5;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.4;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== HARD TECHNO 140-148 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// HYPNOTIC TECHNO (128-135) -- kick discret + ghost snare lointain
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.45;
|
||||
~kickFreq=50;~kickPitchAmt=2.5;~kickDecay=0.35;~kickDrive=1.0;~kickClick=0.08;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.06; // tres discret
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = [0,0,0,0, 0,0,0,1, 0,0,0,0, 0,0,1,0]; ~percAmp = 0.15; // ghost
|
||||
~reload.value; "=== HYPNOTIC TECHNO 128-135 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// DUBSTEP (140 half-time) -- kick on 1, snare on 3 (ressenti 70 BPM)
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq=48;~kickPitchAmt=3.5;~kickDecay=0.5;~kickDrive=1.5;~kickClick=0.15;
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~hatAmp = 0.10;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.55;
|
||||
~snareFreq=220;~snareNoiseAmt=0.7;~snareDecay=0.18;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== DUBSTEP 140 BPM half-time ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// UPLIFTING TRANCE (138) -- kick 4/4 + offbeat bass + clap 2&4
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=55;~kickPitchAmt=3.2;~kickDecay=0.28;~kickDrive=1.5;~kickClick=0.20;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.16;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.35;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== UPLIFTING TRANCE 138 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// DETROIT TECHNO (124) -- 909 swing 56% + ghost notes
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,1, 1,0,0,0]; ~kickAmp = 0.5; // ghost
|
||||
~kickFreq=52;~kickPitchAmt=2.8;~kickDecay=0.32;~kickDrive=1.3;~kickClick=0.16;
|
||||
~hatSteps = [0,1,1,0, 1,1,0,1, 0,1,1,0, 1,1,0,1]; ~hatAmp = 0.13; // shuffle
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~clapAmp = 0.32; // ghost claps
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== DETROIT TECHNO 124 BPM swing ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// LIQUID DNB (174) -- amen feel + ghost notes
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq=55;~kickPitchAmt=4.0;~kickDecay=0.18;~kickDrive=1.5;~kickClick=0.30;
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,1, 1,0,0,1]; ~snareAmp = 0.55;
|
||||
~snareFreq=240;~snareNoiseAmt=0.7;~snareDecay=0.10;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== LIQUID DNB 174 BPM amen ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// NEUROFUNK (174) -- breakbeat complex + 32th rolls
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,1]; ~kickAmp = 0.55;
|
||||
~kickFreq=58;~kickPitchAmt=4.5;~kickDecay=0.15;~kickDrive=2.0;~kickClick=0.4;
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1]; ~hatAmp = 0.14;
|
||||
~snareSteps = [0,0,0,1, 1,0,0,0, 0,1,0,0, 1,0,1,1]; ~snareAmp = 0.55;
|
||||
~snareFreq=260;~snareNoiseAmt=0.75;~snareDecay=0.08;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== NEUROFUNK DNB 174 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// FUTURE GARAGE (130-140) -- 2-step syncope, kick irregulier
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq=48;~kickPitchAmt=2.5;~kickDecay=0.5;~kickDrive=1.2;~kickClick=0.10;
|
||||
~hatSteps = [0,1,1,0, 1,1,0,1, 0,1,1,0, 1,1,0,1]; ~hatAmp = 0.10; // skippy
|
||||
~snareSteps = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,1,0,0]; ~snareAmp = 0.3; // sparse
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~clapAmp = 0.32;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== FUTURE GARAGE 2-STEP ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// HARDCORE GABBER (180) -- kick gabber distorted intense, hihat absent
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~kickAmp = 0.65;
|
||||
~kickFreq=60;~kickPitchAmt=5.0;~kickDecay=0.18;~kickDrive=4.0;~kickClick=0.35;
|
||||
~hatSteps = (0!16); ~hatAmp = 0;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== HARDCORE GABBER 180 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// PHONK (130 half-time) -- cowbell Memphis + 808 + trap hats
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,1, 1,0,0,0, 0,1,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=42;~kickPitchAmt=2.5;~kickDecay=0.6;~kickDrive=1.3;~kickClick=0.10;
|
||||
~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~hatAmp = 0.10; // trap triplets
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.3;
|
||||
~percInst = \cowbell; ~cowbellFreq = 800;
|
||||
~percSteps = [0,0,1,0, 0,1,0,0, 1,0,0,1, 0,0,1,0]; ~percAmp = 0.32;
|
||||
~reload.value; "=== PHONK 130 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// TRIBAL ETHNO (100-128) -- toms polyrhythm 3:4
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.45;
|
||||
~kickFreq=48;~kickPitchAmt=2.2;~kickDecay=0.4;~kickDrive=1.1;~kickClick=0.08;
|
||||
~hatSteps = [0,0,1,0, 0,0,0,1, 0,0,1,0, 0,1,0,0]; ~hatAmp = 0.08; // organique
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \tom; ~tomFreq = 90;
|
||||
~percSteps = [1,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0]; ~percAmp = 0.4;
|
||||
~reload.value; "=== TRIBAL ETHNO 100 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// AMBIENT CINEMATIC (60-80) -- percussions ultra rares + tom solitaire
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = (0!16); ~kickAmp = 0;
|
||||
~hatSteps = (0!16);
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \tom; ~tomFreq = 60;
|
||||
~percSteps = [1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; ~percAmp = 0.3;
|
||||
~reload.value; "=== AMBIENT CINEMATIC -- pas de kick ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// CHIPTUNE 8-BIT (150) -- kick triangle sharp, noise burst
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.45;
|
||||
~kickFreq=80;~kickPitchAmt=4.5;~kickDecay=0.12;~kickDrive=1.4;~kickClick=0.5; // chip kick
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~hatAmp = 0.12;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.40;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== CHIPTUNE 8-BIT 150 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// SYNTHWAVE 80s (100) -- kick + LinnDrum gated snare + hat 8ths
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq=55;~kickPitchAmt=3.0;~kickDecay=0.3;~kickDrive=1.2;~kickClick=0.18;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5; // gated
|
||||
~snareFreq=180;~snareNoiseAmt=0.55;~snareDecay=0.20;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.30; // doubl
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== SYNTHWAVE 100 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// INDUSTRIAL TECHNO (140-160) -- kick hard distorded + metal hits
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq=60;~kickPitchAmt=5.0;~kickDecay=0.28;~kickDrive=3.5;~kickClick=0.4;
|
||||
~hatSteps = [0,1,0,1, 1,1,0,1, 0,1,0,1, 1,1,0,1]; ~hatAmp = 0.13; // breakbeat
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.55;
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~percAmp = 0.4;
|
||||
~reload.value; "=== INDUSTRIAL TECHNO ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// DUB TECHNO (126-130) -- kick muffle + clap echo dub
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.45;
|
||||
~kickFreq=48;~kickPitchAmt=2.3;~kickDecay=0.45;~kickDrive=1.0;~kickClick=0.06; // muffled
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.06;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 0,1,0,0, 0,0,0,0, 0,1,0,0]; ~clapAmp = 0.25; // delay
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== DUB TECHNO 126 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// GLITCH IDM (variable) -- patterns generes aleatoires
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = ~genKickPattern.(0.4);
|
||||
~snareSteps = ~genKickPattern.(0.3);
|
||||
~hatSteps = ~genKickPattern.(0.7);
|
||||
~clapSteps = ~genKickPattern.(0.2);
|
||||
~percSteps = ~genKickPattern.(0.4);
|
||||
~kickFreq=55;~kickPitchAmt=3.5;~kickDecay=0.18;~kickDrive=2.0;~kickClick=0.3;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.12; ~snareAmp = 0.45; ~clapAmp = 0.3; ~percAmp = 0.3;
|
||||
~reload.value; "=== GLITCH IDM random ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// DRONE DOOM (60) -- kick massif espace + crash long
|
||||
// =====================================================================
|
||||
(
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq=40;~kickPitchAmt=2.0;~kickDecay=0.8;~kickDrive=2.0;~kickClick=0.04;
|
||||
~hatSteps = (0!16);
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \tom; ~tomFreq = 50;
|
||||
~percSteps = [1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; ~percAmp = 0.4;
|
||||
~reload.value; "=== DRONE DOOM 60 BPM ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ===== 21 GENRES SUPPLEMENTAIRES (deuxieme batch) =================
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// HARD TECHNO BERLIN (140-145) -- 4/4 hard kick + open hat sustain
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 142; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.62;
|
||||
~kickFreq=62;~kickPitchAmt=4.8;~kickDecay=0.26;~kickDrive=3.2;~kickClick=0.36;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.5;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.40;
|
||||
~percInst = \openHat; ~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~percAmp = 0.20;
|
||||
~reload.value; "=== HARD TECHNO BERLIN 142 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// ACID HOUSE 88 BPM (Chicago classique)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 88; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.50;
|
||||
~kickFreq=50;~kickPitchAmt=2.8;~kickDecay=0.38;~kickDrive=1.2;~kickClick=0.10;
|
||||
~hatSteps = [0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1]; ~hatAmp = 0.12;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.34;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== ACID HOUSE 88 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// TRANCE 138 UPLIFTING (variation grand kick + clap reverb)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 138; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.58;
|
||||
~kickFreq=55;~kickPitchAmt=3.5;~kickDecay=0.30;~kickDrive=1.6;~kickClick=0.22;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.42;
|
||||
~percSteps = [0,0,0,0, 0,0,0,1, 0,0,0,0, 0,0,0,1]; ~percAmp = 0.18;
|
||||
~percInst = \rim;
|
||||
~reload.value; "=== TRANCE 138 UPLIFTING (V2) ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// PSY TRANCE 145 (basse offbeat + kick punchy + hat dense)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 145; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq=58;~kickPitchAmt=4.0;~kickDecay=0.22;~kickDrive=1.8;~kickClick=0.28;
|
||||
~hatSteps = [0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1]; ~hatAmp = 0.16;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~percAmp = 0.25;
|
||||
~reload.value; "=== PSY TRANCE 145 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// GOA TRANCE 145 (psy roots, 16th notes acid)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 145; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=56;~kickPitchAmt=3.5;~kickDecay=0.25;~kickDrive=1.5;~kickClick=0.22;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \tom; ~tomFreq = 100;
|
||||
~percSteps = [0,0,1,0, 0,1,0,0, 1,0,0,1, 0,0,1,0]; ~percAmp = 0.30;
|
||||
~reload.value; "=== GOA TRANCE 145 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// HARDSTYLE 150 (kick gabber + reverse kick simulee + clap large)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 150; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,1, 1,0,0,0, 1,1,0,0]; ~kickAmp = 0.65;
|
||||
~kickFreq=62;~kickPitchAmt=5.5;~kickDecay=0.30;~kickDrive=4.0;~kickClick=0.45;
|
||||
~hatSteps = [0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.55;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.45;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== HARDSTYLE 150 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// HANDS UP TRANCE 150 (eurodance moderne, clap large)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 150; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=58;~kickPitchAmt=3.8;~kickDecay=0.26;~kickDrive=1.6;~kickClick=0.25;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.20;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.5;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.45;
|
||||
~percInst = \openHat; ~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~percAmp = 0.22;
|
||||
~reload.value; "=== HANDS UP TRANCE 150 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// LIQUID DNB 174 (alt) -- amen smooth + ghost note + open hat
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 174; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq=52;~kickPitchAmt=3.5;~kickDecay=0.20;~kickDrive=1.3;~kickClick=0.25;
|
||||
~hatSteps = [1,0,1,1, 0,1,0,1, 1,0,1,1, 0,1,0,1]; ~hatAmp = 0.11;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.45;
|
||||
~snareFreq=220;~snareNoiseAmt=0.55;~snareDecay=0.13;
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \openHat; ~percSteps = [0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.18;
|
||||
~reload.value; "=== LIQUID DNB 174 BPM (V2) ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// NEUROFUNK DNB 174 (alt) -- snare reese + breakbeat hard
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 174; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,1, 0,0,1,0, 0,0,1,1, 1,0,0,0]; ~kickAmp = 0.6;
|
||||
~kickFreq=60;~kickPitchAmt=4.8;~kickDecay=0.14;~kickDrive=2.2;~kickClick=0.42;
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,0,1, 1,1,1,0]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,1, 1,0,0,0, 0,1,0,0, 1,0,1,1]; ~snareAmp = 0.6;
|
||||
~snareFreq=270;~snareNoiseAmt=0.8;~snareDecay=0.07;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== NEUROFUNK DNB 174 BPM (V2) ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// JUNGLE 165 (chopped breakbeat + ragga rim)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 165; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,1, 0,1,0,0, 1,0,0,1, 0,1,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=55;~kickPitchAmt=3.5;~kickDecay=0.20;~kickDrive=1.6;~kickClick=0.32;
|
||||
~hatSteps = [1,1,0,1, 1,0,1,1, 1,1,0,1, 1,0,1,1]; ~hatAmp = 0.12;
|
||||
~snareSteps = [0,0,0,0, 1,0,1,0, 0,0,0,1, 1,0,0,1]; ~snareAmp = 0.55;
|
||||
~snareFreq=220;~snareNoiseAmt=0.7;~snareDecay=0.10;
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,1,0,0, 0,0,1,0, 0,1,0,0]; ~percAmp = 0.30;
|
||||
~reload.value; "=== JUNGLE 165 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// DRUM & BASS JUMP-UP 174 (kick funky + snare bouncy)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 174; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 0,1,1,0, 0,0,1,0, 0,1,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=58;~kickPitchAmt=4.2;~kickDecay=0.18;~kickDrive=1.8;~kickClick=0.35;
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.55;
|
||||
~snareFreq=240;~snareNoiseAmt=0.7;~snareDecay=0.10;
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== DNB JUMP-UP 174 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// FUTURE BASS 150 (half-time, snare large, hat trap)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 150; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=48;~kickPitchAmt=3.0;~kickDecay=0.45;~kickDrive=1.4;~kickClick=0.15;
|
||||
~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~hatAmp = 0.10;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~snareAmp = 0.55;
|
||||
~snareFreq=210;~snareNoiseAmt=0.6;~snareDecay=0.20;
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,0,1, 0,0,1,0, 0,0,0,1]; ~percAmp = 0.18;
|
||||
~reload.value; "=== FUTURE BASS 150 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// DEEP HOUSE 122 (kick warm + clap soft + hat shuffled)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 122; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.50;
|
||||
~kickFreq=48;~kickPitchAmt=2.5;~kickDecay=0.40;~kickDrive=1.1;~kickClick=0.10;
|
||||
~hatSteps = [0,1,1,0, 1,1,0,1, 0,1,1,0, 1,1,0,1]; ~hatAmp = 0.10;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.30;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.16;
|
||||
~reload.value; "=== DEEP HOUSE 122 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// TECH HOUSE 126 (groove tight + hat 16th + clap tight)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 126; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=52;~kickPitchAmt=2.8;~kickDecay=0.32;~kickDrive=1.3;~kickClick=0.18;
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~hatAmp = 0.15;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.34;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,0, 0,0,0,1, 0,0,1,0, 0,0,0,1]; ~percAmp = 0.22;
|
||||
~reload.value; "=== TECH HOUSE 126 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// PROGRESSIVE HOUSE 124 (kick pad + clap echo + hat air)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 124; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.52;
|
||||
~kickFreq=50;~kickPitchAmt=2.6;~kickDecay=0.36;~kickDrive=1.2;~kickClick=0.12;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.15;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,1, 1,0,0,0]; ~clapAmp = 0.32;
|
||||
~percInst = \openHat; ~percSteps = [0,0,1,0, 0,0,0,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.20;
|
||||
~reload.value; "=== PROGRESSIVE HOUSE 124 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// TRIBAL TECHNO 130 (toms layered + kick warm + percussions dense)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 130; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.50;
|
||||
~kickFreq=50;~kickPitchAmt=2.6;~kickDecay=0.34;~kickDrive=1.2;~kickClick=0.12;
|
||||
~hatSteps = [0,0,1,0, 0,1,0,1, 0,0,1,0, 0,1,0,1]; ~hatAmp = 0.10;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \tom; ~tomFreq = 95;
|
||||
~percSteps = [1,0,0,1, 0,1,1,0, 1,0,0,1, 0,1,1,0]; ~percAmp = 0.40;
|
||||
~reload.value; "=== TRIBAL TECHNO 130 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// INDUSTRIAL 145 (alt sombre, perc clang)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 145; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 1,0,1,0, 1,0,0,0, 1,0,1,0]; ~kickAmp = 0.62;
|
||||
~kickFreq=62;~kickPitchAmt=5.2;~kickDecay=0.28;~kickDrive=3.8;~kickClick=0.42;
|
||||
~hatSteps = [0,1,0,1, 1,1,0,1, 0,1,0,1, 1,1,0,1]; ~hatAmp = 0.13;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.55;
|
||||
~snareFreq=270;~snareNoiseAmt=0.85;~snareDecay=0.08;
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \rim; ~percSteps = [1,0,0,1, 1,0,1,0, 1,0,0,1, 1,0,1,1]; ~percAmp = 0.45;
|
||||
~reload.value; "=== INDUSTRIAL 145 BPM (V2) ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// BREAKCORE 200+ (kick hyperdense + breakbeat + snare metallic)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 200; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,1,0,1, 1,0,1,1, 0,1,1,1, 1,1,0,1]; ~kickAmp = 0.55;
|
||||
~kickFreq=80;~kickPitchAmt=4.0;~kickDecay=0.10;~kickDrive=2.5;~kickClick=0.6;
|
||||
~hatSteps = [1,1,1,1, 1,0,1,1, 1,1,0,1, 1,1,1,1]; ~hatAmp = 0.12;
|
||||
~snareSteps = [0,1,0,1, 0,0,1,1, 1,0,0,1, 0,1,1,0]; ~snareAmp = 0.55;
|
||||
~snareFreq=290;~snareNoiseAmt=0.85;~snareDecay=0.06;
|
||||
~clapSteps = [0,0,1,0, 0,1,0,0, 0,0,1,0, 0,1,0,0]; ~clapAmp = 0.30;
|
||||
~percSteps = (0!16);
|
||||
~reload.value; "=== BREAKCORE 200 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// FOOTWORK 160 (juke triplet kick + clap stutter)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 160; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,1, 1,0,0,0, 1,0,1,1, 0,0,1,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=42;~kickPitchAmt=2.4;~kickDecay=0.50;~kickDrive=1.3;~kickClick=0.10;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~snareSteps = (0!16);
|
||||
~clapSteps = [0,0,0,1, 1,0,0,0, 0,0,0,1, 1,0,0,0]; ~clapAmp = 0.32;
|
||||
~percInst = \rim; ~percSteps = [0,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,0,1]; ~percAmp = 0.22;
|
||||
~reload.value; "=== FOOTWORK 160 BPM ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// IDM (intelligent dance music, variable, glitchy random)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 130; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = ~genKickPattern.(0.35);
|
||||
~snareSteps = ~genKickPattern.(0.25);
|
||||
~hatSteps = ~genKickPattern.(0.65);
|
||||
~clapSteps = ~genKickPattern.(0.18);
|
||||
~percSteps = ~genKickPattern.(0.40);
|
||||
~kickFreq=55;~kickPitchAmt=3.2;~kickDecay=0.22;~kickDrive=1.8;~kickClick=0.28;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.12; ~snareAmp = 0.45; ~clapAmp = 0.28; ~percAmp = 0.30;
|
||||
~reload.value; "=== IDM (random) ===".postln;
|
||||
)
|
||||
|
||||
// =====================================================================
|
||||
// GLITCH HOP 110 (half-time hip-hop + glitch perc)
|
||||
// =====================================================================
|
||||
(
|
||||
~bpm = 110; TempoClock.default.tempo = ~bpm/60;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,1, 0,0,1,0, 0,1,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq=45;~kickPitchAmt=2.5;~kickDecay=0.45;~kickDrive=1.3;~kickClick=0.15;
|
||||
~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~hatAmp = 0.11;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.50;
|
||||
~snareFreq=220;~snareNoiseAmt=0.6;~snareDecay=0.12;
|
||||
~clapSteps = (0!16);
|
||||
~percInst = \rim; ~percSteps = ~genKickPattern.(0.5); ~percAmp = 0.25;
|
||||
~reload.value; "=== GLITCH HOP 110 BPM ===".postln;
|
||||
)
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
// =====================================================================
|
||||
// percussions.scd
|
||||
// ~25 patterns clap + perc + ~12 timbres perc selectionnable
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur un bloc pour l'appliquer.
|
||||
//
|
||||
// SynthDef percussion disponibles dans engine.scd :
|
||||
// \rim, \cowbell, \tom, \openHat
|
||||
// (\crash existe aussi mais hors selecteur ~percInst standard)
|
||||
// SynthDef percussion bonus dans synthdefs/authentic.scd :
|
||||
// \taiko, \tabla (utilisable via ~percInst = \taiko;)
|
||||
//
|
||||
// Storage :
|
||||
// ~clC1..~clC12 = patterns clap
|
||||
// ~pcP1..~pcP15 = patterns perc generale
|
||||
// Util par sequences.scd pour sequencer les changements automatiques.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// STOCKAGE -- evaluer ce bloc une fois pour enregistrer toutes les
|
||||
// variables reutilisables.
|
||||
// =====================================================================
|
||||
(
|
||||
// --- Patterns clap (~clC1..~clC12) ----------------------------------
|
||||
~clC1 = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; // backbeat 2 et 4
|
||||
~clC2 = [0,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,0,0]; // techno minimal : 4 seul
|
||||
~clC3 = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; // offbeat (entre beats)
|
||||
~clC4 = [1,1,1,0, 0,0,0,0, 1,1,1,0, 0,0,0,0]; // roll/flam (3 claps)
|
||||
~clC5 = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,0,1]; // house ghost
|
||||
~clC6 = [0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; // dubstep gros (sur 3)
|
||||
~clC7 = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; // trance fort 2/4
|
||||
~clC8 = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; // reggae 1 et 3
|
||||
~clC9 = [0,0,0,0, 1,0,0,0, 0,0,0,1, 1,0,0,0]; // garage shuffled
|
||||
~clC10 = [0,0,1,0, 1,0,0,1, 0,0,1,0, 1,0,0,1]; // dense funk
|
||||
~clC11 = [0,0,0,1, 1,0,0,0, 0,0,0,1, 1,0,0,0]; // stutter trap
|
||||
~clC12 = (0 ! 16); // mute
|
||||
|
||||
// --- Patterns perc generale (~pcP1..~pcP15) -------------------------
|
||||
~pcP1 = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; // offbeat techno
|
||||
~pcP2 = [1,0,1,1, 0,0,1,0, 1,1,0,1, 0,1,1,0]; // trap ghosts
|
||||
~pcP3 = [1,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0]; // tribal congas
|
||||
~pcP4 = [1,0,0,1, 0,0,1,0, 0,0,1,0, 0,0,0,0]; // clave 3-2
|
||||
~pcP5 = [0,0,1,0, 0,0,1,0, 1,0,0,1, 0,0,1,0]; // clave 2-3
|
||||
~pcP6 = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; // tambourine 8th
|
||||
~pcP7 = [1,0,0,0, 0,1,0,0, 1,0,0,1, 0,1,0,0]; // cowbell tribal
|
||||
~pcP8 = [0,0,1,0, 0,1,0,0, 0,0,1,0, 0,1,0,0]; // rim shot offbeat
|
||||
~pcP9 = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; // open hat techno
|
||||
~pcP10 = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; // closed hat 16th
|
||||
~pcP11 = [1,1,0,1, 1,0,1,1, 0,1,1,1, 1,1,0,1]; // shaker rapide
|
||||
~pcP12 = [1,0,1,0, 0,1,0,1, 1,0,0,1, 0,1,0,1]; // bongo polyrythme
|
||||
~pcP13 = [0,0,0,0, 0,0,0,0, 0,0,0,0, 1,1,1,1]; // tom roll fill
|
||||
~pcP14 = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; // perc sur le beat
|
||||
~pcP15 = (0 ! 16); // mute
|
||||
"=== percussions : 12 claps + 15 perc patterns stockes ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// CLAP PATTERNS (blocs auto-applicants)
|
||||
// =====================================================================
|
||||
|
||||
// --- C1 : clap backbeat (5+13) ---- classique ------------------------
|
||||
( ~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.35;
|
||||
~reload.value; "C1 clap backbeat 2/4".postln; )
|
||||
|
||||
// --- C2 : clap techno minimal (sur 4 seul) --------------------------
|
||||
( ~clapSteps = [0,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.4;
|
||||
~reload.value; "C2 clap minimal sur 4".postln; )
|
||||
|
||||
// --- C3 : clap offbeat (entre les beats) ----------------------------
|
||||
( ~clapSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~clapAmp = 0.3;
|
||||
~reload.value; "C3 clap offbeat".postln; )
|
||||
|
||||
// --- C4 : clap roll/flam (3 claps rapides) --------------------------
|
||||
( ~clapSteps = [1,1,1,0, 0,0,0,0, 1,1,1,0, 0,0,0,0]; ~clapAmp = 0.32;
|
||||
~reload.value; "C4 clap roll/flam".postln; )
|
||||
|
||||
// --- C5 : clap house ghost (2/4 + ghost) ----------------------------
|
||||
( ~clapSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,0,1]; ~clapAmp = 0.34;
|
||||
~reload.value; "C5 clap house".postln; )
|
||||
|
||||
// --- C6 : clap dubstep (sur 3, gros) --------------------------------
|
||||
( ~clapSteps = [0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~clapAmp = 0.5;
|
||||
~reload.value; "C6 clap dubstep".postln; )
|
||||
|
||||
// --- C7 : clap trance (fort 2 et 4) ---------------------------------
|
||||
( ~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.42;
|
||||
~reload.value; "C7 clap trance".postln; )
|
||||
|
||||
// --- C8 : clap reggae (sur 1 et 3) ----------------------------------
|
||||
( ~clapSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~clapAmp = 0.30;
|
||||
~reload.value; "C8 clap reggae".postln; )
|
||||
|
||||
// --- Clap mute ------------------------------------------------------
|
||||
( ~clapSteps = (0 ! 16); ~reload.value; "clap mute".postln; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// SELECTEUR D'INSTRUMENT PERC (~percInst)
|
||||
// SynthDef disponibles : \rim \cowbell \tom \openHat
|
||||
// Bonus si authentic.scd charge : \taiko, \tabla
|
||||
// =====================================================================
|
||||
|
||||
( ~percInst = \rim; ~reload.value; "perc = rim".postln; )
|
||||
( ~percInst = \cowbell; ~reload.value; "perc = cowbell".postln; )
|
||||
( ~percInst = \tom; ~reload.value; "perc = tom".postln; )
|
||||
( ~percInst = \openHat; ~reload.value; "perc = openHat".postln; )
|
||||
// --- Bonus (si synthdefs/authentic.scd evalue) -----------------------
|
||||
( ~percInst = \taiko; ~reload.value; "perc = taiko (authentic)".postln; )
|
||||
( ~percInst = \tabla; ~reload.value; "perc = tabla (authentic)".postln; )
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// PATTERNS PERCUSSION GENERALE (utilise ~percInst courant)
|
||||
// =====================================================================
|
||||
|
||||
// --- P1 : offbeat techno (defaut) -----------------------------------
|
||||
( ~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~percAmp = 0.25;
|
||||
~reload.value; "P1 perc offbeat".postln; )
|
||||
|
||||
// --- P2 : trap ghosts ----------------------------------------------
|
||||
( ~percSteps = [1,0,1,1, 0,0,1,0, 1,1,0,1, 0,1,1,0]; ~percAmp = 0.18;
|
||||
~reload.value; "P2 perc trap ghosts".postln; )
|
||||
|
||||
// --- P3 : tribal congas (utiliser ~percInst = \tom) ----------------
|
||||
( ~percInst = \tom; ~tomFreq = 90;
|
||||
~percSteps = [1,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0]; ~percAmp = 0.4;
|
||||
~reload.value; "P3 tribal congas (tom)".postln; )
|
||||
|
||||
// --- P4 : clave 3-2 (afro-cubain classique) ------------------------
|
||||
( ~percInst = \rim;
|
||||
~percSteps = [1,0,0,1, 0,0,1,0, 0,0,1,0, 0,0,0,0]; ~percAmp = 0.35;
|
||||
~reload.value; "P4 clave 3-2 (rim)".postln; )
|
||||
|
||||
// --- P5 : clave 2-3 (variation) ------------------------------------
|
||||
( ~percInst = \rim;
|
||||
~percSteps = [0,0,1,0, 0,0,1,0, 1,0,0,1, 0,0,1,0]; ~percAmp = 0.35;
|
||||
~reload.value; "P5 clave 2-3 (rim)".postln; )
|
||||
|
||||
// --- P6 : tambourine sur 8th notes ---------------------------------
|
||||
( ~percInst = \rim;
|
||||
~percSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~percAmp = 0.22;
|
||||
~reload.value; "P6 tambourine 8th".postln; )
|
||||
|
||||
// --- P7 : cowbell tribal -------------------------------------------
|
||||
( ~percInst = \cowbell; ~cowbellFreq = 800;
|
||||
~percSteps = [1,0,0,0, 0,1,0,0, 1,0,0,1, 0,1,0,0]; ~percAmp = 0.32;
|
||||
~reload.value; "P7 cowbell tribal".postln; )
|
||||
|
||||
// --- P8 : rim shot offbeat -----------------------------------------
|
||||
( ~percInst = \rim;
|
||||
~percSteps = [0,0,1,0, 0,1,0,0, 0,0,1,0, 0,1,0,0]; ~percAmp = 0.30;
|
||||
~reload.value; "P8 rim offbeat".postln; )
|
||||
|
||||
// --- P9 : open hat sur offbeat (techno) ----------------------------
|
||||
( ~percInst = \openHat;
|
||||
~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~percAmp = 0.25;
|
||||
~reload.value; "P9 openHat offbeat".postln; )
|
||||
|
||||
// --- P10 : closed hat 16th (perc layer) ----------------------------
|
||||
( ~percInst = \rim;
|
||||
~percSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~percAmp = 0.12;
|
||||
~reload.value; "P10 hat 16th (rim layer)".postln; )
|
||||
|
||||
// --- P11 : shaker rapide -------------------------------------------
|
||||
( ~percInst = \rim;
|
||||
~percSteps = [1,1,0,1, 1,0,1,1, 0,1,1,1, 1,1,0,1]; ~percAmp = 0.15;
|
||||
~reload.value; "P11 shaker rapide (rim)".postln; )
|
||||
|
||||
// --- P12 : bongo polyrythme (3:4 contre kick) ----------------------
|
||||
( ~percInst = \tom; ~tomFreq = 110;
|
||||
~percSteps = [1,0,1,0, 0,1,0,1, 1,0,0,1, 0,1,0,1]; ~percAmp = 0.32;
|
||||
~reload.value; "P12 bongo polyrythme (tom)".postln; )
|
||||
|
||||
// --- P13 : tom roll fill (4 dernieres steps) -----------------------
|
||||
( ~percInst = \tom; ~tomFreq = 100;
|
||||
~percSteps = [0,0,0,0, 0,0,0,0, 0,0,0,0, 1,1,1,1]; ~percAmp = 0.45;
|
||||
~reload.value; "P13 tom roll fill".postln; )
|
||||
|
||||
// --- P14 : perc sur le beat (renforce kick) ------------------------
|
||||
( ~percInst = \cowbell; ~cowbellFreq = 600;
|
||||
~percSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~percAmp = 0.20;
|
||||
~reload.value; "P14 perc on beat".postln; )
|
||||
|
||||
// --- Perc mute -----------------------------------------------------
|
||||
( ~percSteps = (0 ! 16); ~reload.value; "perc mute".postln; )
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,578 @@
|
||||
// =====================================================================
|
||||
// sequences.scd -- Sequences de patterns automatiques (macros temps)
|
||||
//
|
||||
// CONCEPT
|
||||
// Une sequence est une Routine qui change ~kickSteps / ~melodyNotes /
|
||||
// etc. a intervalles reguliers. 1 step = ~stepDur (defaut 0.25 = 1/16).
|
||||
// Donc 16 steps = 1 mesure 4/4 a 0.25 dur.
|
||||
//
|
||||
// PREREQUIS
|
||||
// engine.scd evalue (definit ~kickSteps, ~reload, etc.).
|
||||
// palette/kicks.scd evalue le bloc STOCKAGE pour avoir ~kK1..~kK25.
|
||||
// palette/percussions.scd evalue le bloc STOCKAGE pour ~clC*, ~pcP*.
|
||||
//
|
||||
// HELPERS exposes
|
||||
// ~seqPlay.(actions) joue [[steps, action], ...]
|
||||
// ~seqStop.() stoppe la sequence courante
|
||||
// ~seqLoop.(actions, repeats) enchaine actions en boucle N fois
|
||||
// ~seqEvolve.(steps, mutator) mute progressivement toutes N steps
|
||||
// ~beatChainPlay.(presets) enchaine plusieurs presets nommes
|
||||
// ~stepDur duree d'un step (defaut 0.25)
|
||||
//
|
||||
// SEQUENCES PRE-CONSTRUITES (~seqXxx.())
|
||||
// seqIntro seqBuildup seqBreakdown seqDrop
|
||||
// seqOutro seqTechnoLoop seqAcidEvolve seqDubstepDrop
|
||||
// seqTrance16 seqDnBSwitch seqHipHopLoop seqWorldEvolve
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// HELPERS DE BASE -- evaluer ce bloc une fois pour exposer les helpers
|
||||
// =====================================================================
|
||||
(
|
||||
~stepDur = 0.25; // duree d'un step en battement (1/16 a 4/4)
|
||||
~currentSeq = nil; // Routine en cours
|
||||
|
||||
|
||||
// --- ~seqPlay.([[steps, action], ...]) ------------------------------
|
||||
// Joue une suite d'actions a intervalles donnes en steps.
|
||||
// Stoppe toute sequence precedente avant de demarrer.
|
||||
~seqPlay = { |actions|
|
||||
~seqStop.value;
|
||||
~currentSeq = Routine({
|
||||
actions.do { |entry|
|
||||
var steps = entry[0];
|
||||
var action = entry[1];
|
||||
action.value;
|
||||
(steps * ~stepDur).wait;
|
||||
};
|
||||
~currentSeq = nil;
|
||||
}).play(TempoClock.default);
|
||||
"=== seqPlay : % steps en cours ===".format(actions.collect(_[0]).sum).postln;
|
||||
};
|
||||
|
||||
|
||||
// --- ~seqStop.() ----------------------------------------------------
|
||||
~seqStop = {
|
||||
~currentSeq !? { ~currentSeq.stop; ~currentSeq = nil; "=== seqStop ===".postln };
|
||||
};
|
||||
|
||||
|
||||
// --- ~seqLoop.(actions, repeats) ------------------------------------
|
||||
// Enchaine la liste d'actions en boucle N fois (defaut 1).
|
||||
~seqLoop = { |actions, repeats = 1|
|
||||
var expanded = Array.new(actions.size * repeats);
|
||||
repeats.do { actions.do { |a| expanded.add(a) } };
|
||||
~seqPlay.value(expanded);
|
||||
"=== seqLoop : % cycles ===".format(repeats).postln;
|
||||
};
|
||||
|
||||
|
||||
// --- ~seqEvolve.(steps, mutator) ------------------------------------
|
||||
// Appelle 'mutator' en boucle toutes les 'steps' steps. La routine
|
||||
// tourne jusqu'a seqStop.
|
||||
~seqEvolve = { |stepsBetween = 16, mutator|
|
||||
~seqStop.value;
|
||||
~currentSeq = Routine({
|
||||
inf.do { |i|
|
||||
mutator.value(i);
|
||||
(stepsBetween * ~stepDur).wait;
|
||||
};
|
||||
}).play(TempoClock.default);
|
||||
"=== seqEvolve : mutator chaque % steps ===".format(stepsBetween).postln;
|
||||
};
|
||||
|
||||
|
||||
// --- ~beatChainPlay.(presets) ---------------------------------------
|
||||
// Enchaine plusieurs presets sous forme de [stepsToHold, action].
|
||||
// Equivalent a ~seqPlay mais sucre syntaxique pour chains de drumkits.
|
||||
~beatChainPlay = { |presets|
|
||||
~seqPlay.value(presets);
|
||||
};
|
||||
|
||||
"=== sequences helpers : ~seqPlay ~seqStop ~seqLoop ~seqEvolve ~beatChainPlay ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// SEQUENCES PRE-CONSTRUITES
|
||||
// Evaluer chaque bloc pour DEFINIR la sequence (variable ~seqXxx).
|
||||
// Ensuite l'invoquer : ~seqIntro.value
|
||||
// =====================================================================
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqIntro -- monte progressive sur 64 steps (4 mesures)
|
||||
// mesure 1 : kick seul
|
||||
// mesure 2 : kick + hat
|
||||
// mesure 3 : kick + hat + clap
|
||||
// mesure 4 : tout (kick + hat + clap + perc)
|
||||
// =====================================================================
|
||||
(
|
||||
~seqIntro = {
|
||||
~seqPlay.value([
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~hatSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~reload.value;
|
||||
"intro 1/4 : kick seul".postln;
|
||||
}],
|
||||
[16, {
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~reload.value;
|
||||
"intro 2/4 : + hat".postln;
|
||||
}],
|
||||
[16, {
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~clapAmp = 0.35;
|
||||
~reload.value;
|
||||
"intro 3/4 : + clap".postln;
|
||||
}],
|
||||
[16, {
|
||||
~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~percAmp = 0.25;
|
||||
~reload.value;
|
||||
"intro 4/4 : tout".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqIntro defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqBuildup -- crescendo trance (riser + cutoff sweep + clap denser)
|
||||
// Argument optionnel : duree totale en mesures (defaut 4)
|
||||
// =====================================================================
|
||||
(
|
||||
~seqBuildup = { |bars = 4|
|
||||
var stepsPerBar = 16;
|
||||
~seqPlay.value([
|
||||
[stepsPerBar, {
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~clapAmp = 0.30;
|
||||
~reload.value;
|
||||
"buildup 1: hat + clap".postln;
|
||||
}],
|
||||
[stepsPerBar, {
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0];
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,1,0, 1,0,0,0];
|
||||
~clapAmp = 0.36;
|
||||
~reload.value;
|
||||
"buildup 2: hat 8th + clap dense".postln;
|
||||
}],
|
||||
[stepsPerBar, {
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~clapSteps = [0,0,1,0, 1,0,1,0, 0,1,0,1, 1,0,1,0];
|
||||
~clapAmp = 0.40;
|
||||
~reload.value;
|
||||
"buildup 3: hat 16th + clap dense".postln;
|
||||
}],
|
||||
[stepsPerBar * (bars - 3).max(1), {
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~snareSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~snareAmp = 0.5;
|
||||
~reload.value;
|
||||
"buildup 4: snare roll TENSION".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqBuildup defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqBreakdown -- reduit a melody seule, puis revient
|
||||
// =====================================================================
|
||||
(
|
||||
~seqBreakdown = {
|
||||
var saveKick, saveHat, saveClap, savePerc, saveSnare;
|
||||
saveKick = ~kickSteps.copy;
|
||||
saveHat = ~hatSteps.copy;
|
||||
saveClap = ~clapSteps.copy;
|
||||
savePerc = ~percSteps.copy;
|
||||
saveSnare = ~snareSteps.copy;
|
||||
~seqPlay.value([
|
||||
[32, {
|
||||
~kickSteps = (0!16);
|
||||
~hatSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~snareSteps = (0!16);
|
||||
~reload.value;
|
||||
"breakdown : melody seule".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = saveKick;
|
||||
~hatSteps = saveHat;
|
||||
~clapSteps = saveClap;
|
||||
~percSteps = savePerc;
|
||||
~snareSteps = saveSnare;
|
||||
~reload.value;
|
||||
"breakdown : retour".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqBreakdown defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqDrop -- 4 steps silence + 1 step impact + reprise
|
||||
// =====================================================================
|
||||
(
|
||||
~seqDrop = {
|
||||
var saveKick, saveHat, saveClap, savePerc, saveSnare;
|
||||
saveKick = ~kickSteps.copy;
|
||||
saveHat = ~hatSteps.copy;
|
||||
saveClap = ~clapSteps.copy;
|
||||
savePerc = ~percSteps.copy;
|
||||
saveSnare = ~snareSteps.copy;
|
||||
~seqPlay.value([
|
||||
[4, {
|
||||
~kickSteps = (0!16);
|
||||
~hatSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~snareSteps = (0!16);
|
||||
~reload.value;
|
||||
"drop : SILENCE".postln;
|
||||
}],
|
||||
[1, {
|
||||
// impact one-shot via clap fort
|
||||
~clapSteps = [1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
|
||||
~clapAmp = 0.7;
|
||||
~reload.value;
|
||||
"drop : IMPACT".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = saveKick;
|
||||
~hatSteps = saveHat;
|
||||
~clapSteps = saveClap; ~clapAmp = 0.35;
|
||||
~percSteps = savePerc;
|
||||
~snareSteps = saveSnare;
|
||||
~reload.value;
|
||||
"drop : DROP !!!".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqDrop defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqOutro -- fade-out progressif sur 32 steps (2 mesures)
|
||||
// =====================================================================
|
||||
(
|
||||
~seqOutro = {
|
||||
~seqPlay.value([
|
||||
[8, {
|
||||
~percSteps = (0!16);
|
||||
~reload.value;
|
||||
"outro 1 : perc out".postln;
|
||||
}],
|
||||
[8, {
|
||||
~clapSteps = (0!16);
|
||||
~reload.value;
|
||||
"outro 2 : clap out".postln;
|
||||
}],
|
||||
[8, {
|
||||
~hatSteps = (0!16);
|
||||
~snareSteps = (0!16);
|
||||
~reload.value;
|
||||
"outro 3 : hat + snare out".postln;
|
||||
}],
|
||||
[8, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
|
||||
~reload.value;
|
||||
"outro 4 : kick minimal".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqOutro defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqTechnoLoop.(repeats) -- enchaine 4 patterns techno mute par mesure
|
||||
// Necessite kicks.scd STOCKAGE evalue (~kK1..~kK25 dispo)
|
||||
// =====================================================================
|
||||
(
|
||||
~seqTechnoLoop = { |repeats = 4|
|
||||
~seqLoop.value([
|
||||
[16, {
|
||||
~kickSteps = ~kK1 ? [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~reload.value; "techno A : 4/4".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = ~kK9 ? [1,0,0,0, 1,0,0,1, 1,0,0,0, 1,0,1,0];
|
||||
~reload.value; "techno B : ghost".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = ~kK16 ? [1,0,0,0, 1,0,0,0, 1,0,0,1, 1,0,0,0];
|
||||
~reload.value; "techno C : minimal".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = ~kK10 ? [1,0,1,0, 1,0,0,1, 1,0,1,0, 1,0,1,1];
|
||||
~reload.value; "techno D : syncope".postln;
|
||||
}],
|
||||
], repeats);
|
||||
};
|
||||
"=== ~seqTechnoLoop defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqAcidEvolve -- acid pattern qui mute progressivement
|
||||
// Note: lit ~acidNotes / ~acidAccents / ~acidSlides du moteur
|
||||
// =====================================================================
|
||||
(
|
||||
~seqAcidEvolve = {
|
||||
~seqPlay.value([
|
||||
[16, {
|
||||
~acidNotes = [36,36,36,36, 36,36,36,36, 36,36,36,36, 36,36,36,36];
|
||||
~acidAccents = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~acidSlides = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
|
||||
~reload.value; "acid 1: drone tonic".postln;
|
||||
}],
|
||||
[16, {
|
||||
~acidNotes = [36,0,39,0, 36,0,43,0, 36,0,39,0, 36,0,43,0];
|
||||
~acidAccents = [1,0,0,0, 1,0,1,0, 1,0,0,0, 1,0,1,0];
|
||||
~reload.value; "acid 2: minor 3rd".postln;
|
||||
}],
|
||||
[16, {
|
||||
~acidNotes = [36,39,43,36, 39,43,48,43, 36,39,43,48, 43,39,36,43];
|
||||
~acidAccents = [1,0,0,1, 0,1,0,0, 1,0,0,1, 0,0,1,0];
|
||||
~acidSlides = [0,1,0,0, 1,0,1,0, 0,0,1,0, 1,1,0,0];
|
||||
~reload.value; "acid 3: arpege".postln;
|
||||
}],
|
||||
[16, {
|
||||
~acidNotes = [36,43,39,48, 36,46,43,48, 39,43,48,46, 43,39,48,36];
|
||||
~acidAccents = [1,0,1,1, 0,1,0,1, 1,0,1,0, 0,1,1,0];
|
||||
~acidSlides = [1,1,0,1, 0,0,1,1, 0,1,0,1, 1,0,1,0];
|
||||
~reload.value; "acid 4: full chaos".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqAcidEvolve defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqDubstepDrop -- pre-drop / drop / breakdown
|
||||
// =====================================================================
|
||||
(
|
||||
~seqDubstepDrop = {
|
||||
~seqPlay.value([
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~hatAmp = 0.06;
|
||||
~kickAmp = 0.4; ~snareAmp = 0.35;
|
||||
~reload.value; "dubstep 1: pre-drop tension".postln;
|
||||
}],
|
||||
[4, {
|
||||
~kickSteps = (0!16); ~snareSteps = (0!16); ~hatSteps = (0!16);
|
||||
~reload.value; "dubstep 2: SILENCE".postln;
|
||||
}],
|
||||
[32, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0];
|
||||
~kickAmp = 0.65; ~snareAmp = 0.55; ~hatAmp = 0.10;
|
||||
~reload.value; "dubstep 3: DROP !!!".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = (0!16); ~hatSteps = (0!16);
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~snareAmp = 0.4;
|
||||
~reload.value; "dubstep 4: breakdown".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqDubstepDrop defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqTrance16 -- 16 mesures de trance avec build implicite
|
||||
// =====================================================================
|
||||
(
|
||||
~seqTrance16 = {
|
||||
~seqPlay.value([
|
||||
[64, {
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~clapSteps = (0!16);
|
||||
~reload.value; "trance 1-4 : kick + offbeat hat".postln;
|
||||
}],
|
||||
[64, {
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~clapAmp = 0.35;
|
||||
~reload.value; "trance 5-8 : + clap 2/4".postln;
|
||||
}],
|
||||
[64, {
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0];
|
||||
~percSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~percAmp = 0.20;
|
||||
~reload.value; "trance 9-12 : + hat 8th + perc".postln;
|
||||
}],
|
||||
[64, {
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~snareSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~snareAmp = 0.45;
|
||||
~reload.value; "trance 13-16 : SNARE ROLL final".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqTrance16 defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqDnBSwitch -- alterne 4 patterns DnB toutes les 32 steps
|
||||
// =====================================================================
|
||||
(
|
||||
~seqDnBSwitch = { |repeats = 2|
|
||||
~seqLoop.value([
|
||||
[32, {
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1];
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1];
|
||||
~kickAmp = 0.55; ~snareAmp = 0.5; ~hatAmp = 0.12;
|
||||
~reload.value; "DnB A: amen".postln;
|
||||
}],
|
||||
[32, {
|
||||
~kickSteps = [1,0,0,1, 0,0,1,0, 0,0,1,0, 1,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,1, 1,0,1,1];
|
||||
~hatSteps = [1,1,0,1, 1,0,1,1, 1,1,0,1, 1,0,1,1];
|
||||
~reload.value; "DnB B: jungle".postln;
|
||||
}],
|
||||
[32, {
|
||||
~kickSteps = [1,0,0,0, 0,1,1,0, 0,0,1,0, 0,1,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0];
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~reload.value; "DnB C: jump-up".postln;
|
||||
}],
|
||||
[32, {
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [1,0,1,1, 0,1,0,1, 1,0,1,1, 0,1,0,1];
|
||||
~reload.value; "DnB D: liquid".postln;
|
||||
}],
|
||||
], repeats);
|
||||
};
|
||||
"=== ~seqDnBSwitch defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqHipHopLoop -- 8 mesures de hip-hop avec petites variations
|
||||
// =====================================================================
|
||||
(
|
||||
~seqHipHopLoop = { |repeats = 1|
|
||||
~seqLoop.value([
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0];
|
||||
~kickAmp = 0.5; ~snareAmp = 0.4; ~hatAmp = 0.10;
|
||||
~reload.value; "hip-hop 1: classic".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 0,0,0,0];
|
||||
~hatSteps = [1,0,1,1, 1,0,1,0, 1,0,1,1, 1,0,1,0];
|
||||
~reload.value; "hip-hop 2: ghost kick".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,1, 1,0,0,0, 0,1,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1];
|
||||
~reload.value; "hip-hop 3: trap shift".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1];
|
||||
~hatSteps = [1,0,1,0, 1,0,1,1, 1,0,1,0, 1,0,1,1];
|
||||
~reload.value; "hip-hop 4: ghost snare".postln;
|
||||
}],
|
||||
], repeats);
|
||||
};
|
||||
"=== ~seqHipHopLoop defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// ~seqWorldEvolve -- ajout progressif de couches ethno world
|
||||
// =====================================================================
|
||||
(
|
||||
~seqWorldEvolve = {
|
||||
~seqPlay.value([
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~hatSteps = (0!16);
|
||||
~clapSteps = (0!16);
|
||||
~percSteps = (0!16);
|
||||
~snareSteps = (0!16);
|
||||
~kickAmp = 0.4;
|
||||
~reload.value; "world 1: kick base".postln;
|
||||
}],
|
||||
[16, {
|
||||
~percInst = \tom; ~tomFreq = 95;
|
||||
~percSteps = [1,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0];
|
||||
~percAmp = 0.4;
|
||||
~reload.value; "world 2: + congas".postln;
|
||||
}],
|
||||
[16, {
|
||||
~hatSteps = [1,1,0,1, 1,0,1,1, 0,1,1,1, 1,0,1,1];
|
||||
~hatAmp = 0.08;
|
||||
~reload.value; "world 3: + shaker".postln;
|
||||
}],
|
||||
[16, {
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~clapAmp = 0.30;
|
||||
~reload.value; "world 4: + clap".postln;
|
||||
}],
|
||||
[16, {
|
||||
~kickSteps = [1,0,0,1, 0,1,0,0, 1,0,1,0, 0,1,0,0];
|
||||
~kickAmp = 0.5;
|
||||
~reload.value; "world 5: kick afrobeat".postln;
|
||||
}],
|
||||
]);
|
||||
};
|
||||
"=== ~seqWorldEvolve defini ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// EXEMPLES D'INVOCATION (a evaluer manuellement)
|
||||
// =====================================================================
|
||||
|
||||
// Lance l'intro :
|
||||
~seqIntro.value
|
||||
// Buildup 4 mesures :
|
||||
~seqBuildup.value(4)
|
||||
// Drop dubstep complet :
|
||||
~seqDubstepDrop.value
|
||||
// Stop la sequence en cours :
|
||||
// ~seqStop.value
|
||||
|
||||
// --- Chaine plusieurs sections via beatChainPlay --------------------
|
||||
~beatChainPlay.value([
|
||||
[64, { ~seqIntro.value }], // ne marche PAS dans une seq
|
||||
[64, { ~kickSteps = ~kK1; ~reload.value }],
|
||||
]);
|
||||
|
||||
// Note : ne pas imbriquer ~seqXxx.value dans une sequence. Pour chainer
|
||||
// des sections complexes, utilise des Routine externes ou enchaine
|
||||
// plusieurs ~seqLoop.value successifs apres un ~seqStop.value.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// =====================================================================
|
||||
// palette/scales.scd -- Scales + helpers de generation melodique
|
||||
//
|
||||
// FUSION : ce fichier consolide les scales et helpers melodiques
|
||||
// precedemment dupliques entre engine.scd et palette/melodies/scales.scd.
|
||||
// C'est la SEULE source de verite pour les scales et les helpers.
|
||||
//
|
||||
// Charge automatiquement par 00_load.scd > CHARGER TOUT, AVANT
|
||||
// palette/melodies/index.scd et palette/harmonics/index.scd.
|
||||
//
|
||||
// Un seul bloc top-level (compatible .load).
|
||||
// =====================================================================
|
||||
(
|
||||
// ---------- SCALES (toutes en C / 60 base, octaves +/-) -------------
|
||||
~scaleMinor = [60, 62, 63, 65, 67, 68, 70, 72]; // mineur naturel
|
||||
~scaleDorian = [60, 62, 63, 65, 67, 69, 70, 72]; // mineur 6e maj
|
||||
~scalePhrygian = [60, 61, 63, 65, 67, 68, 70, 72]; // sombre, 2nd min
|
||||
~scaleHarmonicMin = [60, 62, 63, 65, 67, 68, 71, 72]; // 7e majeure
|
||||
~scaleMinorPent = [60, 63, 65, 67, 70, 72, 75, 79]; // pentatonique min
|
||||
~scaleBlues = [60, 63, 65, 66, 67, 70, 72, 75]; // blues
|
||||
~scaleJapanese = [60, 62, 65, 67, 69, 72, 74, 77]; // hirajoshi-like
|
||||
~scaleHigh = [72, 75, 77, 79, 82, 84, 87, 89]; // octave aigue
|
||||
~scaleAcid = [36, 36, 36, 39, 41, 43, 48, 36, 39]; // bias sub
|
||||
~scaleAcidWide = [24, 36, 36, 39, 41, 43, 48, 51]; // octave -1 a +1
|
||||
~scaleAcidHigh = [48, 48, 51, 53, 55, 60, 63]; // acid en octave +1
|
||||
// Scales additionnelles (orientales / world)
|
||||
~scaleHijaz = [60, 61, 64, 65, 67, 68, 70, 72]; // arabe (b2, 3M)
|
||||
~scaleHirajoshi = [60, 62, 63, 67, 68, 72, 74, 75]; // pent jap sombre
|
||||
~scaleVietnam = [60, 63, 65, 67, 70, 72, 75, 77]; // pent vietnam min
|
||||
~scaleVietnamMaj = [60, 62, 64, 67, 69, 72, 74, 76]; // pent vietnam maj
|
||||
~scaleHungarian = [60, 62, 63, 66, 67, 68, 71, 72]; // gypsy mineur
|
||||
|
||||
// ---------- HELPERS DE GENERATION MELODIQUE -------------------------
|
||||
|
||||
// Genere une melodie de longueur `len` avec densite donnee
|
||||
// (0=tout vide, 1=plein). len defaut 32 pas.
|
||||
~genMelody = { |density = 0.55, scale, len = 32|
|
||||
var s = scale ?? { ~scaleMinorPent };
|
||||
len.collect { if (density.coin) { s.choose } { 0 } };
|
||||
};
|
||||
|
||||
// Mutate : remplace une fraction des notes (proba) par d'autres de la scale
|
||||
~mutate = { |notes, proba = 0.2, scale|
|
||||
var s = scale ?? { ~scaleMinorPent };
|
||||
notes.collect { |n|
|
||||
if (n > 0 and: { proba.coin }) { s.choose } { n }
|
||||
};
|
||||
};
|
||||
|
||||
// Octavate : decale aleatoirement chaque note de +/- 1 octave (proba)
|
||||
~octavate = { |notes, proba = 0.3|
|
||||
notes.collect { |n|
|
||||
if (n > 0 and: { proba.coin }) {
|
||||
n + ([-12, 12, 12].choose);
|
||||
} { n };
|
||||
};
|
||||
};
|
||||
|
||||
// Transpose : decale toutes les notes (sauf 0) de N demi-tons
|
||||
~transpose = { |notes, semitones|
|
||||
notes.collect { |n| if (n > 0) { n + semitones } { 0 } };
|
||||
};
|
||||
|
||||
// Retrograde : inverse l'ordre des notes
|
||||
~retrograde = { |notes| notes.reverse };
|
||||
|
||||
// Density : ajoute des notes aleatoires dans les silences (proba)
|
||||
~densify = { |notes, proba = 0.3, scale|
|
||||
var s = scale ?? { ~scaleMinorPent };
|
||||
notes.collect { |n|
|
||||
if (n == 0 and: { proba.coin }) { s.choose } { n }
|
||||
};
|
||||
};
|
||||
|
||||
// Sparsify : enleve aleatoirement des notes (proba)
|
||||
~sparsify = { |notes, proba = 0.3|
|
||||
notes.collect { |n| if (proba.coin) { 0 } { n } };
|
||||
};
|
||||
|
||||
// Jitter : multiplie une valeur par un facteur aleatoire (+/- amount)
|
||||
~jitter = { |val, amount = 0.1| val * rrand(1.0 - amount, 1.0 + amount) };
|
||||
|
||||
// Genere 16 notes acid en piochant dans la scale (avec biais sub)
|
||||
~genAcidNotes = { |scale| 16.collect { (scale ?? { ~scaleAcid }).choose } };
|
||||
~genAcidAccents = { |density = 0.4| 16.collect { if (density.coin) {1} {0} } };
|
||||
~genAcidSlides = { |density = 0.25, len = 16|
|
||||
len.collect { if (density.coin) {1} {0} };
|
||||
};
|
||||
|
||||
// Genere un pattern kick avec ghost notes (probabilite par step)
|
||||
~genKickPattern = { |density = 0.3|
|
||||
// garde les 4 temps forts, ajoute des ghosts aleatoires
|
||||
16.collect { |i|
|
||||
if (i.mod(4) == 0) { 1 } { if (density.coin) { 1 } { 0 } };
|
||||
};
|
||||
};
|
||||
|
||||
// Randomize : appelle dans une track pour micro-variations
|
||||
// proba : chance d'appliquer un changement (0.0 a 1.0)
|
||||
~randomTweak = { |proba = 0.3|
|
||||
if (proba.coin) { ~acidCutoff = rrand(400, 1800) };
|
||||
if (proba.coin) { ~acidRq = rrand(0.08, 0.25) };
|
||||
if (proba.coin) { ~melodyCutoff = rrand(1500, 3500) };
|
||||
if ((proba * 0.5).coin) { ~kickClick = rrand(0.05, 0.4) };
|
||||
~reload.value;
|
||||
};
|
||||
|
||||
"=== scales + helpers melodiques charges ===".postln;
|
||||
)
|
||||
@@ -0,0 +1,123 @@
|
||||
// =====================================================================
|
||||
// styles.scd
|
||||
// 5 styles complets : Acid Rave / Deep Dub / Hard Techno / Detroit / Minimal
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur un bloc pour l'appliquer.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
|
||||
// --- ACID RAVE -- 132 BPM, full energy, melodie pentatonique ---------
|
||||
(
|
||||
~bpm = 132;
|
||||
~acidNotes = [ 36, 36, 48, 36, 39, 36, 43, 39,
|
||||
36, 41, 36, 39, 43, 36, 36, 41 ];
|
||||
~acidAccents = [ 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1 ];
|
||||
~acidSlides = [ 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0 ];
|
||||
~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ];
|
||||
~hatSteps = [ 0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0 ];
|
||||
~melodyNotes = [ 60, 0, 67, 0, 70, 0, 67, 65,
|
||||
63, 0, 60, 0, 0, 67, 70, 72,
|
||||
75, 0, 72, 70, 67, 0, 0, 65,
|
||||
63, 60, 0, 67, 70, 0, 72, 0 ];
|
||||
~acidCutoff = 800; ~acidRq = 0.15; ~acidDrive = 2.5; ~acidAmp = 0.32;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.18;
|
||||
~melodyCutoff = 2400; ~melodyAttack = 0.012; ~melodyRelease = 0.25; ~melodyAmp = 0.16;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
"=== ACID RAVE 132 BPM ===".postln;
|
||||
)
|
||||
|
||||
// --- DEEP DUB -- 110 BPM, kick lent, plastikman acid, nappe melodique -
|
||||
(
|
||||
~bpm = 110;
|
||||
~acidNotes = [ 36, 36, 36, 36, 36, 36, 41, 36,
|
||||
36, 36, 36, 36, 36, 39, 36, 36 ];
|
||||
~acidAccents = [ 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0 ];
|
||||
~acidSlides = [ 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0 ];
|
||||
~kickSteps = [ 1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0 ];
|
||||
~hatSteps = [ 0,0,0,0, 0,0,1,0, 0,0,0,0, 0,0,1,0 ];
|
||||
// Nappe lente arpegee
|
||||
~melodyNotes = [ 60, 0, 0, 0, 63, 0, 0, 0,
|
||||
67, 0, 0, 0, 70, 0, 0, 0,
|
||||
72, 0, 0, 0, 70, 0, 0, 0,
|
||||
67, 0, 0, 0, 63, 0, 0, 0 ];
|
||||
~acidCutoff = 400; ~acidRq = 0.2; ~acidDrive = 1.6; ~acidAmp = 0.25;
|
||||
~kickAmp = 0.45; ~hatAmp = 0.10;
|
||||
~melodyCutoff = 1500; ~melodyAttack = 0.08; ~melodyRelease = 1.2; ~melodyAmp = 0.14;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
"=== DEEP DUB 110 BPM ===".postln;
|
||||
)
|
||||
|
||||
// --- HARD TECHNO -- 145 BPM, kick double, drive max, pas de melodie ---
|
||||
(
|
||||
~bpm = 145;
|
||||
~acidNotes = [ 36, 39, 48, 36, 41, 39, 43, 36,
|
||||
39, 41, 36, 48, 39, 36, 41, 39 ];
|
||||
~acidAccents = [ 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1 ];
|
||||
~acidSlides = [ 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0 ];
|
||||
~kickSteps = [ 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0 ];
|
||||
~hatSteps = [ 0,1,1,1, 0,1,1,0, 0,1,1,1, 0,1,1,0 ];
|
||||
~melodyNotes = (0 ! 32);
|
||||
~acidCutoff = 1200; ~acidRq = 0.10; ~acidDrive = 3.5; ~acidAmp = 0.32;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.16; ~melodyAmp = 0;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
"=== HARD TECHNO 145 BPM ===".postln;
|
||||
)
|
||||
|
||||
// --- DETROIT -- 128 BPM, melodie stabs en mineur ---------------------
|
||||
(
|
||||
~bpm = 128;
|
||||
~acidNotes = [ 36, 36, 48, 36, 39, 36, 43, 39,
|
||||
36, 41, 36, 39, 43, 36, 36, 41 ];
|
||||
~acidAccents = [ 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1 ];
|
||||
~acidSlides = [ 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0 ];
|
||||
~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ];
|
||||
~hatSteps = [ 0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0 ];
|
||||
~melodyNotes = [ 63, 0, 0, 0, 70, 0, 67, 0,
|
||||
65, 0, 0, 0, 70, 0, 72, 0,
|
||||
63, 0, 0, 0, 67, 0, 70, 0,
|
||||
65, 0, 60, 0, 67, 0, 0, 0 ];
|
||||
~acidCutoff = 700; ~acidRq = 0.18; ~acidDrive = 2.2; ~acidAmp = 0.28;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.15;
|
||||
~melodyCutoff = 2200; ~melodyAttack = 0.005; ~melodyRelease = 0.1; ~melodyAmp = 0.18;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
"=== DETROIT 128 BPM ===".postln;
|
||||
)
|
||||
|
||||
// --- MINIMAL -- 124 BPM, epure, melodie 2 notes ----------------------
|
||||
(
|
||||
~bpm = 124;
|
||||
~acidNotes = [ 36, 0, 0, 0, 36, 0, 0, 0,
|
||||
36, 0, 0, 41, 36, 0, 0, 0 ];
|
||||
~acidAccents = [ 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0 ];
|
||||
~acidSlides = [ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0 ];
|
||||
~kickSteps = [ 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 ];
|
||||
~hatSteps = [ 0,0,0,0, 0,0,1,0, 0,0,0,0, 0,0,1,0 ];
|
||||
~melodyNotes = [ 60, 0, 0, 0, 0, 0, 0, 0,
|
||||
67, 0, 0, 0, 0, 0, 0, 0,
|
||||
60, 0, 0, 0, 0, 0, 0, 0,
|
||||
65, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
~acidCutoff = 500; ~acidRq = 0.25; ~acidDrive = 1.5; ~acidAmp = 0.3;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.08;
|
||||
~melodyCutoff = 1800; ~melodyAttack = 0.02; ~melodyRelease = 0.6; ~melodyAmp = 0.13;
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
~reload.value;
|
||||
"=== MINIMAL 124 BPM ===".postln;
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
// =====================================================================
|
||||
// timbres.scd
|
||||
// Timbres melodie selectionnables via ~melodyInst (L1-L6 base + L7-L18 extra)
|
||||
//
|
||||
// PREREQUIS : engine.scd evalue. Cmd+Entree sur un bloc pour l'appliquer.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
|
||||
// --- L1 : LEAD (defaut) -- saw+pulse detunes + chorus stereo ----------
|
||||
( ~melodyInst = \lead; ~melodyAmp = 0.16; ~melodyAttack = 0.012; ~melodyRelease = 0.25;
|
||||
~reload.value; "L1 lead".postln; )
|
||||
|
||||
// --- L2 : PAD -- super-saw 5 voix, attack/release longs ---------------
|
||||
( ~melodyInst = \pad; ~melodyAmp = 0.14; ~melodyAttack = 0.4; ~melodyRelease = 1.5;
|
||||
~melodyCutoff = 1800;
|
||||
~reload.value; "L2 pad".postln; )
|
||||
|
||||
// --- L3 : PLUCK -- Karplus-Strong, decay naturel comme une corde ------
|
||||
( ~melodyInst = \pluck; ~melodyAmp = 0.22; ~melodyAttack = 0.001; ~melodyRelease = 0.5;
|
||||
~melodyCutoff = 5000;
|
||||
~reload.value; "L3 pluck".postln; )
|
||||
|
||||
// --- L4 : FM BELL DUBSTEP -- wobble + sub MASSIF + saturation -------
|
||||
( ~melodyInst = \fmBell; ~melodyAmp = 0.18;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4;
|
||||
~melodyCutoff = 400;
|
||||
~melodyDrive = 3.5;
|
||||
~melodyWobbleRate = 4; ~melodyWobbleDepth = 1800; ~melodyWobbleShape = 0;
|
||||
~melodySubAmt = 0.85; // SUB MASSIF
|
||||
~reload.value; "L4 fmBell DUBSTEP sub massif".postln; )
|
||||
|
||||
// --- Wobble rate : 1/4 (slow) -> 1/16 (fast) ----------------------
|
||||
( ~melodyWobbleRate = 2; ~reload.value; "wobble 1/4".postln; ) // lent
|
||||
( ~melodyWobbleRate = 4; ~reload.value; "wobble 1/8".postln; ) // standard
|
||||
( ~melodyWobbleRate = 8; ~reload.value; "wobble 1/16".postln; ) // rapide
|
||||
( ~melodyWobbleRate = 16; ~reload.value; "wobble 1/32".postln; ) // tres rapide
|
||||
|
||||
// --- Wobble shape : smooth (LFTri) vs chop (LFPulse) ---------------
|
||||
( ~melodyWobbleShape = 0; ~reload.value; "wobble smooth".postln; )
|
||||
( ~melodyWobbleShape = 1; ~reload.value; "wobble chop".postln; )
|
||||
|
||||
// --- Wobble depth : ouverture du filtre ---------------------------
|
||||
( ~melodyWobbleDepth = 800; ~reload.value; "wobble petit".postln; )
|
||||
( ~melodyWobbleDepth = 1800; ~reload.value; "wobble normal".postln; )
|
||||
( ~melodyWobbleDepth = 3500; ~reload.value; "wobble enorme".postln; )
|
||||
|
||||
// --- Sub level (poid du sub-bass dubstep) -------------------------
|
||||
( ~melodySubAmt = 0.2; ~reload.value; "sub leger".postln; )
|
||||
( ~melodySubAmt = 0.5; ~reload.value; "sub normal".postln; )
|
||||
( ~melodySubAmt = 0.8; ~reload.value; "sub massif".postln; )
|
||||
|
||||
// --- L5 : STAB -- court et sature, parfait pour Detroit ---------------
|
||||
( ~melodyInst = \stab; ~melodyAmp = 0.18; ~melodyAttack = 0.001; ~melodyRelease = 0.06;
|
||||
~melodyCutoff = 1500; ~melodyDrive = 2.8;
|
||||
~reload.value; "L5 stab".postln; )
|
||||
|
||||
// --- L6 : SAW3 -- 3 saws empilees, large -----------------------------
|
||||
( ~melodyInst = \saw3; ~melodyAmp = 0.16; ~melodyAttack = 0.005; ~melodyRelease = 0.25;
|
||||
~melodyCutoff = 2200; ~melodyDrive = 1.4;
|
||||
~reload.value; "L6 saw3".postln; )
|
||||
|
||||
// --- TIMBRE ALEATOIRE ------------------------------------------------
|
||||
(
|
||||
~melodyInst = [\lead, \pad, \pluck, \fmBell, \stab, \saw3].choose;
|
||||
~reload.value;
|
||||
("L random : " ++ ~melodyInst).postln;
|
||||
)
|
||||
|
||||
// --- ROTATION AUTOMATIQUE des timbres (toutes les 16s) ---------------
|
||||
(
|
||||
~lRotate !? { ~lRotate.stop };
|
||||
~lRotate = Routine({
|
||||
var insts = [\lead, \pad, \pluck, \fmBell, \stab, \saw3];
|
||||
inf.do { |k|
|
||||
~melodyInst = insts.wrapAt(k);
|
||||
("L rotate -> " ++ ~melodyInst).postln;
|
||||
~reload.value;
|
||||
16.wait;
|
||||
};
|
||||
}).play;
|
||||
"L rotate ON".postln;
|
||||
)
|
||||
( ~lRotate !? { ~lRotate.stop }; "L rotate OFF".postln; )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TIMBRES EXTRA (necessite synthdefs_extra.scd evalue)
|
||||
// =====================================================================
|
||||
|
||||
// --- L7 : SQUARE LEAD (chiptune / 8-bit) ----------------------------
|
||||
( ~melodyInst = \squareLead; ~melodyAmp = 0.16;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.25; ~melodyCutoff = 5000;
|
||||
~reload.value; "L7 squareLead chiptune".postln; )
|
||||
|
||||
// --- L8 : FM LEAD (DX-style) ----------------------------------------
|
||||
( ~melodyInst = \fmLead; ~melodyAmp = 0.16;
|
||||
~melodyAttack = 0.003; ~melodyRelease = 0.4; ~melodyCutoff = 6000;
|
||||
~reload.value; "L8 fmLead".postln; )
|
||||
|
||||
// --- L9 : ORGAN LEAD (Hammond drawbar) ------------------------------
|
||||
( ~melodyInst = \organLead; ~melodyAmp = 0.14;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.15; ~melodyCutoff = 4500;
|
||||
~reload.value; "L9 organLead".postln; )
|
||||
|
||||
// --- L10 : HARD LEAD (saw avec hard sync) ---------------------------
|
||||
( ~melodyInst = \hardLead; ~melodyAmp = 0.16;
|
||||
~melodyAttack = 0.002; ~melodyRelease = 0.25; ~melodyCutoff = 5500;
|
||||
~reload.value; "L10 hardLead".postln; )
|
||||
|
||||
// --- L11 : WARM PAD (super-saw 7 voix lush) -------------------------
|
||||
( ~melodyInst = \warmPad; ~melodyAmp = 0.13;
|
||||
~melodyAttack = 0.6; ~melodyRelease = 2.0; ~melodyCutoff = 1800;
|
||||
~reload.value; "L11 warmPad".postln; )
|
||||
|
||||
// --- L12 : STRINGS (ensemble orchestral) ----------------------------
|
||||
( ~melodyInst = \strings; ~melodyAmp = 0.15;
|
||||
~melodyAttack = 0.3; ~melodyRelease = 1.2; ~melodyCutoff = 3500;
|
||||
~reload.value; "L12 strings".postln; )
|
||||
|
||||
// --- L13 : CHOIR (voix synthetiques avec formants) ------------------
|
||||
( ~melodyInst = \choir; ~melodyAmp = 0.15;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 2500;
|
||||
~reload.value; "L13 choir".postln; )
|
||||
|
||||
// --- L14 : FM BASS (techno ratio 2:1) -------------------------------
|
||||
( ~melodyInst = \fmBass; ~melodyAmp = 0.30;
|
||||
~melodyAttack = 0.003; ~melodyRelease = 0.2; ~melodyCutoff = 1800;
|
||||
~reload.value; "L14 fmBass".postln; )
|
||||
|
||||
// --- L15 : SUB BOOM (808 amplifie) ----------------------------------
|
||||
( ~melodyInst = \subBoom; ~melodyAmp = 0.36;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.6;
|
||||
~reload.value; "L15 subBoom".postln; )
|
||||
|
||||
// --- L16 : HANDPAN (steel drum) -------------------------------------
|
||||
( ~melodyInst = \handpan; ~melodyAmp = 0.20;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 1.5; ~melodyCutoff = 5000;
|
||||
~reload.value; "L16 handpan".postln; )
|
||||
|
||||
// --- L17 : FLUTE (bambou avec souffle) ------------------------------
|
||||
( ~melodyInst = \flute; ~melodyAmp = 0.16;
|
||||
~melodyAttack = 0.08; ~melodyRelease = 0.3; ~melodyCutoff = 3500;
|
||||
~reload.value; "L17 flute".postln; )
|
||||
|
||||
// --- L18 : DRONE (note longue avec modulation) ---------------------
|
||||
( ~melodyInst = \drone; ~melodyAmp = 0.16;
|
||||
~melodyAttack = 1.5; ~melodyRelease = 3.0; ~melodyCutoff = 1800;
|
||||
~reload.value; "L18 drone".postln; )
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TIMBRES AUTHENTIQUES (L19-L28) -- necessite synthdefs/authentic.scd
|
||||
// =====================================================================
|
||||
|
||||
// --- L19 : SUPERSAW (trance JP-8000 7-voice) -----------------------
|
||||
( ~melodyInst = \supersaw; ~melodyAmp = 0.15;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyCutoff = 4500;
|
||||
~reload.value; "L19 supersaw trance".postln; )
|
||||
|
||||
// --- L20 : RHODES (Detroit DX7 e-piano) -----------------------------
|
||||
( ~melodyInst = \rhodes; ~melodyAmp = 0.20;
|
||||
~melodyAttack = 0.002; ~melodyRelease = 0.8; ~melodyCutoff = 4000;
|
||||
~reload.value; "L20 rhodes Detroit".postln; )
|
||||
|
||||
// --- L21 : HOOVERBASS (Alpha Juno / gabber / trance) ---------------
|
||||
( ~melodyInst = \hooverbass; ~melodyAmp = 0.22;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.2; ~melodyCutoff = 3500;
|
||||
~reload.value; "L21 hooverbass".postln; )
|
||||
|
||||
// --- L22 : VOCAL PAD (formants vocaux ah/eh) -----------------------
|
||||
( ~melodyInst = \vocalPad; ~melodyAmp = 0.18;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5;
|
||||
~reload.value; "L22 vocalPad".postln; )
|
||||
|
||||
// --- L23 : DIDGERIDOO (drone aborigene + growl) -------------------
|
||||
( ~melodyInst = \didgeridoo; ~melodyAmp = 0.22;
|
||||
~melodyAttack = 0.5; ~melodyRelease = 1.0;
|
||||
~reload.value; "L23 didgeridoo".postln; )
|
||||
|
||||
// --- L24 : GUZHENG (harpe chinoise + bend) -------------------------
|
||||
( ~melodyInst = \guzheng; ~melodyAmp = 0.22;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 1.5; ~melodyCutoff = 5500;
|
||||
~reload.value; "L24 guzheng".postln; )
|
||||
|
||||
// --- L25 : SHAKUHACHI (flute japonaise + breath) -------------------
|
||||
( ~melodyInst = \shakuhachi; ~melodyAmp = 0.18;
|
||||
~melodyAttack = 0.12; ~melodyRelease = 0.4; ~melodyCutoff = 3000;
|
||||
~reload.value; "L25 shakuhachi".postln; )
|
||||
|
||||
// --- L26 : REESE DnB (FM brutal hard DnB) --------------------------
|
||||
( ~melodyInst = \reeseDnB; ~melodyAmp = 0.30;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.2; ~melodyCutoff = 800;
|
||||
~melodyDrive = 4.0;
|
||||
~reload.value; "L26 reeseDnB".postln; )
|
||||
|
||||
// --- TRACKS DE PERCUSSION SUPPLEMENTAIRES ------------------------
|
||||
// Ces SynthDefs s'utilisent via Synth(\xxx) plutot que ~melodyInst :
|
||||
(Synth(\taiko, [\freq, 80, \amp, 0.5]);)
|
||||
(Synth(\tabla, [\freq, 220, \amp, 0.4]);)
|
||||
(Synth(\kickGabber, [\amp, 0.6]);)
|
||||
(Synth(\kick808, [\freq, 35, \decay, 1, \amp, 0.7]);)
|
||||
(Synth(\snareGated, [\freq, 200, \decay, 0.2, \amp, 0.5]);)
|
||||
(Synth(\scratch, [\dur, 0.3, \freq, 800, \amp, 0.4]);)
|
||||
@@ -0,0 +1,235 @@
|
||||
// =====================================================================
|
||||
// tweaks_template.scd -- Tweaks live communs charges par toutes les tracks
|
||||
//
|
||||
// Ne PAS evaluer le fichier en bloc. Cmd+Entree sur une ligne au choix
|
||||
// pendant qu'une track tourne.
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE RICHES -- Cmd+Entree sur une ligne pendant la track
|
||||
// =====================================================================
|
||||
|
||||
// === STOP / CONTROLE ============================================
|
||||
(~track.stop;)
|
||||
|
||||
// === MUTE INSTANTANE par voix ===================================
|
||||
(~kickAmp = 0; ~reload.value;)
|
||||
(~kickAmp = 0.5; ~reload.value;)
|
||||
(~hatAmp = 0; ~reload.value;)
|
||||
(~hatAmp = 0.18; ~reload.value;)
|
||||
(~snareAmp = 0; ~reload.value;)
|
||||
(~snareAmp = 0.5; ~reload.value;)
|
||||
(~clapAmp = 0; ~reload.value;)
|
||||
(~clapAmp = 0.35; ~reload.value;)
|
||||
(~percAmp = 0; ~reload.value;)
|
||||
(~percAmp = 0.25; ~reload.value;)
|
||||
(~melodyAmp = 0; ~reload.value;)
|
||||
(~melodyAmp = 0.18;~reload.value;)
|
||||
(~harmonyAmp = 0; ~reload.value;)
|
||||
(~harmonyAmp = 0.14;~reload.value;)
|
||||
|
||||
// === SOLO une piste (mute les autres) ===========================
|
||||
(~kickAmp=0;~hatAmp=0;~clapAmp=0;~melodyAmp=0;~harmonyAmp=0;~snareAmp=0.5;~reload.value;) // solo snare
|
||||
(~kickAmp=0;~hatAmp=0;~clapAmp=0;~snareAmp=0;~harmonyAmp=0;~melodyAmp=0.2;~reload.value;) // solo melody
|
||||
(~kickAmp=0.5;~hatAmp=0;~snareAmp=0;~clapAmp=0;~melodyAmp=0;~harmonyAmp=0;~reload.value;) // solo kick
|
||||
|
||||
// === HARMONY -- 2e voix melodique ==============================
|
||||
(~enableHarmony.(\off);) // mute harmony
|
||||
(~enableHarmony.(\third);) // tierce harmonisee
|
||||
(~enableHarmony.(\fifth);) // quinte harmonisee
|
||||
(~enableHarmony.(\counter);) // contre-melodie inversee
|
||||
(~enableHarmony.(\bassline);) // bass 2 octaves -2
|
||||
(~enableHarmony.(\dubBass);) // dub bass long sustain
|
||||
(~enableHarmony.(\arp);) // arpege octave +1 en 1/32
|
||||
(~enableHarmony.(\chord);) // chord pad sustained
|
||||
(~enableHarmony.(\tranceLayer);) // organ +1 octave
|
||||
(~enableHarmony.(\cinematic);) // strings layer
|
||||
|
||||
// === SWITCH SYNTH MELODIE =======================================
|
||||
(~melodyInst = \lead; ~reload.value;)
|
||||
(~melodyInst = \pad; ~reload.value;)
|
||||
(~melodyInst = \warmPad; ~reload.value;)
|
||||
(~melodyInst = \pluck; ~reload.value;)
|
||||
(~melodyInst = \fmBell; ~reload.value;)
|
||||
(~melodyInst = \stab; ~reload.value;)
|
||||
(~melodyInst = \saw3; ~reload.value;)
|
||||
(~melodyInst = \squareLead; ~reload.value;)
|
||||
(~melodyInst = \fmLead; ~reload.value;)
|
||||
(~melodyInst = \organLead; ~reload.value;)
|
||||
(~melodyInst = \hardLead; ~reload.value;)
|
||||
(~melodyInst = \strings; ~reload.value;)
|
||||
(~melodyInst = \choir; ~reload.value;)
|
||||
(~melodyInst = \fmBass; ~reload.value;)
|
||||
(~melodyInst = \subBoom; ~reload.value;)
|
||||
(~melodyInst = \handpan; ~reload.value;)
|
||||
(~melodyInst = \flute; ~reload.value;)
|
||||
(~melodyInst = \drone; ~reload.value;)
|
||||
(~melodyInst = \koto; ~reload.value;)
|
||||
(~melodyInst = \erhu; ~reload.value;)
|
||||
(~melodyInst = \pipa; ~reload.value;)
|
||||
(~melodyInst = \growl; ~reload.value;)
|
||||
|
||||
// === CUTOFF / RESONANCE =========================================
|
||||
(~melodyCutoff = 400; ~reload.value;)
|
||||
(~melodyCutoff = 1200; ~reload.value;)
|
||||
(~melodyCutoff = 3000; ~reload.value;)
|
||||
(~melodyCutoff = 6000; ~reload.value;)
|
||||
(~melodyRq = 0.05; ~reload.value;) // resonance EXTREME (fmBell/growl)
|
||||
(~melodyRq = 0.2; ~reload.value;)
|
||||
(~melodyRq = 0.5; ~reload.value;)
|
||||
|
||||
// === DRIVE / VOLUME =============================================
|
||||
(~melodyDrive = 1.0; ~reload.value;)
|
||||
(~melodyDrive = 2.5; ~reload.value;)
|
||||
(~melodyDrive = 5.0; ~reload.value;)
|
||||
(~melodyBoost = 1.0; ~reload.value;)
|
||||
(~melodyBoost = 2.5; ~reload.value;)
|
||||
|
||||
// === SIDECHAIN PUMP =============================================
|
||||
(~acidScAmt = 0; ~reload.value;) // acid sans duck
|
||||
(~acidScAmt = 0.7; ~reload.value;) // acid normal
|
||||
(~acidScAmt = 0.95; ~reload.value;) // acid pump fort
|
||||
(~leadScAmt = 0; ~reload.value;)
|
||||
(~leadScAmt = 0.5; ~reload.value;)
|
||||
(~leadScAmt = 0.9; ~reload.value;)
|
||||
(~kickScShape = 0.08; ~reload.value;) // pump court
|
||||
(~kickScShape = 0.18; ~reload.value;) // normal
|
||||
(~kickScShape = 0.35; ~reload.value;) // pump long french touch
|
||||
|
||||
// === KICK CHARACTER =============================================
|
||||
(~kickFreq=42; ~kickPitchAmt=2.0; ~kickDecay=0.5; ~kickDrive=1.0; ~kickClick=0.05; ~reload.value;) // T5 sub
|
||||
(~kickFreq=55; ~kickPitchAmt=3.0; ~kickDecay=0.32;~kickDrive=1.3; ~kickClick=0.20; ~reload.value;) // T1 rond
|
||||
(~kickFreq=65; ~kickPitchAmt=4.0; ~kickDecay=0.18;~kickDrive=1.8; ~kickClick=0.45; ~reload.value;) // T2 claquant
|
||||
(~kickFreq=48; ~kickPitchAmt=2.5; ~kickDecay=0.6; ~kickDrive=1.2; ~kickClick=0.08; ~reload.value;) // T3 boomy
|
||||
(~kickFreq=60; ~kickPitchAmt=5.0; ~kickDecay=0.28;~kickDrive=3.5; ~kickClick=0.30; ~reload.value;) // T4 distordu
|
||||
(~kickFreq=70; ~kickPitchAmt=3.5; ~kickDecay=0.22;~kickDrive=2.0; ~kickClick=0.35; ~reload.value;) // T6 punchy
|
||||
|
||||
// === DUBSTEP WOBBLE (si melodyInst = fmBell ou growl) ===========
|
||||
(~melodyWobbleRate = 2; ~reload.value;) // 1/4
|
||||
(~melodyWobbleRate = 4; ~reload.value;) // 1/8
|
||||
(~melodyWobbleRate = 8; ~reload.value;) // 1/16
|
||||
(~melodyWobbleRate = 16; ~reload.value;) // 1/32
|
||||
(~melodyWobbleShape = 0; ~reload.value;) // smooth
|
||||
(~melodyWobbleShape = 1; ~reload.value;) // chop square
|
||||
(~melodyWobbleDepth = 1000;~reload.value;) // sub
|
||||
(~melodyWobbleDepth = 2500;~reload.value;) // normal
|
||||
(~melodyWobbleDepth = 4000;~reload.value;) // EXTREME
|
||||
(~melodySubAmt = 0.3; ~reload.value;) // sub leger
|
||||
(~melodySubAmt = 0.7; ~reload.value;) // sub normal
|
||||
(~melodySubAmt = 1.0; ~reload.value;) // sub MASSIF
|
||||
|
||||
// === ACID 303 ====================================================
|
||||
(~acidCutoff = 200; ~reload.value;)
|
||||
(~acidCutoff = 800; ~reload.value;)
|
||||
(~acidCutoff = 2000; ~reload.value;)
|
||||
(~acidRq = 0.05; ~reload.value;) // resonance acide EXTREME
|
||||
(~acidRq = 0.15; ~reload.value;)
|
||||
(~acidDrive = 1.0; ~reload.value;)
|
||||
(~acidDrive = 4.5; ~reload.value;)
|
||||
|
||||
// === PATTERNS RYTHME (kick) =====================================
|
||||
(~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~reload.value;) // 4/4
|
||||
(~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~reload.value;) // half-time
|
||||
(~kickSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0]; ~reload.value;) // gabber double
|
||||
(~kickSteps = [1,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0]; ~reload.value;) // syncope
|
||||
(~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~reload.value;) // amen
|
||||
(~kickSteps = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; ~reload.value;) // mute
|
||||
|
||||
// === PATTERNS HAT ================================================
|
||||
(~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~reload.value;) // offbeat
|
||||
(~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~reload.value;) // 16ths
|
||||
(~hatSteps = [1,0,1,1, 0,1,1,0, 1,0,1,1, 0,1,1,0]; ~reload.value;) // trap triplets
|
||||
(~hatSteps = [0,1,0,1, 1,1,0,1, 0,1,0,1, 1,1,0,1]; ~reload.value;) // breakbeat
|
||||
|
||||
// === MELODIES (charger une mélodie sans changer le timbre) =======
|
||||
(~melodyNotes = ~genMelody.(0.55, ~scaleMinorPent); ~reload.value;)
|
||||
(~melodyNotes = ~genMelody.(0.7, ~scaleMinor); ~reload.value;)
|
||||
(~melodyNotes = ~genMelody.(0.5, ~scaleDorian); ~reload.value;)
|
||||
(~melodyNotes = ~genMelody.(0.45, ~scalePhrygian); ~reload.value;)
|
||||
(~melodyNotes = ~genMelody.(0.5, ~scaleHarmonicMin);~reload.value;)
|
||||
(~melodyNotes = ~genMelody.(0.6, ~scaleJapanese); ~reload.value;)
|
||||
(~melodyNotes = ~mutate.(~melodyNotes, 0.3); ~reload.value;)
|
||||
(~melodyNotes = ~transpose.(~melodyNotes, 5); ~reload.value;) // +4te
|
||||
(~melodyNotes = ~transpose.(~melodyNotes, -3);~reload.value;) // -tierce min
|
||||
(~melodyNotes = ~transpose.(~melodyNotes, 12);~reload.value;) // +1 octave
|
||||
(~melodyNotes = ~retrograde.(~melodyNotes); ~reload.value;)
|
||||
(~melodyNotes = ~octavate.(~melodyNotes, 0.4);~reload.value;)
|
||||
(~melodyNotes = ~densify.(~melodyNotes, 0.3); ~reload.value;)
|
||||
(~melodyNotes = ~sparsify.(~melodyNotes, 0.4);~reload.value;)
|
||||
|
||||
// === TEMPO =======================================================
|
||||
(TempoClock.default.tempo = 100/60;)
|
||||
(TempoClock.default.tempo = 120/60;)
|
||||
(TempoClock.default.tempo = 132/60;)
|
||||
(TempoClock.default.tempo = 145/60;)
|
||||
(TempoClock.default.tempo = 174/60;)
|
||||
(TempoClock.default.tempo = (~bpm * 0.95)/60;) // slow down 5%
|
||||
(TempoClock.default.tempo = (~bpm * 1.05)/60;) // speed up 5%
|
||||
|
||||
// === FX ONESHOTS =================================================
|
||||
(Synth(\impact, [\freq, 45, \decay, 1.5, \amp, 0.5]);)
|
||||
(Synth(\impact, [\freq, 30, \decay, 3.0, \amp, 0.7]);) // gros boom
|
||||
(Synth(\riser, [\dur, 4, \startCutoff, 200, \endCutoff, 8000, \amp, 0.25]);)
|
||||
(Synth(\riser, [\dur, 8, \startCutoff, 300, \endCutoff, 10000, \amp, 0.30]);)
|
||||
(Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.35]);) // long
|
||||
(Synth(\sweep, [\dur, 4, \startCutoff, 8000,\endCutoff, 200, \amp, 0.25]);) // descend
|
||||
(Synth(\sweep, [\dur, 8, \startCutoff, 12000,\endCutoff,200, \amp, 0.35]);) // long descend
|
||||
(Synth(\crash, [\decay, 1.5, \amp, 0.3]);)
|
||||
(Synth(\crash, [\decay, 4.0, \amp, 0.4]);) // crash long
|
||||
(Synth(\gong, [\freq, 40, \decay, 8, \amp, 0.6]);) // gong profond
|
||||
(Synth(\gong, [\freq, 80, \decay, 5, \amp, 0.4]);) // gong haut
|
||||
|
||||
// === FILLS et ROLLS =============================================
|
||||
(~snareFill.(8, 1, 0.3, 0.5);) // 8 hits 1s
|
||||
(~snareFill.(16, 2, 0.2, 0.55);) // 16 hits 2s accelerando
|
||||
(~snareFill.(32, 2, 0.15, 0.6);) // 32 hits frenetic
|
||||
(~tomFill.value;) // descente 4 toms
|
||||
(8.do { Synth(\hat, [\amp, 0.15, \decay, 0.03]); 0.075.wait };) // hat roll
|
||||
|
||||
// === VINYL TEXTURE (continu) ====================================
|
||||
(~vinyl !? { ~vinyl.free }; ~vinyl = Synth(\vinyl, [\amp, 0.08]); "vinyl ON".postln;)
|
||||
(~vinyl !? { ~vinyl.free; ~vinyl = nil }; "vinyl OFF".postln;)
|
||||
|
||||
// === FILTER SWEEP AUTOMATIQUE (continu, infini) =================
|
||||
(
|
||||
~filterSweep !? { ~filterSweep.stop };
|
||||
~filterSweep = Routine({
|
||||
inf.do { |k|
|
||||
~melodyCutoff = 200 + ((k / 32 * 2 * pi).sin.abs * 4500);
|
||||
~reload.value;
|
||||
0.25.wait;
|
||||
};
|
||||
}).play;
|
||||
"filter sweep ON".postln;
|
||||
)
|
||||
( ~filterSweep !? { ~filterSweep.stop }; "filter sweep OFF".postln; )
|
||||
|
||||
// === DROP (cut tout sauf melody pendant 2s puis relance) =========
|
||||
(
|
||||
Routine({
|
||||
var oldKick = ~kickAmp; var oldHat = ~hatAmp; var oldClap = ~clapAmp;
|
||||
~kickAmp = 0; ~hatAmp = 0; ~clapAmp = 0; ~reload.value;
|
||||
Synth(\sweep, [\dur, 2, \startCutoff, 8000, \endCutoff, 200, \amp, 0.4]);
|
||||
2.wait;
|
||||
Synth(\impact, [\freq, 35, \decay, 2, \amp, 0.7]);
|
||||
~kickAmp = oldKick; ~hatAmp = oldHat; ~clapAmp = oldClap; ~reload.value;
|
||||
}).play;
|
||||
"=== DROP CUT ===".postln;
|
||||
)
|
||||
|
||||
// === BREAK (mute tout sauf melody, 8 secondes, puis riser + retour) ==
|
||||
(
|
||||
Routine({
|
||||
var oldKick = ~kickAmp; var oldHat = ~hatAmp; var oldClap = ~clapAmp;
|
||||
var oldSnare = ~snareAmp;
|
||||
~kickAmp = 0; ~hatAmp = 0; ~clapAmp = 0; ~snareAmp = 0; ~reload.value;
|
||||
8.wait;
|
||||
Synth(\riser, [\dur, 4, \startCutoff, 400, \endCutoff, 11000, \amp, 0.35]);
|
||||
4.wait;
|
||||
Synth(\impact, [\freq, 38, \decay, 2, \amp, 0.6]);
|
||||
~kickAmp = oldKick; ~hatAmp = oldHat; ~clapAmp = oldClap; ~snareAmp = oldSnare;
|
||||
~reload.value;
|
||||
}).play;
|
||||
"=== BREAK 12s ===".postln;
|
||||
)
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
# PD <-> SC bridge
|
||||
|
||||
Pure Data ↔ SuperCollider via OSC bidirectionnel.
|
||||
|
||||
## Installation
|
||||
|
||||
PD a été installé via `brew install --cask pd` (Pd-vanilla 0.56-2 dans `/Applications/Pd-0.56-2.app`).
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
PureData SuperCollider
|
||||
┌──────────┐ OSC :57120 ┌──────────┐
|
||||
│ bridge.pd│ ──────────────> │ sclang │
|
||||
│ (GUI) │ <────────────── │ engine │
|
||||
└──────────┘ OSC :57121 └──────────┘
|
||||
```
|
||||
|
||||
- **PD → SC** : envoie OSC sur `localhost:57120` (port standard sclang)
|
||||
- **SC → PD** : envoie OSC sur `localhost:57121` (port `udpreceive` du patch)
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Côté SC
|
||||
|
||||
```supercollider
|
||||
// 1. Charge tout le projet
|
||||
// (00_load.scd > CHARGER TOUT)
|
||||
|
||||
// 2. Charge le bridge
|
||||
("/Users/electron/Documents/Projets_Creatifs/sound_algo/pd/bridge.scd").load;
|
||||
// OU ouvre pd/bridge.scd, Cmd+Entree sur le bloc SETUP
|
||||
```
|
||||
|
||||
### 2. Côté PD
|
||||
|
||||
Ouvre `pd/bridge.pd` dans Pure Data (Pd-0.56-2.app).
|
||||
|
||||
Le patch contient :
|
||||
- **TRANSPORT** : boutons PLAY / STOP / CHOKE / DROP / BREAKDOWN / BUILDUP / FREEZE / GLITCH
|
||||
- **FADERS_VOIX** : 8 sliders verticaux (kick / hat / snare / clap / perc / acid / melody / harmony) + master
|
||||
- **TWEAKS_FILTRES** : sliders horizontaux (melody_cutoff / acid_cutoff / bpm)
|
||||
- **FX_PRESETS** : boutons (dub / space / trance / industrial / cosmic / dry)
|
||||
|
||||
Les sliders et boutons envoient OSC vers SC au format `/<addr> <value>`.
|
||||
|
||||
### 3. Test
|
||||
|
||||
Clique sur **PLAY** dans le patch PD → tu dois entendre le beat lancé par SC.
|
||||
|
||||
## Messages OSC supportés (PD → SC)
|
||||
|
||||
| Adresse | Args | Action |
|
||||
|---|---|---|
|
||||
| `/play` | — | Lance les 8 Pdef sequencer |
|
||||
| `/stop` | — | Stop les Pdef |
|
||||
| `/choke` | — | Stop tracks + Pdef |
|
||||
| `/drop` | — | `~drop.()` |
|
||||
| `/breakdown` | — | `~breakdown.(8)` |
|
||||
| `/buildup` | — | `~buildup.(8)` |
|
||||
| `/freeze` | — | `~freeze.(4)` |
|
||||
| `/glitch` | — | `~glitch.(2)` |
|
||||
| `/stutter` | rate, dur | `~stutter.(rate, dur)` |
|
||||
| `/vol/<voie>` | val | `~setVol.(\voie, val)` |
|
||||
| `/vol/master` | val | `~masterVol.(val)` |
|
||||
| `/tweak/melodyCutoff` | hz | `~melodyCutoff = hz` |
|
||||
| `/tweak/acidCutoff` | hz | `~acidCutoff = hz` |
|
||||
| `/tweak/bpm` | bpm | TempoClock |
|
||||
| `/tweak/melodyRq` | val | `~melodyRq = val` |
|
||||
| `/fx/preset` | name | `~fxPreset.(\name)` |
|
||||
| `/fx/send` | voie, fx, amount | `~send.(\voie, \fx, amount)` |
|
||||
| `/fx/freeze` | 0\|1 | freeze reverb |
|
||||
| `/vcf/on` | type, freq, q | `~vcfOn.(\type, freq, q)` |
|
||||
| `/vcf/off` | — | `~vcfOff.()` |
|
||||
| `/lfo/to` | param, rate, depth, shape, center | `~lfoTo.(...)` |
|
||||
| `/lfo/stop` | param | `~lfoStopVar.(\param)` |
|
||||
| `/scene/save` | name | `~saveScene.(\name)` |
|
||||
| `/scene/load` | name | `~loadScene.(\name)` |
|
||||
| `/jump` | track, slug | `~jumpTo.(\track, \slug)` |
|
||||
| `/melody` | name | `~useMelody.(\name)` |
|
||||
| `/melody/genre` | genre | `~melodyByGenre.(\genre)` |
|
||||
| `/preset` | name | `~mixPreset.(\name)` |
|
||||
|
||||
## Messages OSC envoyés (SC → PD)
|
||||
|
||||
| Adresse | Args | Description |
|
||||
|---|---|---|
|
||||
| `/sc/status` | 1 | heartbeat (1Hz) |
|
||||
| `/sc/cpu` | float | CPU usage % |
|
||||
| `/sc/synths` | int | nb de synths actifs |
|
||||
|
||||
## Audio
|
||||
|
||||
Ce bridge gère les **messages de contrôle** (OSC). Pour router l'audio entre PD et SC :
|
||||
|
||||
- **Option 1 — JACK** : `brew install jack` puis route `Pd → SC` via JACK
|
||||
- **Option 2 — BlackHole** : `brew install --cask blackhole-2ch` (loopback virtuel macOS)
|
||||
- **Option 3 — multi-out** : SC sort sur device A, PD lit device A en input
|
||||
|
||||
Aucune route audio n'est configurée par défaut — chaque app sort sur son propre device audio.
|
||||
|
||||
## Stop
|
||||
|
||||
```supercollider
|
||||
~pdDisconnect.(); // libere les OSCdef + status loop
|
||||
```
|
||||
|
||||
Et ferme le patch PD normalement (Cmd+Q).
|
||||
|
||||
## Ajouter un nouveau message
|
||||
|
||||
**Côté PD** : ajoute un objet `[msg send /mon/addresse $1]` connecté à un slider/bouton, le tout connecté à `[netsend -u -b]`.
|
||||
|
||||
**Côté SC** : ajoute un `OSCdef` dans `pd/bridge.scd` :
|
||||
```supercollider
|
||||
~pd[\defs].add(OSCdef(\pdMonAction, { |msg|
|
||||
("recu : " ++ msg).postln;
|
||||
// ... action
|
||||
}, '/mon/addresse'));
|
||||
```
|
||||
|
||||
Re-évalue le bloc SETUP.
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
#N canvas 80 80 1100 820 12;
|
||||
#X obj 10 10 cnv 15 1080 60 empty empty PD<->SC_BRIDGE 18 22 0 16 -261681 -1 0;
|
||||
#X text 30 30 sound_algo control panel - OSC vers SuperCollider;
|
||||
#X text 30 48 status:;
|
||||
#X obj 90 48 cnv 15 200 16 empty empty CONNECTED_to_SC 4 8 0 10 -257985 -34 0;
|
||||
#X text 320 30 PORT cible:;
|
||||
#X floatatom 410 30 6 1024 65535 0 - port-target -;
|
||||
#X obj 490 26 bng 22 250 50 0 reconnect-bang empty RECONNECT 30 8 0 10 -204786 -1 -1;
|
||||
#X obj 620 26 bng 22 250 50 0 dsp-toggle empty DSP_ON_OFF 30 8 0 10 -1109 -1 -1;
|
||||
#X text 770 30 SC->PD on :57121;
|
||||
#X text 770 50 PD->SC default :57122;
|
||||
#X obj 10 80 cnv 15 1080 80 empty empty TRANSPORT 12 14 0 14 -228856 -1 0;
|
||||
#X obj 30 110 bng 36 250 50 0 empty empty PLAY 0 -10 0 10 -257985 -1 -1;
|
||||
#X obj 90 110 bng 36 250 50 0 empty empty STOP 0 -10 0 10 -1109 -1 -1;
|
||||
#X obj 150 110 bng 36 250 50 0 empty empty CHOKE 0 -10 0 10 -262144 -1 -1;
|
||||
#X obj 210 110 bng 36 250 50 0 empty empty PANIC 0 -10 0 10 -1109 -1 -1;
|
||||
#X msg 30 150 \; osc-out send /play;
|
||||
#X msg 90 150 \; osc-out send /stop;
|
||||
#X msg 150 150 \; osc-out send /choke;
|
||||
#X msg 210 150 \; osc-out send /stop \; osc-out send /choke;
|
||||
#X obj 10 170 cnv 15 1080 80 empty empty TRICKS_LIVE 12 14 0 14 -228856 -1 0;
|
||||
#X obj 30 200 bng 28 250 50 0 empty empty DROP 0 -8 0 10 -1109 -1 -1;
|
||||
#X obj 80 200 bng 28 250 50 0 empty empty BREAKDOWN 0 -8 0 10 -228856 -1 -1;
|
||||
#X obj 130 200 bng 28 250 50 0 empty empty BUILDUP 0 -8 0 10 -204786 -1 -1;
|
||||
#X obj 180 200 bng 28 250 50 0 empty empty FREEZE 0 -8 0 10 -257985 -1 -1;
|
||||
#X obj 230 200 bng 28 250 50 0 empty empty GLITCH 0 -8 0 10 -1109 -1 -1;
|
||||
#X obj 280 200 bng 28 250 50 0 empty empty STUTTER 0 -8 0 10 -228856 -1 -1;
|
||||
#X obj 330 200 bng 28 250 50 0 empty empty TAPESTOP 0 -8 0 10 -1109 -1 -1;
|
||||
#X obj 380 200 bng 28 250 50 0 empty empty HANDS_UP 0 -8 0 10 -204786 -1 -1;
|
||||
#X obj 430 200 bng 28 250 50 0 empty empty JUMPCUT 0 -8 0 10 -228856 -1 -1;
|
||||
#X obj 480 200 bng 28 250 50 0 empty empty TAPEREV 0 -8 0 10 -228856 -1 -1;
|
||||
#X msg 30 230 \; osc-out send /drop;
|
||||
#X msg 80 230 \; osc-out send /breakdown;
|
||||
#X msg 130 230 \; osc-out send /buildup;
|
||||
#X msg 180 230 \; osc-out send /freeze;
|
||||
#X msg 230 230 \; osc-out send /glitch;
|
||||
#X msg 280 230 \; osc-out send /stutter 8 1;
|
||||
#X msg 330 230 \; osc-out send /tapeStop;
|
||||
#X msg 380 230 \; osc-out send /handsUp;
|
||||
#X msg 430 230 \; osc-out send /jumpCut;
|
||||
#X msg 480 230 \; osc-out send /tapeReverse;
|
||||
#X obj 10 260 cnv 15 1080 170 empty empty MIXER_8_VOIES_+_MASTER 12 14 0 14 -228856 -1 0;
|
||||
#X obj 40 290 vsl 18 110 0 1 0 0 empty empty kick 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 100 290 vsl 18 110 0 1 0 0 empty empty hat 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 160 290 vsl 18 110 0 1 0 0 empty empty snare 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 220 290 vsl 18 110 0 1 0 0 empty empty clap 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 280 290 vsl 18 110 0 1 0 0 empty empty perc 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 340 290 vsl 18 110 0 1 0 0 empty empty acid 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 400 290 vsl 18 110 0 1 0 0 empty empty melody 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 460 290 vsl 18 110 0 1 0 0 empty empty harmony 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 540 290 vsl 18 110 0 2 0 0 empty empty MASTER 0 -8 0 10 -260818 -1 -1 0 1;
|
||||
#X msg 40 410 \; osc-out send /vol/kick \$1;
|
||||
#X msg 100 410 \; osc-out send /vol/hat \$1;
|
||||
#X msg 160 410 \; osc-out send /vol/snare \$1;
|
||||
#X msg 220 410 \; osc-out send /vol/clap \$1;
|
||||
#X msg 280 410 \; osc-out send /vol/perc \$1;
|
||||
#X msg 340 410 \; osc-out send /vol/acid \$1;
|
||||
#X msg 400 410 \; osc-out send /vol/melody \$1;
|
||||
#X msg 460 410 \; osc-out send /vol/harmony \$1;
|
||||
#X msg 540 410 \; osc-out send /vol/master \$1;
|
||||
#X obj 10 440 cnv 15 530 130 empty empty TWEAKS 12 14 0 14 -228856 -1 0;
|
||||
#X obj 30 470 hsl 160 18 100 12000 1 0 empty empty melodyCutoff 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 30 495 hsl 160 18 100 8000 1 0 empty empty acidCutoff 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 30 520 hsl 160 18 0 1 0 0 empty empty melodyRq 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 30 545 hsl 160 18 0 1 0 0 empty empty acidRq 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 280 470 hsl 160 18 0.5 5 0 0 empty empty melodyDrive 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 280 495 hsl 160 18 60 200 1 0 empty empty bpm 0 -8 0 10 -260818 -1 -1 0 1;
|
||||
#X msg 200 470 \; osc-out send /tweak/melodyCutoff \$1;
|
||||
#X msg 200 495 \; osc-out send /tweak/acidCutoff \$1;
|
||||
#X msg 200 520 \; osc-out send /tweak/melodyRq \$1;
|
||||
#X msg 200 545 \; osc-out send /tweak/acidRq \$1;
|
||||
#X msg 450 470 \; osc-out send /tweak/melodyDrive \$1;
|
||||
#X msg 450 495 \; osc-out send /tweak/bpm \$1;
|
||||
#X obj 550 440 cnv 15 540 130 empty empty FX_BUS 12 14 0 14 -228856 -1 0;
|
||||
#X obj 570 470 tgl 22 0 empty empty REV_FREEZE 0 -8 0 10 -257985 -1 -1 0 1;
|
||||
#X msg 600 510 \; osc-out send /fx/freeze \$1;
|
||||
#X obj 670 470 hsl 130 16 0 1 0 0 empty empty reverbMix 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 670 490 hsl 130 16 0 1 0 0 empty empty delayMix 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 670 510 hsl 130 16 0 1 0 0 empty empty chorusMix 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 670 530 hsl 130 16 0 1 0 0 empty empty shimmerMix 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X msg 810 470 \; osc-out send /fx/setMix reverb \$1;
|
||||
#X msg 810 490 \; osc-out send /fx/setMix delay \$1;
|
||||
#X msg 810 510 \; osc-out send /fx/setMix chorus \$1;
|
||||
#X msg 810 530 \; osc-out send /fx/setMix shimmer \$1;
|
||||
#X obj 970 470 hradio 16 1 0 10 empty empty fx_preset 0 -8 0 10 -204786 -1 0;
|
||||
#X text 970 455 fx preset:;
|
||||
#X text 970 490 dry/dub/spc/trn/dub/ret/ind/drm/cos/drn;
|
||||
#X obj 970 510 select 0 1 2 3 4 5 6 7 8 9;
|
||||
#X msg 970 530 \; osc-out send /fx/preset dry;
|
||||
#X msg 970 545 \; osc-out send /fx/preset dub;
|
||||
#X msg 970 560 \; osc-out send /fx/preset space;
|
||||
#X msg 1000 530 \; osc-out send /fx/preset trance;
|
||||
#X msg 1000 545 \; osc-out send /fx/preset dubstep;
|
||||
#X msg 1000 560 \; osc-out send /fx/preset retro;
|
||||
#X msg 1030 530 \; osc-out send /fx/preset industrial;
|
||||
#X msg 1030 545 \; osc-out send /fx/preset dream;
|
||||
#X msg 1030 560 \; osc-out send /fx/preset cosmic;
|
||||
#X msg 1060 530 \; osc-out send /fx/preset drone;
|
||||
#X obj 10 580 cnv 15 530 90 empty empty VCF_MASTER 12 14 0 14 -228856 -1 0;
|
||||
#X text 30 590 type:;
|
||||
#X text 150 590 moog ms20 ladder formant comb hpf bpf notch;
|
||||
#X obj 30 605 hradio 14 1 0 8 empty empty vcf_type 0 -8 0 10 -204786 -1 0;
|
||||
#X obj 30 635 hsl 200 16 50 15000 1 0 empty empty vcf_freq 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 250 635 hsl 130 16 0.05 1.5 0 0 empty empty vcf_q 0 -8 0 10 -204786 -1 -1 0 1;
|
||||
#X obj 410 605 bng 26 250 50 0 empty empty VCF_OFF 0 -8 0 10 -1109 -1 -1;
|
||||
#X obj 470 605 bng 22 250 50 0 empty empty VCF_ON 0 -8 0 10 -204786 -1 -1;
|
||||
#X msg 30 660 \; osc-out send /vcf/setFreq \$1;
|
||||
#X msg 250 660 \; osc-out send /vcf/setQ \$1;
|
||||
#X msg 410 635 \; osc-out send /vcf/off;
|
||||
#X msg 470 635 \; osc-out send /vcf/on moog 800 0.4;
|
||||
#X obj 550 580 cnv 15 540 90 empty empty MELODIES_+_JUMP 12 14 0 14 -228856 -1 0;
|
||||
#X obj 570 605 bng 22 250 50 0 empty empty rand_long 0 -8 0 10 -204786 -1 -1;
|
||||
#X obj 620 605 bng 22 250 50 0 empty empty rand_xlong 0 -8 0 10 -204786 -1 -1;
|
||||
#X obj 670 605 bng 22 250 50 0 empty empty rand_epic 0 -8 0 10 -204786 -1 -1;
|
||||
#X msg 570 635 \; osc-out send /melody/random/long;
|
||||
#X msg 620 635 \; osc-out send /melody/random/xlong;
|
||||
#X msg 670 635 \; osc-out send /melody/random/epic;
|
||||
#X text 740 590 acid dub trn det dnb ori syn;
|
||||
#X obj 740 605 hradio 14 1 0 7 empty empty melody_genre 0 -8 0 10 -204786 -1 0;
|
||||
#X obj 740 635 select 0 1 2 3 4 5 6;
|
||||
#X msg 740 655 \; osc-out send /melody/genre acid;
|
||||
#X msg 770 655 \; osc-out send /melody/genre dub;
|
||||
#X msg 800 655 \; osc-out send /melody/genre trance;
|
||||
#X msg 830 655 \; osc-out send /melody/genre detroit;
|
||||
#X msg 860 655 \; osc-out send /melody/genre dnb;
|
||||
#X msg 890 655 \; osc-out send /melody/genre oriental;
|
||||
#X msg 920 655 \; osc-out send /melody/genre synthwave;
|
||||
#X obj 970 605 bng 20 250 50 0 empty empty Aint 0 -8 0 9 -228856 -1 -1;
|
||||
#X obj 1000 605 bng 20 250 50 0 empty empty Adrp 0 -8 0 9 -228856 -1 -1;
|
||||
#X obj 1030 605 bng 20 250 50 0 empty empty Bdub 0 -8 0 9 -228856 -1 -1;
|
||||
#X obj 1060 605 bng 20 250 50 0 empty empty Chyp 0 -8 0 9 -228856 -1 -1;
|
||||
#X obj 970 635 bng 20 250 50 0 empty empty Edrp 0 -8 0 9 -228856 -1 -1;
|
||||
#X obj 1000 635 bng 20 250 50 0 empty empty Fdrp 0 -8 0 9 -228856 -1 -1;
|
||||
#X obj 1030 635 bng 20 250 50 0 empty empty Wdub 0 -8 0 9 -228856 -1 -1;
|
||||
#X msg 970 660 \; osc-out send /jump A intro;
|
||||
#X msg 1000 660 \; osc-out send /jump A drop;
|
||||
#X msg 1030 660 \; osc-out send /jump B dub;
|
||||
#X msg 1060 660 \; osc-out send /jump C hyp;
|
||||
#X msg 970 680 \; osc-out send /jump E drop;
|
||||
#X msg 1000 680 \; osc-out send /jump F drop;
|
||||
#X msg 1030 680 \; osc-out send /jump W dub;
|
||||
#X obj 10 680 cnv 15 1080 60 empty empty SCENES 12 14 0 14 -228856 -1 0;
|
||||
#X text 30 705 SCENES presets (load):;
|
||||
#X obj 220 705 bng 22 250 50 0 empty empty verseA 0 -8 0 10 -228856 -1 -1;
|
||||
#X obj 280 705 bng 22 250 50 0 empty empty breakdown 0 -8 0 10 -228856 -1 -1;
|
||||
#X obj 360 705 bng 22 250 50 0 empty empty drop 0 -8 0 10 -228856 -1 -1;
|
||||
#X obj 420 705 bng 22 250 50 0 empty empty favorite 0 -8 0 10 -228856 -1 -1;
|
||||
#X msg 220 730 \; osc-out send /scene/load verseA;
|
||||
#X msg 280 730 \; osc-out send /scene/load breakdown;
|
||||
#X msg 360 730 \; osc-out send /scene/load drop;
|
||||
#X msg 420 730 \; osc-out send /scene/load favorite;
|
||||
#X text 520 705 SAVE/LOAD 'live':;
|
||||
#X obj 670 705 bng 22 250 50 0 empty empty save_live 0 -8 0 10 -204786 -1 -1;
|
||||
#X obj 720 705 bng 22 250 50 0 empty empty load_live 0 -8 0 10 -204786 -1 -1;
|
||||
#X msg 670 730 \; osc-out send /scene/save live;
|
||||
#X msg 720 730 \; osc-out send /scene/load live;
|
||||
#X obj 10 750 cnv 15 1080 22 empty empty SC->PD_status 4 8 0 10 -228856 -1 0;
|
||||
#X text 30 752 SC->;
|
||||
#X text 80 752 status:;
|
||||
#X obj 130 752 r sc-status;
|
||||
#X floatatom 175 752 4 0 0 0 - - -;
|
||||
#X text 220 752 cpu:;
|
||||
#X obj 260 752 r sc-cpu;
|
||||
#X floatatom 305 752 5 0 0 0 - - -;
|
||||
#X text 360 752 synths:;
|
||||
#X obj 410 752 r sc-synths;
|
||||
#X floatatom 455 752 4 0 0 0 - - -;
|
||||
#N canvas 100 100 760 460 osc 0;
|
||||
#X text 20 10 sub-patch OSC: netsend (PD->SC) + netreceive (SC->PD);
|
||||
#X obj 20 60 r osc-out;
|
||||
#X obj 20 90 netsend -u -b;
|
||||
#X obj 20 120 print net-status;
|
||||
#X text 200 60 <- recoit toutes les commandes des widgets;
|
||||
#X text 200 90 -> envoie OSC vers SC sur le port cible;
|
||||
#X obj 20 170 loadbang;
|
||||
#X msg 20 200 connect localhost 57122;
|
||||
#X obj 20 230 t a;
|
||||
#X text 200 200 connexion auto au load (port 57122);
|
||||
#X obj 200 170 r reconnect-bang;
|
||||
#X obj 200 200 r port-target;
|
||||
#X obj 200 230 list prepend connect localhost;
|
||||
#X obj 200 260 list trim;
|
||||
#X text 400 200 modif port via la number-box du header;
|
||||
#X obj 20 290 r dsp-toggle;
|
||||
#X obj 20 320 t b b;
|
||||
#X msg 20 350 \; pd dsp 1;
|
||||
#X msg 100 350 \; pd dsp 0;
|
||||
#X text 200 320 alterne DSP on/off via [\; pd dsp ...];
|
||||
#X obj 500 60 netreceive -u 57121;
|
||||
#X obj 500 90 oscparse;
|
||||
#X obj 500 120 route /sc/status /sc/cpu /sc/synths /sc/hello /sc/bpm;
|
||||
#X obj 500 160 s sc-status;
|
||||
#X obj 560 160 s sc-cpu;
|
||||
#X obj 620 160 s sc-synths;
|
||||
#X obj 500 200 print SC-hello;
|
||||
#X obj 560 200 print SC-bpm;
|
||||
#X obj 500 240 print SC-other;
|
||||
#X text 500 30 reception OSC depuis SC sur :57121;
|
||||
#X connect 1 0 2 0;
|
||||
#X connect 2 0 3 0;
|
||||
#X connect 6 0 7 0;
|
||||
#X connect 7 0 8 0;
|
||||
#X connect 8 0 2 0;
|
||||
#X connect 10 0 12 0;
|
||||
#X connect 11 0 12 0;
|
||||
#X connect 12 0 13 0;
|
||||
#X connect 13 0 8 0;
|
||||
#X connect 15 0 16 0;
|
||||
#X connect 16 0 17 0;
|
||||
#X connect 16 1 18 0;
|
||||
#X connect 20 0 21 0;
|
||||
#X connect 21 0 22 0;
|
||||
#X connect 22 0 23 0;
|
||||
#X connect 22 1 24 0;
|
||||
#X connect 22 2 25 0;
|
||||
#X connect 22 3 26 0;
|
||||
#X connect 22 4 27 0;
|
||||
#X connect 22 5 28 0;
|
||||
#X restore 10 775 pd osc;
|
||||
#X obj 200 775 loadbang;
|
||||
#X msg 320 775 PD bridge loaded -- check connection;
|
||||
#X obj 320 795 print bridge;
|
||||
#X text 480 775 Cote SC: Cmd+Entree sur SETUP de pd/bridge.scd \, Cmd+/ pour DSP;
|
||||
#X text 480 795 [pd osc] sub-patch contains netsend/netreceive plumbing;
|
||||
#X connect 11 0 15 0;
|
||||
#X connect 12 0 16 0;
|
||||
#X connect 13 0 17 0;
|
||||
#X connect 14 0 18 0;
|
||||
#X connect 20 0 30 0;
|
||||
#X connect 21 0 31 0;
|
||||
#X connect 22 0 32 0;
|
||||
#X connect 23 0 33 0;
|
||||
#X connect 24 0 34 0;
|
||||
#X connect 25 0 35 0;
|
||||
#X connect 26 0 36 0;
|
||||
#X connect 27 0 37 0;
|
||||
#X connect 28 0 38 0;
|
||||
#X connect 29 0 39 0;
|
||||
#X connect 41 0 50 0;
|
||||
#X connect 42 0 51 0;
|
||||
#X connect 43 0 52 0;
|
||||
#X connect 44 0 53 0;
|
||||
#X connect 45 0 54 0;
|
||||
#X connect 46 0 55 0;
|
||||
#X connect 47 0 56 0;
|
||||
#X connect 48 0 57 0;
|
||||
#X connect 49 0 58 0;
|
||||
#X connect 60 0 66 0;
|
||||
#X connect 61 0 67 0;
|
||||
#X connect 62 0 68 0;
|
||||
#X connect 63 0 69 0;
|
||||
#X connect 64 0 70 0;
|
||||
#X connect 65 0 71 0;
|
||||
#X connect 73 0 74 0;
|
||||
#X connect 75 0 79 0;
|
||||
#X connect 76 0 80 0;
|
||||
#X connect 77 0 81 0;
|
||||
#X connect 78 0 82 0;
|
||||
#X connect 83 0 86 0;
|
||||
#X connect 86 0 87 0;
|
||||
#X connect 86 1 88 0;
|
||||
#X connect 86 2 89 0;
|
||||
#X connect 86 3 90 0;
|
||||
#X connect 86 4 91 0;
|
||||
#X connect 86 5 92 0;
|
||||
#X connect 86 6 93 0;
|
||||
#X connect 86 7 94 0;
|
||||
#X connect 86 8 95 0;
|
||||
#X connect 86 9 96 0;
|
||||
#X connect 101 0 105 0;
|
||||
#X connect 102 0 106 0;
|
||||
#X connect 103 0 107 0;
|
||||
#X connect 104 0 108 0;
|
||||
#X connect 110 0 113 0;
|
||||
#X connect 111 0 114 0;
|
||||
#X connect 112 0 115 0;
|
||||
#X connect 117 0 118 0;
|
||||
#X connect 118 0 119 0;
|
||||
#X connect 118 1 120 0;
|
||||
#X connect 118 2 121 0;
|
||||
#X connect 118 3 122 0;
|
||||
#X connect 118 4 123 0;
|
||||
#X connect 118 5 124 0;
|
||||
#X connect 118 6 125 0;
|
||||
#X connect 126 0 133 0;
|
||||
#X connect 127 0 134 0;
|
||||
#X connect 128 0 135 0;
|
||||
#X connect 129 0 136 0;
|
||||
#X connect 130 0 137 0;
|
||||
#X connect 131 0 138 0;
|
||||
#X connect 132 0 139 0;
|
||||
#X connect 142 0 146 0;
|
||||
#X connect 143 0 147 0;
|
||||
#X connect 144 0 148 0;
|
||||
#X connect 145 0 149 0;
|
||||
#X connect 151 0 153 0;
|
||||
#X connect 152 0 154 0;
|
||||
#X connect 158 0 159 0;
|
||||
#X connect 161 0 162 0;
|
||||
#X connect 164 0 165 0;
|
||||
#X connect 167 0 168 0;
|
||||
#X connect 168 0 169 0;
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
// =====================================================================
|
||||
// pd/bridge.scd -- Bridge SuperCollider <-> Pure Data via OSC
|
||||
//
|
||||
// Echange OSC bidirectionnel :
|
||||
// PD -> SC : envoie sur localhost:57120 (port standard sclang)
|
||||
// SC -> PD : envoie sur localhost:57121 (port netreceive de bridge.pd)
|
||||
//
|
||||
// PD addresses ecoutees par SC :
|
||||
// /play /stop /choke
|
||||
// /drop /breakdown /buildup /freeze /glitch
|
||||
// /vol/<voie> <0..1> -- voie : kick hat snare clap perc acid melody harmony
|
||||
// /vol/master <0..2> -- multiplicateur master
|
||||
// /tweak/<param> <val> -- param : melodyCutoff acidCutoff bpm melodyRq acidRq
|
||||
// /fx/preset <name> -- name : dub space trance industrial cosmic dry
|
||||
// /fx/send <voie> <fx> <amount> -- ex: /fx/send acid rev 0.4
|
||||
// /fx/freeze <0|1> -- freeze reverb
|
||||
// /vcf/on <type> <freq> <q> -- vcf master
|
||||
// /vcf/off
|
||||
// /lfo/to <param> <rate> <depth> <shape> <center>
|
||||
// /lfo/stop <param>
|
||||
// /scene/save <name>
|
||||
// /scene/load <name>
|
||||
// /jump <track> <slug> -- ex: /jump A acid_rave_kick_t1_melody_lead_variations
|
||||
// /melody <name> -- ex: /melody m50
|
||||
// /melody/genre <genre> -- ex: /melody/genre acid
|
||||
// /preset <mix> -- ex: /preset drumsHeavy
|
||||
// /kit <name> -- ex: /kit kitTechno
|
||||
//
|
||||
// USAGE :
|
||||
// 1. Lance PD : ouvre pd/bridge.pd
|
||||
// 2. Cote SC : Cmd+Entree sur le bloc SETUP ci-dessous
|
||||
// 3. Test : clique sur PLAY dans le patch PD -- tu dois entendre le beat
|
||||
// 4. Pour stopper le bridge : ~pdDisconnect.()
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// --- SETUP -- enregistre les OSCdef cote SC -------------------------
|
||||
(
|
||||
~pd = ~pd ?? { () };
|
||||
~pd[\target] = NetAddr("127.0.0.1", 57121); // port netreceive du patch PD
|
||||
~pd[\defs] = ~pd[\defs] ?? { List.new };
|
||||
|
||||
// Helpers d'envoi vers PD
|
||||
~pdSend = { |addr ...args| ~pd[\target].sendMsg(addr, *args) };
|
||||
|
||||
// Liberer les anciennes OSCdef
|
||||
~pd[\defs].do { |d| d.free }; ~pd[\defs] = List.new;
|
||||
|
||||
// --- transport -----------------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdPlay, {
|
||||
TempoClock.default.tempo = (~bpm ? 128) / 60;
|
||||
~reload !? { ~reload.value };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
"[PD] PLAY".postln;
|
||||
}, '/play'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdStop, {
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[PD] STOP".postln;
|
||||
}, '/stop'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdChoke, {
|
||||
~track !? { ~track.stop; ~track = nil };
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[PD] CHOKE".postln;
|
||||
}, '/choke'));
|
||||
|
||||
// --- tricks live ---------------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdDrop, { ~drop !? { ~drop.() } }, '/drop'));
|
||||
~pd[\defs].add(OSCdef(\pdBreakdown, { ~breakdown !? { ~breakdown.(8) } }, '/breakdown'));
|
||||
~pd[\defs].add(OSCdef(\pdBuildup, { ~buildup !? { ~buildup.(8) } }, '/buildup'));
|
||||
~pd[\defs].add(OSCdef(\pdFreeze, { ~freeze !? { ~freeze.(4) } }, '/freeze'));
|
||||
~pd[\defs].add(OSCdef(\pdGlitch, { ~glitch !? { ~glitch.(2) } }, '/glitch'));
|
||||
~pd[\defs].add(OSCdef(\pdStutter, { |msg| ~stutter !? { ~stutter.(msg[1] ? 8, msg[2] ? 1) } }, '/stutter'));
|
||||
~pd[\defs].add(OSCdef(\pdTapeStop, { ~tapeStop !? { ~tapeStop.(2) } }, '/tapeStop'));
|
||||
~pd[\defs].add(OSCdef(\pdHandsUp, { ~handsUp !? { ~handsUp.() } }, '/handsUp'));
|
||||
~pd[\defs].add(OSCdef(\pdJumpCut, { |msg| ~jumpCut !? { ~jumpCut.(msg[1] ? 0.5) } }, '/jumpCut'));
|
||||
~pd[\defs].add(OSCdef(\pdTapeRev, { ~tapeReverse !? { ~tapeReverse.(4) } }, '/tapeReverse'));
|
||||
~pd[\defs].add(OSCdef(\pdPanic, {
|
||||
~track !? { ~track.stop; ~track = nil };
|
||||
~teardown !? { ~teardown.() };
|
||||
"[PD] PANIC -- teardown lance".postln;
|
||||
}, '/panic'));
|
||||
|
||||
// --- volumes (mixer) -----------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdVolKick, { |msg| ~setVol !? { ~setVol.(\kick, msg[1]) } }, '/vol/kick'));
|
||||
~pd[\defs].add(OSCdef(\pdVolHat, { |msg| ~setVol !? { ~setVol.(\hat, msg[1]) } }, '/vol/hat'));
|
||||
~pd[\defs].add(OSCdef(\pdVolSnare, { |msg| ~setVol !? { ~setVol.(\snare, msg[1]) } }, '/vol/snare'));
|
||||
~pd[\defs].add(OSCdef(\pdVolClap, { |msg| ~setVol !? { ~setVol.(\clap, msg[1]) } }, '/vol/clap'));
|
||||
~pd[\defs].add(OSCdef(\pdVolPerc, { |msg| ~setVol !? { ~setVol.(\perc, msg[1]) } }, '/vol/perc'));
|
||||
~pd[\defs].add(OSCdef(\pdVolAcid, { |msg| ~setVol !? { ~setVol.(\acid, msg[1]) } }, '/vol/acid'));
|
||||
~pd[\defs].add(OSCdef(\pdVolMelody, { |msg| ~setVol !? { ~setVol.(\melody, msg[1]) } }, '/vol/melody'));
|
||||
~pd[\defs].add(OSCdef(\pdVolHarmony, { |msg| ~setVol !? { ~setVol.(\harmony, msg[1]) } }, '/vol/harmony'));
|
||||
~pd[\defs].add(OSCdef(\pdVolMaster, { |msg| ~masterVol !? { ~masterVol.(msg[1]) } }, '/vol/master'));
|
||||
|
||||
// --- tweaks parametriques ------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdTweakMelCut, { |msg| ~melodyCutoff = msg[1].asFloat; ~reload.value }, '/tweak/melodyCutoff'));
|
||||
~pd[\defs].add(OSCdef(\pdTweakAcidCut,{ |msg| ~acidCutoff = msg[1].asFloat; ~reload.value }, '/tweak/acidCutoff'));
|
||||
~pd[\defs].add(OSCdef(\pdTweakBpm, { |msg| ~bpm = msg[1].asFloat; TempoClock.default.tempo = ~bpm/60 }, '/tweak/bpm'));
|
||||
~pd[\defs].add(OSCdef(\pdTweakMelRq, { |msg| ~melodyRq = msg[1].asFloat; ~reload.value }, '/tweak/melodyRq'));
|
||||
~pd[\defs].add(OSCdef(\pdTweakAcidRq, { |msg| ~acidRq = msg[1].asFloat; ~reload.value }, '/tweak/acidRq'));
|
||||
~pd[\defs].add(OSCdef(\pdTweakDrive, { |msg| ~melodyDrive = msg[1].asFloat; ~reload.value }, '/tweak/melodyDrive'));
|
||||
|
||||
// --- FX bus --------------------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdFxPreset, { |msg|
|
||||
~fxPreset !? { ~fxPreset.(msg[1].asSymbol) };
|
||||
("[PD] fxPreset " ++ msg[1]).postln;
|
||||
}, '/fx/preset'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdFxSend, { |msg|
|
||||
~send !? { ~send.(msg[1].asSymbol, msg[2].asSymbol, msg[3].asFloat) };
|
||||
}, '/fx/send'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdFxFreeze, { |msg|
|
||||
~setFx !? { ~setFx.(\rev, \freeze, msg[1].asInteger) };
|
||||
}, '/fx/freeze'));
|
||||
|
||||
// /fx/setMix <fxname:reverb|delay|chorus|shimmer|...> <0..1>
|
||||
~pd[\defs].add(OSCdef(\pdFxSetMix, { |msg|
|
||||
var name = msg[1].asSymbol;
|
||||
var key = (name: \rev, reverb: \rev, delay: \dly, dly: \dly,
|
||||
chorus: \chr, chr: \chr, phaser: \phs, phs: \phs,
|
||||
flanger: \flg, flg: \flg, bitcrush: \crsh, crsh: \crsh,
|
||||
tape: \tape, shimmer: \shim, shim: \shim, dist: \dist)[name] ? name;
|
||||
~setFx !? { ~setFx.(key, \mix, msg[2].asFloat) };
|
||||
}, '/fx/setMix'));
|
||||
|
||||
// --- VCF master ----------------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdVcfOn, { |msg|
|
||||
~vcfOn !? { ~vcfOn.(msg[1].asSymbol, msg[2].asFloat, msg[3].asFloat) };
|
||||
}, '/vcf/on'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdVcfOff, { ~vcfOff !? { ~vcfOff.() } }, '/vcf/off'));
|
||||
~pd[\defs].add(OSCdef(\pdVcfFreq, { |msg| ~vcfSet !? { ~vcfSet.(\freq, msg[1].asFloat) } }, '/vcf/setFreq'));
|
||||
~pd[\defs].add(OSCdef(\pdVcfQ, { |msg| ~vcfSet !? { ~vcfSet.(\q, msg[1].asFloat) } }, '/vcf/setQ'));
|
||||
|
||||
// --- LFO -----------------------------------------------------------
|
||||
~pd[\defs].add(OSCdef(\pdLfoTo, { |msg|
|
||||
~lfoTo !? { ~lfoTo.(msg[1].asSymbol, msg[2].asFloat, msg[3].asFloat,
|
||||
msg[4].asSymbol, msg[5].asFloat) };
|
||||
}, '/lfo/to'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdLfoStop, { |msg|
|
||||
~lfoStopVar !? { ~lfoStopVar.(msg[1].asSymbol) };
|
||||
}, '/lfo/stop'));
|
||||
|
||||
// --- Scenes / jump / mélodies / kits / presets ---------------------
|
||||
~pd[\defs].add(OSCdef(\pdSceneSave, { |msg|
|
||||
~saveScene !? { ~saveScene.(msg[1].asSymbol) };
|
||||
}, '/scene/save'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdSceneLoad, { |msg|
|
||||
~loadScene !? { ~loadScene.(msg[1].asSymbol) };
|
||||
}, '/scene/load'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdJump, { |msg|
|
||||
~jumpTo !? { ~jumpTo.(msg[1].asSymbol, msg[2].asSymbol) };
|
||||
}, '/jump'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdMelody, { |msg|
|
||||
~useMelody !? { ~useMelody.(msg[1].asSymbol) };
|
||||
}, '/melody'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdMelodyGenre, { |msg|
|
||||
~melodyByGenre !? { ~melodyByGenre.(msg[1].asSymbol) };
|
||||
}, '/melody/genre'));
|
||||
|
||||
~pd[\defs].add(OSCdef(\pdMixPreset, { |msg|
|
||||
~mixPreset !? { ~mixPreset.(msg[1].asSymbol) };
|
||||
}, '/preset'));
|
||||
|
||||
// --- Boucle de status (envoi periodique vers PD) -------------------
|
||||
~pd[\statusLoop] !? { ~pd[\statusLoop].stop };
|
||||
~pd[\statusLoop] = Routine({
|
||||
loop {
|
||||
~pdSend.('/sc/status', 1);
|
||||
~pdSend.('/sc/cpu', s.avgCPU.round(0.1));
|
||||
~pdSend.('/sc/synths', s.numSynths);
|
||||
1.wait;
|
||||
};
|
||||
}).play;
|
||||
|
||||
"=== PD bridge ACTIF (SC<-OSC->PD) ===".postln;
|
||||
" PD -> SC : 57120 (sclang OSC default)".postln;
|
||||
" SC -> PD : 57121 (bridge.pd udpreceive)".postln;
|
||||
" stoppe avec ~pdDisconnect.()".postln;
|
||||
)
|
||||
|
||||
|
||||
// --- DECONNECT (libere tous les OSCdef + status loop) ---------------
|
||||
(
|
||||
~pdDisconnect = {
|
||||
~pd !? {
|
||||
~pd[\statusLoop] !? { ~pd[\statusLoop].stop; ~pd[\statusLoop] = nil };
|
||||
~pd[\defs] !? { ~pd[\defs].do { |d| d.free }; ~pd[\defs] = List.new };
|
||||
};
|
||||
"=== PD bridge STOP ===".postln;
|
||||
};
|
||||
~pdDisconnect.();
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// Tests rapides (Cmd+Entree pour envoyer un message vers PD)
|
||||
// =====================================================================
|
||||
|
||||
// --- Test : envoyer un message a PD --------------------------------
|
||||
( ~pdSend.('/sc/hello', "ping"); )
|
||||
|
||||
// --- Test : envoi du tempo courant a PD ----------------------------
|
||||
( ~pdSend.('/sc/bpm', ~bpm ? 128); )
|
||||
@@ -0,0 +1,779 @@
|
||||
// =====================================================================
|
||||
// setup.scd -- Verification d'etat + init complete du projet
|
||||
//
|
||||
// USAGE PRINCIPAL (workflow recommande) :
|
||||
// Tout est fait depuis 00_load.scd > bloc "CHARGER TOUT". Ce fichier
|
||||
// est charge automatiquement par le loader, qui appelle ~setupAll.()
|
||||
// a la fin. Tu n'as PAS besoin de l'ouvrir manuellement en general.
|
||||
//
|
||||
// USAGE MANUEL (debug ou redemarrage rapide) :
|
||||
// Ouvre ce fichier dans l'IDE puis Cmd+Entree sur un bloc :
|
||||
// ( ~check.() ) -- rapport d'etat colore
|
||||
// ( ~setupAll.() ) -- recharge TOUT (engine + live + ...)
|
||||
// ( ~setupLive.() ) -- recharge UNIQUEMENT live/* (rapide)
|
||||
// ( ~ensureLive.() ) -- charge ce qui manque seulement
|
||||
// ( ~teardown.() ) -- stop tout proprement
|
||||
//
|
||||
// HELPERS EXPOSES (tous definis dans le 1er bloc -- .load-compatible) :
|
||||
// ~check status global colore
|
||||
// ~setupAll charge engine + synthdefs + scales + melodies
|
||||
// + harmonics + boot serveur + setup live + check
|
||||
// ~setupLive recharge UNIQUEMENT les modules live (rapide)
|
||||
// ~ensureLive charge live/* paresseusement (seulement absents)
|
||||
// ~teardown stop tout proprement
|
||||
// ~loadFirstBlock(path) helper interne -- evalue le 1er bloc d'un .scd
|
||||
//
|
||||
// STRUCTURE
|
||||
// Le 1er bloc top-level contient TOUS les helpers : c'est le SETUP
|
||||
// HELPERS, evaluable via .load setup.scd (ce que fait CHARGER TOUT).
|
||||
// Les blocs suivants sont des exemples Cmd+Entree (pas charges par
|
||||
// .load, evaluables manuellement dans l'IDE).
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// SETUP HELPERS (1er bloc top-level -- .load-compatible)
|
||||
//
|
||||
// Definit ~base, ~loadFirstBlock, ~check, ~setupAll, ~setupLive,
|
||||
// ~ensureLive, ~teardown. Ce bloc est execute par .load setup.scd
|
||||
// depuis le bloc CHARGER TOUT de 00_load.scd.
|
||||
// =====================================================================
|
||||
(
|
||||
// --- BASE PATH (auto-detection si pas deja defini) -------------------
|
||||
~base = ~base ?? { "/Users/electron/Documents/Projets_Creatifs/sound_algo/" };
|
||||
"~base = ".post; ~base.postln;
|
||||
|
||||
|
||||
// --- HELPER : ~loadFirstBlock ---------------------------------------
|
||||
// Lit un fichier .scd et evalue son PREMIER bloc top-level (...) en
|
||||
// comptant les parens balancees. Sert pour les fichiers multi-blocs
|
||||
// dont seul le 1er bloc est le SETUP a evaluer (live/*, jump.scd, ...).
|
||||
//
|
||||
// Robuste : try/protect pour qu'une erreur d'un fichier n'arrete pas
|
||||
// les autres. Print clair de chaque etape ([setupAll] ... OK / FAIL).
|
||||
// --------------------------------------------------------------------
|
||||
~loadFirstBlock = { |path|
|
||||
var src, depth = 0, start = nil, firstBlock = nil;
|
||||
var label = path.basename;
|
||||
var i = 0, n, ch, ch2;
|
||||
var inLineComment = false, inBlockComment = false, inString = false;
|
||||
if (File.exists(path).not) {
|
||||
("[setupAll] " ++ label ++ " ... FAIL (fichier introuvable)").postln;
|
||||
} {
|
||||
src = File.readAllString(path);
|
||||
n = src.size;
|
||||
block { |break|
|
||||
while { i < n } {
|
||||
ch = src[i];
|
||||
ch2 = if (i + 1 < n) { src[i + 1] } { $ };
|
||||
// ----- gestion des etats -----
|
||||
if (inLineComment) {
|
||||
if (ch == $\n) { inLineComment = false };
|
||||
i = i + 1;
|
||||
} {
|
||||
if (inBlockComment) {
|
||||
if ((ch == $*) and: { ch2 == $/ }) { inBlockComment = false; i = i + 2 }
|
||||
{ i = i + 1 };
|
||||
} {
|
||||
if (inString) {
|
||||
if (ch == $\\) { i = i + 2 } // skip escape
|
||||
{ if (ch == $") { inString = false; i = i + 1 } { i = i + 1 } };
|
||||
} {
|
||||
// ----- pas dans un comment / string -----
|
||||
// entree commentaire ligne
|
||||
if ((ch == $/) and: { ch2 == $/ }) { inLineComment = true; i = i + 2 }
|
||||
// entree commentaire bloc
|
||||
{ if ((ch == $/) and: { ch2 == $* }) { inBlockComment = true; i = i + 2 }
|
||||
// char literal SC : $( ou $) ou $" -- on saute le caractere suivant
|
||||
{ if ((ch == $$) and: { (ch2 == $() or: { (ch2 == $)) or: { ch2 == $" } } }) { i = i + 2 }
|
||||
// entree string
|
||||
{ if (ch == $") { inString = true; i = i + 1 }
|
||||
// parens REELLES
|
||||
{ if (ch == $() {
|
||||
if (depth == 0) { start = i };
|
||||
depth = depth + 1;
|
||||
i = i + 1;
|
||||
} { if (ch == $)) {
|
||||
depth = depth - 1;
|
||||
if ((depth == 0) and: { start.notNil }) {
|
||||
firstBlock = src.copyRange(start, i);
|
||||
break.value;
|
||||
};
|
||||
i = i + 1;
|
||||
} { i = i + 1 } } } } } };
|
||||
} } };
|
||||
};
|
||||
};
|
||||
if (firstBlock.isNil) {
|
||||
("[setupAll] " ++ label ++ " ... FAIL (aucun bloc trouve)").postln;
|
||||
} {
|
||||
("[setupAll] " ++ label ++ " ... loading [" ++ firstBlock.size ++ " chars]").post;
|
||||
try {
|
||||
firstBlock.interpret;
|
||||
" OK".postln;
|
||||
} { |err|
|
||||
" FAIL".postln;
|
||||
(" " ++ err.errorString).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- HELPER : ~loadAllBlocks ----------------------------------------
|
||||
// Comme ~loadFirstBlock mais charge TOUS les blocs top-level d'un
|
||||
// fichier. Utile pour fichiers comme sequences.scd qui ont leurs
|
||||
// helpers en bloc 1 puis ~seqIntro/Buildup/Drop en blocs separes.
|
||||
// Ignore comments / strings / char literals.
|
||||
// --------------------------------------------------------------------
|
||||
~loadAllBlocks = { |path|
|
||||
var src, depth = 0, start = nil, blocks = List.new;
|
||||
var label = path.basename;
|
||||
var i = 0, n, ch, ch2;
|
||||
var inLineComment = false, inBlockComment = false, inString = false;
|
||||
if (File.exists(path).not) {
|
||||
("[setupAll] " ++ label ++ " ... FAIL (fichier introuvable)").postln;
|
||||
} {
|
||||
src = File.readAllString(path);
|
||||
n = src.size;
|
||||
while { i < n } {
|
||||
ch = src[i];
|
||||
ch2 = if (i + 1 < n) { src[i + 1] } { $ };
|
||||
if (inLineComment) {
|
||||
if (ch == $\n) { inLineComment = false }; i = i + 1;
|
||||
} {
|
||||
if (inBlockComment) {
|
||||
if ((ch == $*) and: { ch2 == $/ }) { inBlockComment = false; i = i + 2 } { i = i + 1 };
|
||||
} {
|
||||
if (inString) {
|
||||
if (ch == $\\) { i = i + 2 } { if (ch == $") { inString = false; i = i + 1 } { i = i + 1 } };
|
||||
} {
|
||||
if ((ch == $/) and: { ch2 == $/ }) { inLineComment = true; i = i + 2 }
|
||||
{ if ((ch == $/) and: { ch2 == $* }) { inBlockComment = true; i = i + 2 }
|
||||
{ if ((ch == $$) and: { (ch2 == $() or: { (ch2 == $)) or: { ch2 == $" } } }) { i = i + 2 }
|
||||
{ if (ch == $") { inString = true; i = i + 1 }
|
||||
{ if (ch == $() {
|
||||
if (depth == 0) { start = i };
|
||||
depth = depth + 1; i = i + 1;
|
||||
} { if (ch == $)) {
|
||||
depth = depth - 1;
|
||||
if ((depth == 0) and: { start.notNil }) {
|
||||
blocks.add(src.copyRange(start, i));
|
||||
start = nil;
|
||||
};
|
||||
i = i + 1;
|
||||
} { i = i + 1 } } } } } };
|
||||
} } };
|
||||
};
|
||||
("[setupAll] " ++ label ++ " ... " ++ blocks.size ++ " blocs ").post;
|
||||
try {
|
||||
blocks.do { |b| b.interpret };
|
||||
" OK".postln;
|
||||
} { |err|
|
||||
" FAIL".postln;
|
||||
(" " ++ err.errorString).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- HELPER : ~check ------------------------------------------------
|
||||
// Affiche un rapport coloree (postln) listant l'etat de chaque
|
||||
// module. Utilise des prefixes ASCII :
|
||||
// [OK] = tout est la
|
||||
// [!!] = certains helpers manquent (action recommandee)
|
||||
// [--] = pas initialise (optionnel : MIDI, jump)
|
||||
// --------------------------------------------------------------------
|
||||
~check = {
|
||||
var sd = SynthDescLib.global.synthDescs;
|
||||
var hasSd = { |sym| sd[sym].notNil };
|
||||
var hasV = { |sym| currentEnvironment[sym].notNil };
|
||||
var allSd = { |list| list.every { |s| hasSd.(s) } };
|
||||
var allV = { |list| list.every { |s| hasV.(s) } };
|
||||
var missingSd = { |list| list.select { |s| hasSd.(s).not } };
|
||||
var missingV = { |list| list.select { |s| hasV.(s).not } };
|
||||
var actions = List.new;
|
||||
var line = { |label, status, msg|
|
||||
("[" ++ label ++ "]").padRight(13).post;
|
||||
status.post; " ".post; msg.postln;
|
||||
};
|
||||
|
||||
"".postln;
|
||||
"=== sound_algo STATUS ===".postln;
|
||||
|
||||
// ----- Server -----
|
||||
if (s.serverRunning) {
|
||||
("[server] running, " ++ s.numSynths ++ " synths, "
|
||||
++ s.avgCPU.round(0.1) ++ "% CPU").postln;
|
||||
} {
|
||||
"[server] [--] pas demarre (lance ~setupAll ou s.boot)".postln;
|
||||
actions.add("Lance ~setupAll.() pour booter le serveur");
|
||||
};
|
||||
|
||||
// ----- engine.scd -----
|
||||
block { |b|
|
||||
var engineSd = [\kick, \hat, \snare, \clap, \acid, \lead, \pad, \pluck,
|
||||
\fmBell, \stab, \saw3, \openHat, \crash, \tom, \rim,
|
||||
\cowbell, \reese, \bass808, \impact, \riser, \sweep,
|
||||
\vinyl, \masterLim];
|
||||
var engineHelpers = [\reload, \bpm, \kickAmp, \melodyAmp, \melodyNotes,
|
||||
\kickSteps, \scBus, \masterLim];
|
||||
var miss = missingSd.(engineSd) ++ missingV.(engineHelpers);
|
||||
if (miss.isEmpty) {
|
||||
line.("engine", "[OK]", engineSd.size.asString
|
||||
++ " SynthDefs + ~reload + ~scBus + ~masterLim");
|
||||
} {
|
||||
line.("engine", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("CHARGER TOUT depuis 00_load.scd (engine + synthdefs + scales + melodies + harmonics)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- synthdefs/asia.scd -----
|
||||
block { |b|
|
||||
var asia = [\koto, \erhu, \pipa, \gong, \growl, \reeseHard];
|
||||
var miss = missingSd.(asia);
|
||||
if (miss.isEmpty) { line.("asia", "[OK]", asia.size.asString ++ " SynthDefs"); }
|
||||
{ line.("asia", "[!!]", "manquant : " ++ miss); };
|
||||
};
|
||||
|
||||
// ----- synthdefs/extra.scd -----
|
||||
block { |b|
|
||||
var extra = [\squareLead, \fmLead, \organLead, \hardLead, \warmPad,
|
||||
\strings, \choir, \fmBass, \subBoom, \handpan, \flute, \drone];
|
||||
var miss = missingSd.(extra);
|
||||
if (miss.isEmpty) { line.("extra", "[OK]", extra.size.asString ++ " SynthDefs"); }
|
||||
{ line.("extra", "[!!]", "manquant : " ++ miss); };
|
||||
};
|
||||
|
||||
// ----- synthdefs/authentic.scd -----
|
||||
block { |b|
|
||||
var auth = [\kickGabber, \kick808, \snareGated, \reeseDnB, \supersaw,
|
||||
\hooverbass, \rhodes, \vocalPad, \didgeridoo, \guzheng,
|
||||
\shakuhachi, \taiko, \tabla, \scratch];
|
||||
var miss = missingSd.(auth);
|
||||
if (miss.isEmpty) { line.("authentic", "[OK]", auth.size.asString ++ " SynthDefs"); }
|
||||
{ line.("authentic", "[!!]", "manquant : " ++ miss); };
|
||||
};
|
||||
|
||||
// ----- palette/scales.scd -----
|
||||
block { |b|
|
||||
var scales = [\scaleMinor, \scaleDorian, \scaleMinorPent, \scaleAcid,
|
||||
\scaleHijaz, \scaleVietnam];
|
||||
var helpers = [\genMelody, \mutate, \octavate, \transpose, \retrograde,
|
||||
\densify, \sparsify, \jitter, \genAcidNotes, \genKickPattern,
|
||||
\randomTweak];
|
||||
var miss = missingV.(scales) ++ missingV.(helpers);
|
||||
if (miss.isEmpty) {
|
||||
line.("scales", "[OK]", "16 scales + ~genMelody/mutate/octavate/...");
|
||||
} {
|
||||
line.("scales", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("CHARGER TOUT (scales = source unique helpers melodiques)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- palette/melodies/* -----
|
||||
block { |b|
|
||||
var probes = [\m1, \m78, \ml1, \ml30, \mxl1, \mxl15, \mepic1, \mepic10,
|
||||
\melodyBank, \useMelody, \melodyByGenre, \chainPatterns, \buildArc];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("melodies", "[OK]",
|
||||
"~m1..78, ~ml1..30, ~mxl1..15, ~mepic1..10 + ~useMelody/byGenre");
|
||||
} {
|
||||
line.("melodies", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("CHARGER TOUT (charge palette/melodies/index.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- palette/harmonics/* -----
|
||||
block { |b|
|
||||
var probes = [\enableHarmony, \genThirdHarmony, \genFifthHarmony,
|
||||
\genCounterMelody, \genArpFromChords];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("harmonics", "[OK]", "~enableHarmony + 4 helpers");
|
||||
} {
|
||||
line.("harmonics", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("CHARGER TOUT (charge palette/harmonics/index.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- palette/melodies/tracks.scd (multi-pistes) -----
|
||||
block { |b|
|
||||
var probes = [\mel, \melTrackAdd, \melTrackOn, \melTrackOff, \melTrackSet,
|
||||
\melTrackList, \melTrackSolo];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("mel-track", "[OK]", "~mel + ~melTrackAdd/On/Off/Set/...");
|
||||
} {
|
||||
line.("mel-track", "[!!]", "manquant : " ++ miss);
|
||||
};
|
||||
};
|
||||
|
||||
// ----- live API wrappers (~kk / ~mm / ~ff / ~cc / ~p) -----
|
||||
// Ces wrappers (live/_load.scd) remplacent fonctionnellement les
|
||||
// ~kK1, ~clC1, ~pcP1 des palette/rhythm/* (qui sont multi-blocs).
|
||||
block { |b|
|
||||
var probes = [\kk, \kPat, \kTim, \kList,
|
||||
\mm, \mShort, \mLong, \mEpic, \mGen, \mList,
|
||||
\ff, \fxSnd, \fxSt, \fxDrop, \fxList,
|
||||
\chIntro, \chDrop, \chBuildup, \chList,
|
||||
\pKit, \pGenre, \pHat, \pList];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("live-api", "[OK]", "~kk ~mm ~ff ~chIntro ~pKit + 19 wrappers");
|
||||
} {
|
||||
line.("live-api", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance (~base++\"live/_load.scd\").load (charge les 5 wrappers live)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- palette/rhythm/fills.scd (~snareFill / ~tomFill) -----
|
||||
block { |b|
|
||||
var probes = [\snareFill, \tomFill];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("fills", "[OK]", "~snareFill / ~tomFill");
|
||||
} {
|
||||
line.("fills", "[!!]", "~snareFill et/ou ~tomFill manquent");
|
||||
actions.add("Lance ~setupAll.() (charge palette/rhythm/fills.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- palette/rhythm/sequences.scd (~seqPlay / ~seqIntro / ...) -----
|
||||
block { |b|
|
||||
var probes = [\seqPlay, \seqStop, \seqIntro, \seqBuildup, \seqDrop];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("sequences", "[OK]", "~seqPlay / ~seqIntro / ~seqBuildup / ~seqDrop / ...");
|
||||
} {
|
||||
line.("sequences", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance ~setupAll.() (charge palette/rhythm/sequences.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- palette/chords_progressions.scd -----
|
||||
block { |b|
|
||||
var probes = [\progDetroit, \progTrance, \progDnB, \chordsToMelody];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("chords", "[OK]", "~progXxx + ~chordsToMelody/Harmony");
|
||||
} {
|
||||
line.("chords", "[--]", "non charge (optionnel) : " ++ miss);
|
||||
};
|
||||
};
|
||||
|
||||
// ----- live/live.scd -----
|
||||
block { |b|
|
||||
var probes = [\lfoTo, \vcfOn, \drop, \breakdown, \stutter, \glitch,
|
||||
\freeze, \addFx, \compOn, \satOn];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("live", "[OK]", "~lfoTo / ~vcfOn / ~drop / ~stutter / ~addFx / ~compOn / ...");
|
||||
} {
|
||||
line.("live", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance ~setupAll.() (charge live/live.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- live/mixer.scd -----
|
||||
block { |b|
|
||||
var probes = [\setVol, \mute, \solo, \mixPreset, \mixMaster, \mix];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("mixer", "[OK]", "~setVol / ~mute / ~solo / ~mixPreset / ~mixMaster");
|
||||
} {
|
||||
line.("mixer", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance ~setupAll.() (charge live/mixer.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- live/fx_bus.scd -----
|
||||
block { |b|
|
||||
var probes = [\fxFx, \fxBuses, \send, \setFx, \lfo, \fxPreset, \tap];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("fx_bus", "[OK]", "9 bus FX + ~send / ~setFx / ~lfo / ~fxPreset / ~tap");
|
||||
} {
|
||||
line.("fx_bus", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance ~setupAll.() (charge live/fx_bus.scd EN PREMIER)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- live/scenes.scd -----
|
||||
block { |b|
|
||||
var probes = [\saveScene, \loadScene, \listScenes];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("scenes", "[OK]", "~saveScene / ~loadScene / ~listScenes");
|
||||
} {
|
||||
line.("scenes", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance ~setupAll.() (charge live/scenes.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- live/loops.scd -----
|
||||
block { |b|
|
||||
var probes = [\loopOn, \loopOff, \loopRepeat, \loopProgress, \loopList];
|
||||
var miss = missingV.(probes);
|
||||
if (miss.isEmpty) {
|
||||
line.("loops", "[OK]", "~loopOn / ~loopOff / ~loopRepeat / ~loopProgress");
|
||||
} {
|
||||
line.("loops", "[!!]", "manquant : " ++ miss);
|
||||
actions.add("Lance ~setupAll.() (charge live/loops.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- control/midi.scd (optionnel) -----
|
||||
block { |b|
|
||||
if (~midiFuncs.notNil and: { ~midiFuncs.size > 0 }) {
|
||||
line.("midi", "[OK]", "~midiFuncs (" ++ ~midiFuncs.size ++ " mappings)");
|
||||
} {
|
||||
line.("midi", "[--]", "pas init (optionnel) -- ouvre control/midi.scd");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- control/playlist.scd (optionnel) -----
|
||||
block { |b|
|
||||
if (hasV.(\playPlaylist)) {
|
||||
line.("playlist", "[OK]", "~playPlaylist pret");
|
||||
} {
|
||||
line.("playlist", "[--]", "pas charge (optionnel) -- ouvre control/playlist.scd");
|
||||
};
|
||||
};
|
||||
|
||||
// ----- control/jump.scd -----
|
||||
block { |b|
|
||||
if (hasV.(\jumpTo) and: { hasV.(\sections) }) {
|
||||
var nbTracks = ~sections.size;
|
||||
line.("jump", "[OK]", "~jumpTo + ~sections (" ++ nbTracks ++ " tracks chargees)");
|
||||
} {
|
||||
line.("jump", "[!!]", "pas init");
|
||||
actions.add("Lance ~setupAll.() (charge control/jump.scd)");
|
||||
};
|
||||
};
|
||||
|
||||
"=== fin status ===".postln;
|
||||
|
||||
if (actions.size > 0) {
|
||||
"".postln;
|
||||
"ACTIONS RECOMMANDEES :".postln;
|
||||
actions.do { |a| (" - " ++ a).postln };
|
||||
} {
|
||||
"".postln;
|
||||
"Tout est OK -- pret a jouer.".postln;
|
||||
};
|
||||
"".postln;
|
||||
};
|
||||
|
||||
|
||||
// --- HELPER : ~setupAll ---------------------------------------------
|
||||
// Charge engine + synthdefs + scales + melodies + harmonics, attend
|
||||
// le boot du serveur (skip si deja boote), puis evalue le 1er bloc
|
||||
// (SETUP) de chaque module live + rhythm/fills + rhythm/sequences +
|
||||
// control/jump. Termine par ~check.()
|
||||
//
|
||||
// Print clair de chaque etape via ~loadFirstBlock (qui catche les
|
||||
// erreurs : un fichier qui plante n'arrete PAS les autres).
|
||||
//
|
||||
// Ordre d'init des modules live :
|
||||
// 1. fx_bus.scd (alloue les bus FX, doit etre en PREMIER)
|
||||
// 2. live.scd (LFO/VCF/tricks/SynthDefs additionnels)
|
||||
// 3. mixer.scd (~mix / ~setVol / ~mute / ~solo)
|
||||
// 4. scenes.scd (~saveScene / ~loadScene)
|
||||
// 5. loops.scd (~loopOn / ~loopOff / ~loopRepeat)
|
||||
// 6. rhythm/fills.scd (~snareFill / ~tomFill)
|
||||
// 7. rhythm/sequences.scd (~seqPlay / ~seqIntro / ~seqDrop / ...)
|
||||
// 8. control/jump.scd (~jumpTo + ~sections)
|
||||
//
|
||||
// PAS init automatiquement :
|
||||
// - control/midi.scd (init MIDI -- a faire manuellement)
|
||||
// - control/playlist.scd (juste un helper, charge a la demande)
|
||||
// - live/tweaks.scd (one-liners, pas de SETUP)
|
||||
// --------------------------------------------------------------------
|
||||
~setupAll = {
|
||||
var liveSetup = {
|
||||
"".postln;
|
||||
"=== ~setupAll : init modules live ===".postln;
|
||||
|
||||
// Ordre critique : fx_bus.scd EN PREMIER (alloue ~fxBuses / ~fxFx
|
||||
// que les autres modules peuvent referencer)
|
||||
~loadFirstBlock.(~base ++ "live/fx_bus.scd");
|
||||
~loadFirstBlock.(~base ++ "live/live.scd");
|
||||
~loadFirstBlock.(~base ++ "live/mixer.scd");
|
||||
~loadFirstBlock.(~base ++ "live/scenes.scd");
|
||||
~loadFirstBlock.(~base ++ "live/loops.scd");
|
||||
~loadFirstBlock.(~base ++ "palette/rhythm/fills.scd");
|
||||
~loadAllBlocks.(~base ++ "palette/rhythm/sequences.scd");
|
||||
~loadFirstBlock.(~base ++ "control/jump.scd");
|
||||
|
||||
// 5 wrappers API live (~kk / ~mm / ~ff / ~cc / ~p) -- 1er bloc
|
||||
// chacun contient les definitions ; les blocs suivants sont des
|
||||
// exemples interactifs Cmd+Entree qu'on ne veut PAS executer au boot.
|
||||
~loadFirstBlock.(~base ++ "live/kicks.scd");
|
||||
~loadFirstBlock.(~base ++ "live/melodies.scd");
|
||||
~loadFirstBlock.(~base ++ "live/fx.scd");
|
||||
~loadFirstBlock.(~base ++ "live/chains.scd");
|
||||
~loadFirstBlock.(~base ++ "live/patterns.scd");
|
||||
|
||||
s.sync;
|
||||
"".postln;
|
||||
"=== setupAll DONE ===".postln;
|
||||
"".postln;
|
||||
~check.value;
|
||||
};
|
||||
|
||||
"=== ~setupAll : start ===".postln;
|
||||
~base = ~base ?? { "/Users/electron/Documents/Projets_Creatifs/sound_algo/" };
|
||||
|
||||
// --- 1. Charge tous les fichiers .load-compatibles ---
|
||||
"[setupAll] engine.scd ... loading".postln;
|
||||
(~base ++ "engine.scd").load;
|
||||
"[setupAll] synthdefs/asia.scd ... loading".postln;
|
||||
(~base ++ "synthdefs/asia.scd").load;
|
||||
"[setupAll] synthdefs/extra.scd ... loading".postln;
|
||||
(~base ++ "synthdefs/extra.scd").load;
|
||||
"[setupAll] synthdefs/authentic.scd ... loading".postln;
|
||||
(~base ++ "synthdefs/authentic.scd").load;
|
||||
"[setupAll] palette/scales.scd ... loading".postln;
|
||||
(~base ++ "palette/scales.scd").load;
|
||||
"[setupAll] palette/melodies/index.scd ... loading".postln;
|
||||
(~base ++ "palette/melodies/index.scd").load;
|
||||
"[setupAll] palette/harmonics/index.scd ... loading".postln;
|
||||
(~base ++ "palette/harmonics/index.scd").load;
|
||||
|
||||
// --- 2. Boot serveur (skip si deja boote) puis init modules live ---
|
||||
if (s.serverRunning) {
|
||||
"=== ~setupAll : serveur deja boote, skip waitForBoot ===".postln;
|
||||
liveSetup.value;
|
||||
} {
|
||||
"=== ~setupAll : boot serveur en cours... ===".postln;
|
||||
s.waitForBoot {
|
||||
s.sync;
|
||||
"=== ~setupAll : boot OK ===".postln;
|
||||
liveSetup.value;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- HELPER : ~setupLive --------------------------------------------
|
||||
// Charge UNIQUEMENT les modules live (ne touche pas engine /
|
||||
// synthdefs / scales / melodies / harmonics). Pour redemarrage
|
||||
// rapide quand le serveur tourne deja avec engine charge.
|
||||
// --------------------------------------------------------------------
|
||||
~setupLive = {
|
||||
~base = ~base ?? { "/Users/electron/Documents/Projets_Creatifs/sound_algo/" };
|
||||
if (s.serverRunning.not) {
|
||||
"!! ~setupLive : serveur pas demarre. Lance ~setupAll a la place.".postln;
|
||||
} {
|
||||
"=== ~setupLive : init modules live seulement ===".postln;
|
||||
~loadFirstBlock.(~base ++ "live/fx_bus.scd");
|
||||
~loadFirstBlock.(~base ++ "live/live.scd");
|
||||
~loadFirstBlock.(~base ++ "live/mixer.scd");
|
||||
~loadFirstBlock.(~base ++ "live/scenes.scd");
|
||||
~loadFirstBlock.(~base ++ "live/loops.scd");
|
||||
~loadFirstBlock.(~base ++ "palette/rhythm/fills.scd");
|
||||
~loadAllBlocks.(~base ++ "palette/rhythm/sequences.scd");
|
||||
~loadFirstBlock.(~base ++ "control/jump.scd");
|
||||
// 5 wrappers API live (~kk / ~mm / ~ff / ~cc / ~p)
|
||||
~loadFirstBlock.(~base ++ "live/kicks.scd");
|
||||
~loadFirstBlock.(~base ++ "live/melodies.scd");
|
||||
~loadFirstBlock.(~base ++ "live/fx.scd");
|
||||
~loadFirstBlock.(~base ++ "live/chains.scd");
|
||||
~loadFirstBlock.(~base ++ "live/patterns.scd");
|
||||
"=== ~setupLive : OK ===".postln;
|
||||
~check.value;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- HELPER : ~ensureLive -------------------------------------------
|
||||
// Helper paresseux : detecte ce qui manque dans live/* + fills +
|
||||
// sequences + jump et charge SEULEMENT les modules absents.
|
||||
// Idempotent : peut etre appele plusieurs fois sans rien recharger.
|
||||
// --------------------------------------------------------------------
|
||||
~ensureLive = {
|
||||
var loaded = 0;
|
||||
~base = ~base ?? { "/Users/electron/Documents/Projets_Creatifs/sound_algo/" };
|
||||
if (s.serverRunning.not) {
|
||||
"!! ~ensureLive : serveur pas demarre. Lance ~setupAll d'abord.".postln;
|
||||
} {
|
||||
// fx_bus en premier (les autres modules peuvent en dependre)
|
||||
if (~fxFx.isNil or: { ~send.isNil }) {
|
||||
"ensure : fx_bus.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/fx_bus.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~lfoTo.isNil or: { ~vcfOn.isNil }) {
|
||||
"ensure : live.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/live.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~setVol.isNil or: { ~mixPreset.isNil }) {
|
||||
"ensure : mixer.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/mixer.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~saveScene.isNil) {
|
||||
"ensure : scenes.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/scenes.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~loopOn.isNil) {
|
||||
"ensure : loops.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/loops.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~snareFill.isNil or: { ~tomFill.isNil }) {
|
||||
"ensure : fills.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "palette/rhythm/fills.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~seqPlay.isNil or: { ~seqIntro.isNil }) {
|
||||
"ensure : sequences.scd".postln;
|
||||
~loadAllBlocks.(~base ++ "palette/rhythm/sequences.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~jumpTo.isNil) {
|
||||
"ensure : jump.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "control/jump.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
// 5 wrappers API live (chacun expose un dict + des wrappers env)
|
||||
if (~kk.isNil) {
|
||||
"ensure : live/kicks.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/kicks.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~mm.isNil) {
|
||||
"ensure : live/melodies.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/melodies.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~ff.isNil) {
|
||||
"ensure : live/fx.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/fx.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~cc.isNil) {
|
||||
"ensure : live/chains.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/chains.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (~p.isNil) {
|
||||
"ensure : live/patterns.scd".postln;
|
||||
~loadFirstBlock.(~base ++ "live/patterns.scd");
|
||||
loaded = loaded + 1;
|
||||
};
|
||||
if (loaded == 0) {
|
||||
"=== ~ensureLive : tout est deja la, rien a charger ===".postln;
|
||||
} {
|
||||
("=== ~ensureLive : " ++ loaded ++ " module(s) charge(s) ===").postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// --- HELPER : ~teardown ---------------------------------------------
|
||||
// Stop tout proprement :
|
||||
// - ~track et autres routines
|
||||
// - tous les Pdef de l'engine
|
||||
// - LFO / VCF / loops / playlist / sequences
|
||||
// - libere ~masterLim et ~scBus
|
||||
// - libere les bus FX et synths FX si presents
|
||||
// --------------------------------------------------------------------
|
||||
~teardown = {
|
||||
"=== ~teardown : stop tout ===".postln;
|
||||
|
||||
// Routines de track / sweep / loops engine
|
||||
~track !? { ~track.stop; ~track = nil };
|
||||
~filterSweep !? { ~filterSweep.stop; ~filterSweep = nil };
|
||||
~randomLoop !? { ~randomLoop.stop; ~randomLoop = nil };
|
||||
~melodyEvolve !? { ~melodyEvolve.stop; ~melodyEvolve = nil };
|
||||
~lRotate !? { ~lRotate.stop; ~lRotate = nil };
|
||||
|
||||
// Tous les Pdef
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq,
|
||||
\acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
|
||||
// LFO live (live.scd)
|
||||
~lfoStopEverything !? { ~lfoStopEverything.value };
|
||||
|
||||
// LFO fx_bus (fx_bus.scd)
|
||||
~lfoStopAll !? { ~lfoStopAll.value };
|
||||
|
||||
// VCF master
|
||||
~vcfOff !? { ~vcfOff.value };
|
||||
|
||||
// Loops live
|
||||
~loopOffAll !? { ~loopOffAll.value };
|
||||
|
||||
// Sequences (palette/rhythm/sequences.scd)
|
||||
~seqStop !? { ~seqStop.value };
|
||||
|
||||
// Auto-fx (autoPan / tremolo)
|
||||
~stopAutoFx !? {
|
||||
[\kick, \hat, \snare, \clap, \perc, \acid, \melody, \harmony]
|
||||
.do { |v| ~stopAutoFx.(v) };
|
||||
};
|
||||
|
||||
// Compresseur / saturation master
|
||||
~compOff !? { ~compOff.value };
|
||||
~satOff !? { ~satOff.value };
|
||||
|
||||
// Playlist
|
||||
~playlist !? { ~playlist.stop; ~playlist = nil };
|
||||
|
||||
// Free pdef tracks melodiques (multi-pistes)
|
||||
~melTrackChoke !? { ~melTrackChoke.value };
|
||||
|
||||
// Master limiter + sidechain bus
|
||||
~masterLim !? { ~masterLim.free; ~masterLim = nil };
|
||||
~scBus !? { ~scBus.free; ~scBus = nil };
|
||||
|
||||
// Bus FX + synths FX
|
||||
~fxFx !? {
|
||||
~fxFx.do { |syn| syn !? { syn.free } };
|
||||
~fxFx = nil;
|
||||
};
|
||||
~fxBuses !? {
|
||||
~fxBuses.do { |b| b !? { b.free } };
|
||||
~fxBuses = nil;
|
||||
};
|
||||
|
||||
"=== ~teardown OK ===".postln;
|
||||
};
|
||||
|
||||
"~loadFirstBlock / ~check / ~setupAll / ~setupLive / ~ensureLive / ~teardown prets".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// BLOCS Cmd+Entree -- workflows manuels (executes a la demande)
|
||||
//
|
||||
// IMPORTANT : ces blocs sont COMMENTES car .load echoue avec >1 bloc
|
||||
// top-level. Pour les utiliser : DECOMMENTE la ligne (retire les "//")
|
||||
// puis Cmd+Entree dessus dans l'IDE. Ou copie-colle le contenu.
|
||||
// =====================================================================
|
||||
|
||||
// --- VERIF rapide de l'etat ----------
|
||||
// ( ~check.(); )
|
||||
|
||||
// --- INIT COMPLETE (charge tout + boot + setup live + check) ---------
|
||||
// ( ~setupAll.(); )
|
||||
|
||||
// --- INIT LIVE SEULEMENT (serveur deja boote) ------------------------
|
||||
// ( ~setupLive.(); )
|
||||
|
||||
// --- INIT PARESSEUSE (charge ce qui manque seulement) ----------------
|
||||
// ( ~ensureLive.(); )
|
||||
|
||||
// --- ARRET PROPRE ----------------------------------------------------
|
||||
// ( ~teardown.(); )
|
||||
|
||||
// --- COMBO : check d'abord, puis setup auto si besoin ----------------
|
||||
// ( ~check.(); ~setupAll.(); )
|
||||
|
||||
// --- COMBO : teardown puis re-setupAll (full restart sans rebooter) --
|
||||
// ( ~teardown.(); ~setupAll.(); )
|
||||
@@ -0,0 +1,47 @@
|
||||
# synthdefs/ — Instruments additionnels
|
||||
|
||||
Palettes exotiques : `asia.scd` (koto, erhu, gong, growl),
|
||||
`extra.scd`, `authentic.scd`. Charges automatiquement par
|
||||
`00_load.scd` apres `engine.scd`.
|
||||
|
||||
## Convention SynthDef
|
||||
|
||||
```supercollider
|
||||
SynthDef(\nomInstrument, {
|
||||
arg freq = 220, gate = 1,
|
||||
attack = 0.001, decay = 0.04, sustain = 0.5, release = 0.6,
|
||||
amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4; // sidechain
|
||||
var sig, env, duck;
|
||||
sig = ...; // synthese
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release),
|
||||
gate, doneAction: 2); // OBLIGATOIRE si gate
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
```
|
||||
|
||||
## Regles
|
||||
|
||||
- `doneAction: 2` obligatoire si l'instrument utilise `gate`
|
||||
(sinon Synth zombie)
|
||||
- Toujours `Pan2.ar(sig, pan)` pour stereo (pas `[sig, sig]`)
|
||||
- `scBus`/`scAmt` exposes pour sidechain (kick -> instruments)
|
||||
- `LeakDC.ar` apres feedback comb / waveshaping
|
||||
- `clip(min, max)` sur freq/cutoff pour eviter blow-up
|
||||
- Drive : `(sig * drive).tanh / drive.sqrt` (preserve le gain)
|
||||
|
||||
## Acces
|
||||
|
||||
Les nouveaux instruments deviennent disponibles via
|
||||
`~melodyInst = \koto`, `~kickInst = ...`, etc. Ils doivent suivre
|
||||
les memes args (freq, gate, amp) que les SynthDef du `engine.scd`
|
||||
pour etre interchangeables dans les Pdef.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Ne pas oublier `doneAction: 2` -> Synths qui s'accumulent en RAM
|
||||
- Ne pas utiliser `Out.ar` direct sans Pan -> mono qui casse le mixer
|
||||
- Ne pas laisser un `freq` non-clip -> NaN/Inf au synthe
|
||||
- Ne pas dupliquer un SynthDef existant dans `engine.scd`
|
||||
- Ne pas ajouter d'arg sans valeur par defaut (Pdef plante)
|
||||
@@ -0,0 +1,157 @@
|
||||
// =====================================================================
|
||||
// synthdefs_asia.scd -- Palette exotique pour mélodies asiatiques
|
||||
// (koto, erhu, gong, growl dubstep)
|
||||
//
|
||||
// USAGE : evaluer ce bloc une fois apres engine.scd. Les nouveaux
|
||||
// SynthDef sont disponibles dans ~melodyInst (\koto, \erhu, ...)
|
||||
// et via Synth direct pour les FX (\gong, \growl).
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
// ----- Koto (corde asiatique pincee : Karplus-Strong + brillant) -----
|
||||
// son percussif, decay long, fondamentale + 2 harmoniques claires
|
||||
SynthDef(\koto, {
|
||||
arg freq = 220, gate = 1, cutoff = 6000, rq = 0.5,
|
||||
attack = 0.001, decay = 0.04, sustain = 0.0, release = 0.6,
|
||||
drive = 1.2, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, exciter, ks, harm;
|
||||
exciter = WhiteNoise.ar(0.6) * EnvGen.kr(Env.perc(0.0005, 0.003));
|
||||
ks = LeakDC.ar(CombC.ar(exciter, 0.05, freq.reciprocal, 3.0));
|
||||
// Harmonique 2 (octave) ajoute pour brillance koto
|
||||
harm = LeakDC.ar(CombC.ar(exciter * 0.3, 0.05, (freq * 2).reciprocal, 1.5));
|
||||
sig = LPF.ar(ks + harm, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Erhu (violon chinois -- saw filtre + portamento + vibrato) ---
|
||||
// corde frottee, sustain naturel, vibrato lent
|
||||
SynthDef(\erhu, {
|
||||
arg freq = 440, gate = 1,
|
||||
cutoff = 2500, rq = 0.4,
|
||||
vibratoRate = 5.5, vibratoDepth = 0.015,
|
||||
attack = 0.05, decay = 0.1, sustain = 0.6, release = 0.3,
|
||||
drive = 1.3, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, vibFreq;
|
||||
// Vibrato sinusoidal (apres petit delay pour entrer doucement)
|
||||
vibFreq = freq * (1 + (SinOsc.kr(vibratoRate,
|
||||
EnvGen.kr(Env([0, 0, 1], [0.1, 0.3])) * pi) * vibratoDepth));
|
||||
sig = (Saw.ar(vibFreq) * 0.6) + (Pulse.ar(vibFreq * 1.005, 0.4) * 0.4);
|
||||
sig = RLPF.ar(sig, cutoff, rq);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Pipa (luth chinois : pluck + decay rapide + bend) -------------
|
||||
SynthDef(\pipa, {
|
||||
arg freq = 330, gate = 1, bendAmt = 0.04, bendTime = 0.08,
|
||||
cutoff = 4500, rq = 0.4,
|
||||
attack = 0.001, decay = 0.06, sustain = 0.0, release = 0.4,
|
||||
drive = 1.5, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, exciter, ks, bentFreq;
|
||||
// Petit bend de pitch initial (caracteristique pipa)
|
||||
bentFreq = freq * (1 + EnvGen.kr(Env([bendAmt, 0], [bendTime], -3)));
|
||||
exciter = WhiteNoise.ar(0.7) * EnvGen.kr(Env.perc(0.0005, 0.004));
|
||||
ks = LeakDC.ar(CombC.ar(exciter, 0.05, bentFreq.reciprocal, 1.8));
|
||||
sig = LPF.ar(ks, cutoff);
|
||||
sig = (sig * drive).tanh;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Gong (FX oneshot : metallique avec long decay + pitch drop) --
|
||||
SynthDef(\gong, {
|
||||
arg freq = 80, decay = 4, amp = 0.5, pan = 0;
|
||||
var sig, env, partials, pitchEnv;
|
||||
// Pitch drop expo (caracteristique gong)
|
||||
pitchEnv = EnvGen.kr(Env([freq * 1.3, freq], [0.15], \exp));
|
||||
// Plusieurs partiels inharmoniques (gong : ratios non-entiers)
|
||||
partials = [1, 1.41, 1.93, 2.71, 3.42, 4.83];
|
||||
sig = Mix.fill(partials.size, { |i|
|
||||
SinOsc.ar(pitchEnv * partials[i]) *
|
||||
(1 / (i + 1)) *
|
||||
EnvGen.kr(Env.perc(0.005, decay * (1 - (i * 0.12)), 1, -3 - i));
|
||||
});
|
||||
sig = sig + (HPF.ar(WhiteNoise.ar, 4000) *
|
||||
EnvGen.kr(Env.perc(0.001, 0.05)) * 0.3);
|
||||
env = EnvGen.kr(Env.linen(0.001, decay, 0.05), doneAction: 2);
|
||||
sig = (sig * 1.3).tanh;
|
||||
sig = LeakDC.ar(sig) * env * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Growl (hard dubstep -- saturation maitrisee) -----------------
|
||||
// Saws detunes + FM legere + sub charpente + RLPF wobble + tanh
|
||||
// simple normalise. Headroom protege le master limiter.
|
||||
SynthDef(\growl, {
|
||||
arg freq = 55, gate = 1,
|
||||
modRatio = 0.5, modIndex = 4,
|
||||
wobbleRate = 4, wobbleDepth = 2500, wobbleShape = 0,
|
||||
cutoff = 250, rq = 0.25,
|
||||
subAmt = 0.7, detune = 0.012,
|
||||
attack = 0.005, decay = 0.2, sustain = 0.7, release = 0.3,
|
||||
drive = 3.0, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, sub, mod, carL, carR, wobble, lfo;
|
||||
lfo = SelectX.kr(wobbleShape, [
|
||||
LFTri.kr(wobbleRate),
|
||||
LFPulse.kr(wobbleRate, 0, 0.5, 2, -1)
|
||||
]);
|
||||
wobble = (cutoff + (lfo.range(0, 1) * wobbleDepth)).clip(60, 10000);
|
||||
// FM modulee (modIndex 4 max -- pas trop violent)
|
||||
mod = SinOsc.ar(freq * modRatio) * freq * modIndex * 0.0008;
|
||||
carL = Saw.ar(freq * (1 - detune) + mod);
|
||||
carR = Saw.ar(freq * (1 + detune) + mod);
|
||||
// Sub charpente (2 oscillateurs, normalisees a 1)
|
||||
sub = ((SinOsc.ar(freq * 0.5) * 0.6) +
|
||||
(SinOsc.ar(freq * 0.25) * 0.4)) * subAmt;
|
||||
// Mix : carrieres a 0.4 chacune + sub a 0.5 = headroom
|
||||
sig = [(carL * 0.4) + (sub * 0.5), (carR * 0.4) + (sub * 0.5)];
|
||||
sig = RLPF.ar(sig, wobble, rq);
|
||||
// UN seul tanh + normalisation par sqrt(drive)
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
sig = Balance2.ar(sig[0], sig[1], pan);
|
||||
Out.ar(0, sig);
|
||||
}).add;
|
||||
|
||||
// ----- Reese aggressive (hard DnB / dubstep) ------------------------
|
||||
// Filtre passe-bande resonant + LFO sur depth + drive max
|
||||
SynthDef(\reeseHard, {
|
||||
arg freq = 55, gate = 1, detune = 0.018,
|
||||
cutoff = 600, rq = 0.15,
|
||||
modRate = 0.3, modDepth = 400, // LFO sur cutoff (slow sweep)
|
||||
attack = 0.005, decay = 0.1, sustain = 0.7, release = 0.2,
|
||||
drive = 4.0, amp = 0.3, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, fc;
|
||||
fc = (cutoff + (SinOsc.kr(modRate) * modDepth)).clip(80, 6000);
|
||||
sig = (Saw.ar(freq * (1 - detune)) * 0.4) +
|
||||
(Saw.ar(freq * (1 + detune)) * 0.4) +
|
||||
(Saw.ar(freq * 0.5) * 0.3) +
|
||||
(Pulse.ar(freq * 1.501, 0.5) * 0.2);
|
||||
sig = BPF.ar(sig, fc, rq) * 4;
|
||||
sig = LPF.ar(sig, 4000);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
sig = (sig * 1.3).tanh;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
"=== synthdefs_asia.scd : 6 nouveaux SynthDef charges ===".postln;
|
||||
" melodiques : \\koto \\erhu \\pipa".postln;
|
||||
" FX oneshot : \\gong".postln;
|
||||
" bass dubstep: \\growl \\reeseHard".postln;
|
||||
)
|
||||
@@ -0,0 +1,317 @@
|
||||
// =====================================================================
|
||||
// authentic.scd -- Instruments authentiques par genre (deep recherche)
|
||||
//
|
||||
// Couvre : kick gabber overdrive 909, reese DnB FM, supersaw trance,
|
||||
// Rhodes Detroit, hooverbass, vocal chop, taiko, tabla, didgeridoo,
|
||||
// guzheng (harpe chinoise), DX7 epiano, pad Juno-106, Linn-style snare,
|
||||
// cowbell Memphis 808, sub 808 trap, vocal pad
|
||||
//
|
||||
// USAGE : Cmd+Entree apres engine.scd. Tous compatibles ~melodyInst.
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
|
||||
// ----- Kick gabber (909 overdriven cliped, occupe le spectre) -----
|
||||
SynthDef(\kickGabber, {
|
||||
arg freq = 50, decay = 0.32, drive = 6.0, click = 0.4,
|
||||
amp = 0.55, pan = 0,
|
||||
scBus = 0, scShape = 0.18;
|
||||
var pEnv, body, sub, clickSig, ampEnv, sig, scEnv;
|
||||
pEnv = EnvGen.kr(Env([freq * 4, freq], [0.04], -3));
|
||||
body = SinOsc.ar(pEnv) + (Saw.ar(pEnv) * 0.3);
|
||||
sub = SinOsc.ar(freq * 0.5);
|
||||
clickSig = HPF.ar(WhiteNoise.ar, 4000) *
|
||||
EnvGen.kr(Env.perc(0.0005, 0.005));
|
||||
sig = body + (sub * 0.4) + (clickSig * click);
|
||||
ampEnv = EnvGen.kr(Env.perc(0.001, decay, curve: -3), doneAction: 2);
|
||||
sig = (sig * drive).clip(-1, 1); // hard clip gabber
|
||||
sig = (sig * 1.4).tanh;
|
||||
sig = sig * ampEnv;
|
||||
sig = LeakDC.ar(sig) * amp;
|
||||
scEnv = EnvGen.kr(Env.perc(0.001, scShape, curve: -4));
|
||||
Out.kr(scBus, scEnv);
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Reese bass DnB (FM brutal + mod chaos) ---------------------
|
||||
SynthDef(\reeseDnB, {
|
||||
arg freq = 55, gate = 1, detune = 0.018,
|
||||
cutoff = 800, rq = 0.2,
|
||||
modRate1 = 0.25, modDepth1 = 600,
|
||||
modRate2 = 0.7, modDepth2 = 250,
|
||||
attack = 0.005, decay = 0.1, sustain = 0.7, release = 0.2,
|
||||
drive = 4.0, amp = 0.30, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, fc, sub;
|
||||
fc = (cutoff + (SinOsc.kr(modRate1) * modDepth1)
|
||||
+ (SinOsc.kr(modRate2) * modDepth2)).clip(80, 8000);
|
||||
sig = (Saw.ar(freq * (1 - detune)) * 0.4) +
|
||||
(Saw.ar(freq * (1 + detune)) * 0.4) +
|
||||
(Saw.ar(freq * (1 + (detune * 2.7))) * 0.3);
|
||||
sub = SinOsc.ar(freq * 0.5) * 0.5;
|
||||
sig = BPF.ar(sig, fc, rq) * 4 + sub;
|
||||
sig = LPF.ar(sig, 4500);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Supersaw Trance (12 voix detunees + chorus + LP) ---------
|
||||
SynthDef(\supersaw, {
|
||||
arg freq = 220, gate = 1, detune = 0.018, mix = 0.5,
|
||||
cutoff = 4500, rq = 0.5,
|
||||
attack = 0.005, decay = 0.15, sustain = 0.6, release = 0.4,
|
||||
drive = 1.2, amp = 0.16, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, voices, center, sides;
|
||||
// 7 voix detunees (style JP-8000 supersaw)
|
||||
voices = (-3..3).collect { |i|
|
||||
Saw.ar(freq * (1 + (i * detune)))
|
||||
};
|
||||
center = voices[3];
|
||||
sides = voices.removeAt(3);
|
||||
sig = (center * (1 - mix)) + (Mix(voices) * mix * 0.18);
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
// Chorus stereo
|
||||
sig = [DelayC.ar(sig, 0.03, SinOsc.kr(0.4, 0).range(0.005, 0.018)),
|
||||
DelayC.ar(sig, 0.03, SinOsc.kr(0.5, pi).range(0.005, 0.018))];
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = Balance2.ar(sig[0], sig[1], pan);
|
||||
Out.ar(0, sig * env * amp * duck);
|
||||
}).add;
|
||||
|
||||
// ----- Rhodes Detroit (DX7 e-piano simulation) -------------------
|
||||
SynthDef(\rhodes, {
|
||||
arg freq = 440, gate = 1,
|
||||
modRatio = 14, modIndex = 0.4, // Rhodes : 14:1 ratio
|
||||
cutoff = 4000, rq = 0.6,
|
||||
attack = 0.002, decay = 0.2, sustain = 0.0, release = 0.8,
|
||||
drive = 1.1, amp = 0.20, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, mod, idxEnv, chorus;
|
||||
idxEnv = EnvGen.kr(Env([modIndex * 2, 0], [0.4], -3));
|
||||
mod = SinOsc.ar(freq * modRatio) * freq * idxEnv;
|
||||
sig = SinOsc.ar(freq + (mod * 0.5));
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
chorus = DelayC.ar(sig, 0.02, SinOsc.kr(0.7).range(0.002, 0.012));
|
||||
sig = sig + (chorus * 0.4);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release, curve: -4),
|
||||
gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Hooverbass Gabber/Trance (Roland Alpha Juno PWM detuned) -
|
||||
SynthDef(\hooverbass, {
|
||||
arg freq = 110, gate = 1, detune = 0.012,
|
||||
cutoff = 3500, rq = 0.4,
|
||||
attack = 0.001, decay = 0.1, sustain = 0.7, release = 0.2,
|
||||
drive = 1.6, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, voices, pwm;
|
||||
pwm = LFTri.kr(0.3).range(0.3, 0.7);
|
||||
voices = [
|
||||
Saw.ar(freq * (1 - detune)) * 0.4,
|
||||
Saw.ar(freq * (1 + detune)) * 0.4,
|
||||
Pulse.ar(freq * 0.5, pwm) * 0.3, // sub octave
|
||||
Pulse.ar(freq * 2 * (1 + (detune * 1.5)), pwm) * 0.2 // octave aigu
|
||||
];
|
||||
sig = Mix(voices);
|
||||
sig = RLPF.ar(sig, cutoff, rq);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Vocal pad (formants vocaux + chorus + reverb-like) -------
|
||||
SynthDef(\vocalPad, {
|
||||
arg freq = 220, gate = 1,
|
||||
// Formants pour voyelle "ah" : 700/1220/2600
|
||||
f1 = 700, f2 = 1220, f3 = 2600,
|
||||
attack = 0.4, decay = 0.3, sustain = 0.7, release = 1.5,
|
||||
drive = 1.0, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.3;
|
||||
var sig, env, duck, src, vib;
|
||||
vib = freq * (1 + (SinOsc.kr(4.5).range(-1, 1) *
|
||||
EnvGen.kr(Env([0, 0, 0.012], [0.3, 0.5]))));
|
||||
src = (Saw.ar(vib) * 0.5) + (SinOsc.ar(vib * 0.5) * 0.4);
|
||||
sig = (BPF.ar(src, f1, 0.12) * 1.0) +
|
||||
(BPF.ar(src, f2, 0.18) * 0.6) +
|
||||
(BPF.ar(src, f3, 0.30) * 0.3);
|
||||
// Faux chorus stereo
|
||||
sig = [DelayC.ar(sig, 0.04, SinOsc.kr(0.5, 0).range(0.008, 0.025)),
|
||||
DelayC.ar(sig, 0.04, SinOsc.kr(0.55, pi).range(0.008, 0.025))];
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = Balance2.ar(sig[0], sig[1], pan);
|
||||
Out.ar(0, sig * env * amp * duck);
|
||||
}).add;
|
||||
|
||||
// ----- Taiko (Japanese big drum -- thick body + skin attack) ----
|
||||
SynthDef(\taiko, {
|
||||
arg freq = 70, decay = 0.6, drive = 1.4, amp = 0.5, pan = 0;
|
||||
var pEnv, body, skin, env, sig;
|
||||
pEnv = EnvGen.kr(Env([freq * 1.5, freq], [0.04], -3));
|
||||
body = SinOsc.ar(pEnv) + (Saw.ar(pEnv) * 0.15);
|
||||
skin = HPF.ar(WhiteNoise.ar, 800) *
|
||||
EnvGen.kr(Env.perc(0.001, 0.04));
|
||||
sig = body + (skin * 0.4);
|
||||
env = EnvGen.kr(Env.perc(0.003, decay, curve: -3), doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
sig = LeakDC.ar(sig) * env * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Tabla (Indian drum -- pitched + slap) -------------------
|
||||
SynthDef(\tabla, {
|
||||
arg freq = 220, decay = 0.18, drive = 1.3, amp = 0.4, pan = 0;
|
||||
var pEnv, body, slap, env, sig;
|
||||
pEnv = EnvGen.kr(Env([freq * 3, freq], [0.02], -4));
|
||||
body = SinOsc.ar(pEnv) + (SinOsc.ar(pEnv * 1.5) * 0.2);
|
||||
slap = HPF.ar(WhiteNoise.ar, 2500) *
|
||||
EnvGen.kr(Env.perc(0.001, 0.012));
|
||||
sig = body + (slap * 0.5);
|
||||
env = EnvGen.kr(Env.perc(0.002, decay, curve: -4), doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
sig = LeakDC.ar(sig) * env * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Didgeridoo (drone aborigene avec growl harmonique) ------
|
||||
SynthDef(\didgeridoo, {
|
||||
arg freq = 60, gate = 1,
|
||||
growlRate = 4, growlDepth = 0.15,
|
||||
attack = 0.5, decay = 0.3, sustain = 0.85, release = 1.0,
|
||||
drive = 1.5, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.3;
|
||||
var sig, env, duck, growl, harmonics;
|
||||
growl = SinOsc.kr(growlRate * (1 + LFNoise2.kr(0.5).range(-0.15, 0.15)))
|
||||
.range(1 - growlDepth, 1 + growlDepth);
|
||||
harmonics = (Saw.ar(freq * growl) * 0.4) +
|
||||
(Pulse.ar(freq * 2 * growl, 0.3) * 0.2) +
|
||||
(Pulse.ar(freq * 3 * growl, 0.4) * 0.15) +
|
||||
(SinOsc.ar(freq * 0.5) * 0.5);
|
||||
sig = LPF.ar(harmonics, 1200);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig) * env * amp * duck;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Guzheng (harpe chinoise -- corde + decay long + bend) ---
|
||||
SynthDef(\guzheng, {
|
||||
arg freq = 220, gate = 1,
|
||||
bendAmt = 0.025, bendTime = 0.3,
|
||||
cutoff = 5500, rq = 0.4,
|
||||
attack = 0.001, decay = 0.05, sustain = 0.0, release = 1.5,
|
||||
drive = 1.1, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, exciter, ks, harm, bentFreq;
|
||||
// Bend caracteristique guzheng (slide vers la note finale)
|
||||
bentFreq = freq * (1 + EnvGen.kr(Env([bendAmt, 0], [bendTime], -2)));
|
||||
exciter = WhiteNoise.ar(0.6) * EnvGen.kr(Env.perc(0.0005, 0.003));
|
||||
ks = LeakDC.ar(CombC.ar(exciter, 0.05, bentFreq.reciprocal, 4.0));
|
||||
// Harmonique octave + 5te (caractere chinois)
|
||||
harm = LeakDC.ar(CombC.ar(exciter * 0.25, 0.05, (bentFreq * 1.5).reciprocal, 2.0));
|
||||
sig = LPF.ar(ks + harm, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Shakuhachi (flute japonaise avec breath + bend) ---------
|
||||
SynthDef(\shakuhachi, {
|
||||
arg freq = 440, gate = 1,
|
||||
breathAmt = 0.25, vibratoRate = 4.5, vibratoDepth = 0.018,
|
||||
cutoff = 3000, rq = 0.5,
|
||||
attack = 0.12, decay = 0.1, sustain = 0.7, release = 0.4,
|
||||
drive = 1.0, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, vibFreq, breath, body, bendEnv;
|
||||
bendEnv = EnvGen.kr(Env([0.97, 1.0], [0.08], -2)); // attack bend (style shakuhachi)
|
||||
vibFreq = freq * bendEnv * (1 + (SinOsc.kr(vibratoRate,
|
||||
EnvGen.kr(Env([0, 0, 1], [0.3, 0.4])) * pi) * vibratoDepth));
|
||||
body = SinOsc.ar(vibFreq) +
|
||||
(SinOsc.ar(vibFreq * 2) * 0.18) +
|
||||
(SinOsc.ar(vibFreq * 3) * 0.06);
|
||||
breath = HPF.ar(WhiteNoise.ar, 2000) * breathAmt *
|
||||
EnvGen.kr(Env([0.4, 1, 0.5], [0.05, 0.5]));
|
||||
sig = body + breath;
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Kick 808 trap (sub long avec pitch slide) ---------------
|
||||
SynthDef(\kick808, {
|
||||
arg freq = 50, glide = 0.04, decay = 0.7,
|
||||
drive = 1.4, amp = 0.6, pan = 0,
|
||||
scBus = 0, scShape = 0.18;
|
||||
var pEnv, body, click, ampEnv, sig, scEnv;
|
||||
pEnv = EnvGen.kr(Env([freq * 5, freq], [0.025], \exp));
|
||||
body = SinOsc.ar(pEnv);
|
||||
click = HPF.ar(WhiteNoise.ar, 1500) *
|
||||
EnvGen.kr(Env.perc(0.0005, 0.003));
|
||||
ampEnv = EnvGen.kr(Env.perc(0.003, decay, curve: -3), doneAction: 2);
|
||||
sig = body + (click * 0.15);
|
||||
sig = (sig * drive).tanh;
|
||||
sig = sig * ampEnv;
|
||||
sig = LeakDC.ar(sig) * amp;
|
||||
scEnv = EnvGen.kr(Env.perc(0.001, scShape, curve: -4));
|
||||
Out.kr(scBus, scEnv);
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Snare gated reverb 80s (LinnDrum + Lexicon 224) ----------
|
||||
SynthDef(\snareGated, {
|
||||
arg freq = 200, decay = 0.2, gateTime = 0.15,
|
||||
amp = 0.5, pan = 0;
|
||||
var tone, noise, env, gate, sig;
|
||||
tone = SinOsc.ar(freq) * EnvGen.kr(Env.perc(0.001, 0.04));
|
||||
noise = HPF.ar(WhiteNoise.ar, 1200) *
|
||||
EnvGen.kr(Env.perc(0.001, decay));
|
||||
sig = (tone * 0.4) + (noise * 0.6);
|
||||
// Gated reverb : signal + reverb tronque par envelope gate
|
||||
sig = sig + (CombC.ar(sig, 0.05, 0.04, 0.3) *
|
||||
EnvGen.kr(Env([0, 1, 1, 0], [0.001, gateTime, 0.005])));
|
||||
env = EnvGen.kr(Env.linen(0.001, gateTime, 0.005), doneAction: 2);
|
||||
sig = (sig * 1.4).tanh;
|
||||
sig = LeakDC.ar(sig) * env * amp;
|
||||
Out.ar(0, Pan2.ar(sig, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Vinyl scratch / glitch FX ------------------------------
|
||||
SynthDef(\scratch, {
|
||||
arg dur = 0.5, freq = 800, sweepDir = 1, amp = 0.3, pan = 0;
|
||||
var sig, env, sweepFreq;
|
||||
sweepFreq = Select.kr(sweepDir > 0, [
|
||||
Line.kr(freq * 2, freq * 0.5, dur),
|
||||
Line.kr(freq * 0.5, freq * 2, dur)
|
||||
]);
|
||||
sig = (SinOsc.ar(sweepFreq) * 0.5) +
|
||||
(HPF.ar(WhiteNoise.ar, sweepFreq * 0.8) * 0.3);
|
||||
sig = sig * LFPulse.kr(20).range(0.3, 1); // stutter
|
||||
env = EnvGen.kr(Env.linen(0.005, dur, 0.02), doneAction: 2);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp, pan));
|
||||
}).add;
|
||||
|
||||
"=== authentic.scd : 14 nouveaux SynthDef ===".postln;
|
||||
" drums : \\kickGabber \\kick808 \\snareGated \\taiko \\tabla".postln;
|
||||
" basses : \\reeseDnB \\hooverbass".postln;
|
||||
" leads : \\supersaw \\rhodes".postln;
|
||||
" pads/voc : \\vocalPad".postln;
|
||||
" world : \\didgeridoo \\guzheng \\shakuhachi".postln;
|
||||
" fx : \\scratch".postln;
|
||||
)
|
||||
@@ -0,0 +1,267 @@
|
||||
// =====================================================================
|
||||
// synthdefs_extra.scd -- Palette etendue : leads, pads, bass, world
|
||||
//
|
||||
// Tous compatibles ~melodyInst (freq/gate/cutoff/attack/release/drive/
|
||||
// amp/pan/scBus/scAmt). Ajoutent du caractere a la palette de base.
|
||||
//
|
||||
// USAGE : Cmd+Entree sur le bloc apres engine.scd. Puis utiliser via
|
||||
// (~melodyInst = \squareLead; ~reload.value;)
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
|
||||
// ----- Square Lead (chiptune / 8-bit avec PWM) ---------------------
|
||||
SynthDef(\squareLead, {
|
||||
arg freq = 440, gate = 1, pwmRate = 0.5, pwmDepth = 0.3,
|
||||
cutoff = 5000, rq = 0.6,
|
||||
attack = 0.005, decay = 0.1, sustain = 0.5, release = 0.25,
|
||||
drive = 1.4, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, pw;
|
||||
pw = SinOsc.kr(pwmRate).range(0.5 - pwmDepth, 0.5 + pwmDepth);
|
||||
sig = Pulse.ar(freq, pw);
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- FM Lead (style Yamaha DX, 2 operateurs) ----------------------
|
||||
SynthDef(\fmLead, {
|
||||
arg freq = 440, gate = 1,
|
||||
modRatio = 2.0, modIndex = 3,
|
||||
cutoff = 6000, rq = 0.7,
|
||||
attack = 0.003, decay = 0.15, sustain = 0.6, release = 0.4,
|
||||
drive = 1.2, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, mod, idxEnv;
|
||||
// Index modulation qui decroit (caracteristique FM)
|
||||
idxEnv = EnvGen.kr(Env([modIndex, modIndex * 0.3], [0.3], -3));
|
||||
mod = SinOsc.ar(freq * modRatio) * freq * idxEnv * 0.001;
|
||||
sig = SinOsc.ar(freq + (mod * freq));
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Organ Lead (drawbar orgue Hammond-like) ---------------------
|
||||
SynthDef(\organLead, {
|
||||
arg freq = 440, gate = 1,
|
||||
cutoff = 4500, rq = 0.5,
|
||||
attack = 0.005, decay = 0.05, sustain = 0.85, release = 0.15,
|
||||
drive = 1.3, amp = 0.16, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, drawbars;
|
||||
// 6 drawbars : sub, fund, octave, 12th, 15th, 17th
|
||||
drawbars = [0.5, 1, 2, 3, 4, 5];
|
||||
sig = Mix.fill(drawbars.size, { |i|
|
||||
SinOsc.ar(freq * drawbars[i]) * (1 / (i + 1));
|
||||
}) * 0.6;
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
sig = sig + (sig * SinOsc.kr(6.5, 0).range(0.7, 1)); // leslie tremolo leger
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Hard Lead (saw avec hard sync, brillant) ---------------------
|
||||
SynthDef(\hardLead, {
|
||||
arg freq = 440, gate = 1, syncRatio = 1.5,
|
||||
cutoff = 5500, rq = 0.4,
|
||||
attack = 0.002, decay = 0.08, sustain = 0.6, release = 0.25,
|
||||
drive = 1.8, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck;
|
||||
// Sync : oscillateur slave reset par master
|
||||
sig = SyncSaw.ar(freq, freq * syncRatio);
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Warm Pad (super-saw 7 voix + LPF doux + chorus stereo) -------
|
||||
SynthDef(\warmPad, {
|
||||
arg freq = 220, gate = 1, detune = 0.014,
|
||||
cutoff = 1800, rq = 0.7,
|
||||
attack = 0.6, decay = 0.4, sustain = 0.8, release = 2.0,
|
||||
drive = 1.0, amp = 0.14, pan = 0,
|
||||
scBus = 0, scAmt = 0.3;
|
||||
var sig, env, duck, oscs, chorusL, chorusR;
|
||||
// 7 oscillateurs detunes
|
||||
oscs = Mix.fill(7, { |i|
|
||||
Saw.ar(freq * (1 + ((i - 3) * detune)))
|
||||
}) * 0.18;
|
||||
oscs = LPF.ar(oscs, cutoff);
|
||||
// Chorus stereo profond
|
||||
chorusL = DelayC.ar(oscs, 0.05, SinOsc.kr(0.3, 0).range(0.005, 0.025));
|
||||
chorusR = DelayC.ar(oscs, 0.05, SinOsc.kr(0.4, pi).range(0.005, 0.025));
|
||||
sig = [oscs + (chorusL * 0.5), oscs + (chorusR * 0.5)];
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = Balance2.ar(sig[0], sig[1], pan);
|
||||
Out.ar(0, sig * env * amp * duck);
|
||||
}).add;
|
||||
|
||||
// ----- Strings (ensemble orchestral, 5 voix detunees stochastiquement) ---
|
||||
SynthDef(\strings, {
|
||||
arg freq = 440, gate = 1, detune = 0.008,
|
||||
cutoff = 3500, rq = 0.6,
|
||||
attack = 0.3, decay = 0.2, sustain = 0.85, release = 1.2,
|
||||
drive = 1.1, amp = 0.16, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, voices;
|
||||
voices = Mix.fill(5, { |i|
|
||||
var f = freq * (1 + (LFNoise2.kr(0.3 + (i * 0.1)) * detune));
|
||||
Saw.ar(f) + (Pulse.ar(f * 1.005, 0.4) * 0.3);
|
||||
}) * 0.15;
|
||||
voices = RLPF.ar(voices, cutoff, rq);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (voices * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Choir (voix synthetique via formants vocaux) -----------------
|
||||
SynthDef(\choir, {
|
||||
arg freq = 220, gate = 1,
|
||||
formant1 = 800, formant2 = 1150, formant3 = 2900,
|
||||
attack = 0.4, decay = 0.3, sustain = 0.7, release = 1.5,
|
||||
drive = 1.0, amp = 0.16, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, src, vib;
|
||||
// Vibrato lent humain
|
||||
vib = freq * (1 + (SinOsc.kr(5, 0,
|
||||
EnvGen.kr(Env([0, 0, 0.015], [0.5, 0.5]))).abs));
|
||||
// Source : saw filtree + sub
|
||||
src = Saw.ar(vib) + (SinOsc.ar(vib * 0.5) * 0.4);
|
||||
// 3 formants vocaux (a, e, o)
|
||||
sig = (BPF.ar(src, formant1, 0.15) * 1.0) +
|
||||
(BPF.ar(src, formant2, 0.20) * 0.5) +
|
||||
(BPF.ar(src, formant3, 0.30) * 0.25);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- FM Bass (techno classic, ratio 2:1) --------------------------
|
||||
SynthDef(\fmBass, {
|
||||
arg freq = 55, gate = 1, modRatio = 2, modIndex = 5,
|
||||
cutoff = 1800, rq = 0.5,
|
||||
attack = 0.003, decay = 0.15, sustain = 0.6, release = 0.2,
|
||||
drive = 1.6, amp = 0.32, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var sig, env, duck, mod, idxEnv;
|
||||
idxEnv = EnvGen.kr(Env([modIndex, 0], [0.2], -3));
|
||||
mod = SinOsc.ar(freq * modRatio) * freq * idxEnv * 0.001;
|
||||
sig = SinOsc.ar(freq + (mod * freq * 0.8)) +
|
||||
(Saw.ar(freq) * 0.3);
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Sub Boom (sub-bass 808 amplified avec saturation tape) ------
|
||||
SynthDef(\subBoom, {
|
||||
arg freq = 50, gate = 1, glide = 0.04,
|
||||
attack = 0.005, decay = 0.4, sustain = 0.85, release = 0.6,
|
||||
drive = 1.4, amp = 0.4, pan = 0,
|
||||
scBus = 0, scAmt = 0.5;
|
||||
var sig, env, duck, f;
|
||||
f = Lag.kr(freq, glide);
|
||||
// Sub fondamental + octave -1 + harmonique 2 leger
|
||||
sig = (SinOsc.ar(f) * 0.8) +
|
||||
(SinOsc.ar(f * 0.5) * 0.5) +
|
||||
(SinOsc.ar(f * 2) * 0.15);
|
||||
sig = (sig * drive).tanh;
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Handpan (steel drum, decay long + harmoniques pures) --------
|
||||
SynthDef(\handpan, {
|
||||
arg freq = 220, gate = 1,
|
||||
cutoff = 5000, rq = 0.6,
|
||||
attack = 0.001, decay = 0.05, sustain = 0.0, release = 1.5,
|
||||
drive = 1.1, amp = 0.22, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, partials;
|
||||
// 4 partiels harmoniques (octaves + quintes)
|
||||
partials = [1, 2, 3, 4];
|
||||
sig = Mix.fill(partials.size, { |i|
|
||||
SinOsc.ar(freq * partials[i]) *
|
||||
(1 / ((i * 1.5) + 1)) *
|
||||
EnvGen.kr(Env.perc(0.001, release * (1 - (i * 0.15)), 1, -4));
|
||||
});
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
sig = LeakDC.ar(sig);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Flute (bambou avec souffle + vibrato) -----------------------
|
||||
SynthDef(\flute, {
|
||||
arg freq = 440, gate = 1,
|
||||
breathAmt = 0.15, vibratoRate = 5, vibratoDepth = 0.012,
|
||||
cutoff = 3500, rq = 0.6,
|
||||
attack = 0.08, decay = 0.1, sustain = 0.7, release = 0.3,
|
||||
drive = 1.0, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.4;
|
||||
var sig, env, duck, vibFreq, breath, body;
|
||||
vibFreq = freq * (1 + (SinOsc.kr(vibratoRate,
|
||||
EnvGen.kr(Env([0, 0, 1], [0.15, 0.4])) * pi) * vibratoDepth));
|
||||
body = SinOsc.ar(vibFreq) +
|
||||
(SinOsc.ar(vibFreq * 2) * 0.15) +
|
||||
(SinOsc.ar(vibFreq * 3) * 0.05);
|
||||
breath = HPF.ar(WhiteNoise.ar, 2000) * breathAmt *
|
||||
EnvGen.kr(Env([0, 1, 0.6], [0.05, 0.5]));
|
||||
sig = body + breath;
|
||||
sig = LPF.ar(sig, cutoff);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
// ----- Drone (note longue avec modulation lente, pour ambiances) ---
|
||||
SynthDef(\drone, {
|
||||
arg freq = 110, gate = 1, detune = 0.01,
|
||||
cutoff = 1800, rq = 0.4, modRate = 0.15, modDepth = 600,
|
||||
attack = 1.5, decay = 0.5, sustain = 0.85, release = 3.0,
|
||||
drive = 1.1, amp = 0.18, pan = 0,
|
||||
scBus = 0, scAmt = 0.3;
|
||||
var sig, env, duck, fc, voices;
|
||||
fc = (cutoff + (LFNoise2.kr(modRate) * modDepth)).clip(60, 8000);
|
||||
voices = (Saw.ar(freq * (1 - detune)) * 0.4) +
|
||||
(Saw.ar(freq * (1 + detune)) * 0.4) +
|
||||
(SinOsc.ar(freq * 0.5) * 0.3); // sub
|
||||
sig = RLPF.ar(voices, fc, rq);
|
||||
sig = sig + (DelayC.ar(sig, 0.05,
|
||||
SinOsc.kr(0.2, 0).range(0.01, 0.04)) * 0.3);
|
||||
env = EnvGen.kr(Env.adsr(attack, decay, sustain, release), gate, doneAction: 2);
|
||||
sig = (sig * drive).tanh / drive.sqrt;
|
||||
duck = 1 - (In.kr(scBus, 1) * scAmt);
|
||||
Out.ar(0, Pan2.ar(sig * env * amp * duck, pan));
|
||||
}).add;
|
||||
|
||||
"=== synthdefs_extra.scd : 12 nouveaux SynthDef charges ===".postln;
|
||||
" leads : \\squareLead \\fmLead \\organLead \\hardLead".postln;
|
||||
" pads : \\warmPad \\strings \\choir".postln;
|
||||
" bass : \\fmBass \\subBoom".postln;
|
||||
" world : \\handpan \\flute".postln;
|
||||
" ambient : \\drone".postln;
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
# tests/ — Suite E2E SuperCollider
|
||||
|
||||
Tests bout-en-bout via `sclang`. Chaque test affiche un resume
|
||||
parsable que `run_all.sh` collecte (l'exit code de sclang n'est
|
||||
pas fiable -- libc++abi peut crasher au quit du serveur interne).
|
||||
|
||||
## Lancement
|
||||
|
||||
```bash
|
||||
cd tests && bash run_all.sh
|
||||
```
|
||||
|
||||
Un test seul :
|
||||
```bash
|
||||
/Applications/SuperCollider.app/Contents/MacOS/sclang tests/e2e_05_melodies.scd
|
||||
```
|
||||
|
||||
## Convention de test
|
||||
|
||||
```supercollider
|
||||
"=== e2e_NN_xxx ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0; ~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) { (" [OK] " ++ label).postln }
|
||||
{ ~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ " : " ++ (info ? "")).postln };
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
```
|
||||
|
||||
Ligne resume **obligatoire** : `== N tests, M failed ==`
|
||||
(parsee par `run_all.sh` via `grep -E`).
|
||||
|
||||
## Ce qui est teste
|
||||
|
||||
| Fichier | Cible |
|
||||
| --- | --- |
|
||||
| `e2e_01_syntax.scd` | parse `String.compile` de chaque bloc top-level |
|
||||
| `e2e_02_load.scd` | `00_load.scd` charge sans erreur |
|
||||
| `e2e_03_reload_guards.scd` | `~reload.value` n'explose pas |
|
||||
| `e2e_04_synthdef_compile.scd` | tous les SynthDef se compilent |
|
||||
| `e2e_05_melodies.scd` | banques melodies coherentes |
|
||||
| `e2e_06_mixer.scd` | mixer 8 voies |
|
||||
| `e2e_07_jump.scd` | `~jumpTo` valide |
|
||||
| `e2e_08_live.scd` | API live (mm, fx, scenes, ...) |
|
||||
| `e2e_09_tracks.scd` | tracks A-W parsent |
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Ne pas se fier a l'exit code sclang (peut etre != 0 alors que tests passent)
|
||||
- Ne pas oublier `~report.value` a la fin -> SKIP dans run_all.sh
|
||||
- Ne pas booter le serveur audio dans un test syntax (lent, instable en CI)
|
||||
- Ne pas hardcoder le path sclang (utiliser `$SCLANG` env var)
|
||||
- Ne pas laisser de Routine running en fin de test (fuite)
|
||||
@@ -0,0 +1,164 @@
|
||||
// =====================================================================
|
||||
// e2e_01_syntax.scd
|
||||
// Verifie que chaque .scd parse correctement.
|
||||
// Strategie : pour chaque fichier, on extrait les blocs top-level
|
||||
// (lignes commencant par '(' a la colonne 0) et on tente de compiler
|
||||
// chaque bloc independamment via String.compile.
|
||||
// Convention du projet : les blocs ouvrent par '(' col 0 et ferment
|
||||
// par ')' col 0 (multi-ligne) OU '( ... )' sur une seule ligne.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_01_syntax ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
// Extrait les blocs top-level d'un .scd selon la convention du projet :
|
||||
// - ligne qui commence par '(' = ouverture
|
||||
// - ligne qui se termine par ')' au col 0 (ou ligne single-line se
|
||||
// terminant par ')' qui equilibre les parens) = fermeture
|
||||
~extractBlocks = { |src|
|
||||
var blocks = List.new;
|
||||
var lines = src.split($\n);
|
||||
var i = 0, j, startIdx, line, depth, balance;
|
||||
while { i < lines.size } {
|
||||
line = lines[i];
|
||||
// ligne commence par '(' (premier char) ?
|
||||
if ((line.size > 0) and: { line[0] == $( }) {
|
||||
startIdx = i;
|
||||
// calcule la balance de parens pour cette ligne
|
||||
// (compte brut sans tenir compte des chaines/commentaires ;
|
||||
// c'est OK pour la convention du projet)
|
||||
balance = 0;
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) {
|
||||
// bloc 1-ligne : '( ... )'
|
||||
blocks.add(line);
|
||||
} {
|
||||
// bloc multi-ligne : cherche la ligne suivante qui ramene
|
||||
// la balance a 0
|
||||
j = i + 1;
|
||||
while { (j < lines.size) and: { balance != 0 } } {
|
||||
var l2 = lines[j];
|
||||
l2.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
j = j + 1;
|
||||
};
|
||||
if (balance == 0) {
|
||||
blocks.add(lines.copyRange(startIdx, j - 1).join($\n));
|
||||
i = j - 1;
|
||||
} {
|
||||
(" [WARN] bloc unterminated ligne " ++ (startIdx + 1)).postln;
|
||||
i = lines.size;
|
||||
};
|
||||
};
|
||||
};
|
||||
i = i + 1;
|
||||
};
|
||||
blocks;
|
||||
};
|
||||
|
||||
// Si un bloc utilise une classe IDE-only (Document, etc.) il echouera
|
||||
// en mode CLI sclang. On ignore ces blocs (warning seulement).
|
||||
~ideOnlyKeywords = ["Document.open", "Document.current", "Document.dir"];
|
||||
|
||||
~isIdeOnlyBlock = { |src|
|
||||
~ideOnlyKeywords.any { |kw| src.contains(kw) };
|
||||
};
|
||||
|
||||
~compileFileSyntax = { |path|
|
||||
var src = File.readAllString(path);
|
||||
var blocks, nFail = 0, nIdeSkip = 0, idx = 0;
|
||||
if (src.isNil) { false } {
|
||||
// Tente d'abord compileFile (rapide pour single-block)
|
||||
var single;
|
||||
try { single = thisProcess.interpreter.compileFile(path) } { single = nil };
|
||||
if (single.notNil) {
|
||||
true
|
||||
} {
|
||||
blocks = ~extractBlocks.(src);
|
||||
if (blocks.size == 0) {
|
||||
false
|
||||
} {
|
||||
blocks.do { |b|
|
||||
idx = idx + 1;
|
||||
if (~isIdeOnlyBlock.(b)) {
|
||||
nIdeSkip = nIdeSkip + 1;
|
||||
} {
|
||||
if (b.compile.isNil) {
|
||||
nFail = nFail + 1;
|
||||
(" !! " ++ path.basename ++ " bloc#" ++ idx
|
||||
++ " parse FAIL").postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (nIdeSkip > 0) {
|
||||
(" [INFO] " ++ path.basename ++ " : " ++ nIdeSkip
|
||||
++ " blocs IDE-only ignores (Document.open)").postln;
|
||||
};
|
||||
nFail == 0
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
~files = [
|
||||
"00_load.scd", "engine.scd",
|
||||
"live/fx_bus.scd", "live/live.scd", "live/mixer.scd",
|
||||
"live/loops.scd", "live/scenes.scd", "live/tweaks.scd",
|
||||
"live/live_fx_panel.scd",
|
||||
"control/midi.scd", "control/playlist.scd", "control/jump.scd",
|
||||
"synthdefs/asia.scd", "synthdefs/extra.scd", "synthdefs/authentic.scd",
|
||||
"palette/scales.scd",
|
||||
"palette/styles.scd", "palette/timbres.scd",
|
||||
"palette/melodies/helpers.scd", "palette/melodies/short.scd",
|
||||
"palette/melodies/long.scd", "palette/melodies/xlong.scd",
|
||||
"palette/melodies/epic.scd", "palette/melodies/bank.scd",
|
||||
"palette/melodies/tracks.scd",
|
||||
"palette/harmonics/helpers.scd", "palette/harmonics/presets.scd",
|
||||
"palette/rhythm/kicks.scd", "palette/rhythm/percussions.scd",
|
||||
"palette/rhythm/drum_kits.scd", "palette/rhythm/patterns_genre.scd",
|
||||
"palette/rhythm/sequences.scd", "palette/rhythm/fills.scd",
|
||||
"palette/chords_progressions.scd",
|
||||
"palette/fx.scd", "palette/fx_genre.scd",
|
||||
"palette/tweaks_template.scd",
|
||||
];
|
||||
|
||||
~files.do { |rel|
|
||||
var path = ~base ++ rel;
|
||||
if (File.exists(path).not) {
|
||||
~assert.(rel, false, "fichier introuvable");
|
||||
} {
|
||||
~assert.("syntax: " ++ rel, ~compileFileSyntax.(path), "parse FAIL");
|
||||
};
|
||||
};
|
||||
|
||||
PathName(~base ++ "tracks/").files.do { |pn|
|
||||
if (pn.fullPath.endsWith(".scd")) {
|
||||
~assert.("syntax: tracks/" ++ pn.fileName, ~compileFileSyntax.(pn.fullPath),
|
||||
"parse FAIL");
|
||||
};
|
||||
};
|
||||
|
||||
~report.value;
|
||||
@@ -0,0 +1,108 @@
|
||||
// =====================================================================
|
||||
// e2e_02_load.scd
|
||||
// Boot Server.internal, charge engine + synthdefs + fills (sequence
|
||||
// "CHARGER TOUT" du loader) et verifie helpers + SynthDefs attendus.
|
||||
// Note : engine.scd wrap son SETUP dans s.waitForBoot {} qui differe
|
||||
// l'execution sur AppClock. On utilise une Routine + .wait pour
|
||||
// laisser le callback s'executer.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_02_load ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
// Pas de s.quit -- declenche un abort C++ a la fin sur certains setups.
|
||||
// sclang fera le cleanup propre via 0.exit.
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
// Charge le PREMIER bloc top-level (...) d'un fichier multi-blocs
|
||||
// (utile pour palette/rhythm/fills.scd qui contient en fin des blocs '( ~snareFill.value; )' de demo).
|
||||
~loadFirstBlock = { |path|
|
||||
var src = File.readAllString(path);
|
||||
var lines, block, capturing, done, balance;
|
||||
lines = src.split($\n);
|
||||
block = List.new;
|
||||
capturing = false; done = false; balance = 0;
|
||||
lines.do { |line|
|
||||
if (done.not) {
|
||||
if (capturing.not and: { (line.size > 0) and: { line[0] == $( } }) {
|
||||
capturing = true;
|
||||
balance = 0;
|
||||
};
|
||||
if (capturing) {
|
||||
block.add(line);
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) { done = true };
|
||||
};
|
||||
};
|
||||
};
|
||||
block.join($\n).interpret;
|
||||
};
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
" [INFO] Server.internal booted".postln;
|
||||
s.sync;
|
||||
|
||||
// engine.scd : single-block top-level qui wrappe s.waitForBoot {...}
|
||||
try { (~base ++ "engine.scd").load } { |e|
|
||||
(" [INFO] engine load: " ++ e.errorString).postln };
|
||||
// Laisse l'AppClock executer le callback de waitForBoot
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
try { (~base ++ "synthdefs/asia.scd").load } { |e| (" [INFO] asia: " ++ e.errorString).postln };
|
||||
try { (~base ++ "synthdefs/extra.scd").load } { |e| (" [INFO] extra: " ++ e.errorString).postln };
|
||||
try { (~base ++ "synthdefs/authentic.scd").load } { |e| (" [INFO] authn: " ++ e.errorString).postln };
|
||||
|
||||
try { ~loadFirstBlock.(~base ++ "palette/rhythm/fills.scd") } { |e|
|
||||
(" [INFO] fills: " ++ e.errorString).postln };
|
||||
// Charge scales + harmonics (sources de ~genMelody et ~enableHarmony
|
||||
// depuis la reorganisation -- engine.scd ne les definit plus).
|
||||
try { (~base ++ "palette/scales.scd").load } { |e|
|
||||
(" [INFO] scales: " ++ e.errorString).postln };
|
||||
try { (~base ++ "palette/harmonics/index.scd").load } { |e|
|
||||
(" [INFO] harmonics: " ++ e.errorString).postln };
|
||||
s.sync;
|
||||
|
||||
~assert.("helper ~reload defini", ~reload.notNil);
|
||||
~assert.("helper ~enableHarmony defini", ~enableHarmony.notNil);
|
||||
~assert.("helper ~snareFill defini", ~snareFill.notNil);
|
||||
~assert.("helper ~tomFill defini", ~tomFill.notNil);
|
||||
|
||||
// Note: \fbVoice etait dans la liste attendue mais n'est defini
|
||||
// que dans _old/. On le verifie comme reference d'absence.
|
||||
[
|
||||
\kick, \hat, \snare, \clap, \acid, \koto, \erhu,
|
||||
\warmPad, \subBoom, \drone, \kickGabber, \supersaw, \scratch
|
||||
].do { |sym|
|
||||
var defined = SynthDescLib.global.synthDescs[sym].notNil;
|
||||
~assert.("synthdef " ++ sym, defined, "absent de SynthDescLib.global");
|
||||
};
|
||||
// \fbVoice : reporte mais NON-FAIL (reference uniquement dans _old/)
|
||||
if (SynthDescLib.global.synthDescs[\fbVoice].isNil) {
|
||||
" [INFO] \\fbVoice non defini (existe seulement dans _old/)".postln;
|
||||
};
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { " [FAIL] Server.internal boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,72 @@
|
||||
// =====================================================================
|
||||
// e2e_03_reload_guards.scd
|
||||
// Verifie les guards ajoutes a ~reload (engine.scd:498-516) :
|
||||
// Quand ~kickSteps / ~melodyNotes / etc. sont nil ou vides, ~reload
|
||||
// doit auto-defaulter sans planter (Pseq sur nil/empty plante sinon).
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_03_reload_guards ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
~runReload = {
|
||||
var crashed = false, msg = nil;
|
||||
try { ~reload.value } { |e| crashed = true; msg = e.errorString };
|
||||
[crashed, msg];
|
||||
};
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
var r;
|
||||
s.sync;
|
||||
try { (~base ++ "engine.scd").load } { |e| ("engine err: " ++ e.errorString).postln };
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
~assert.("~reload defini", ~reload.notNil);
|
||||
|
||||
// --- Test 1 : nil ---
|
||||
~kickSteps = nil; ~hatSteps = nil;
|
||||
~snareSteps = nil; ~clapSteps = nil;
|
||||
~percSteps = nil; ~acidNotes = nil;
|
||||
~acidAccents = nil; ~acidSlides = nil;
|
||||
~melodyNotes = nil; ~harmonyNotes = nil;
|
||||
|
||||
r = ~runReload.value;
|
||||
~assert.("~reload survive a nil", r[0].not, r[1]);
|
||||
~assert.("~kickSteps default apres reload", ~kickSteps.notNil and: { ~kickSteps.size > 0 });
|
||||
~assert.("~melodyNotes default apres reload", ~melodyNotes.notNil and: { ~melodyNotes.size > 0 });
|
||||
~assert.("~harmonyNotes default apres reload", ~harmonyNotes.notNil and: { ~harmonyNotes.size > 0 });
|
||||
~assert.("~acidNotes default apres reload", ~acidNotes.notNil and: { ~acidNotes.size > 0 });
|
||||
|
||||
// --- Test 2 : empty array ---
|
||||
~kickSteps = [];
|
||||
~melodyNotes = [];
|
||||
~acidNotes = [];
|
||||
r = ~runReload.value;
|
||||
~assert.("~reload survive a [] ", r[0].not, r[1]);
|
||||
~assert.("~kickSteps refilled apres []", ~kickSteps.size > 0);
|
||||
~assert.("~melodyNotes refilled apres []", ~melodyNotes.size > 0);
|
||||
~assert.("~acidNotes refilled apres []", ~acidNotes.size > 0);
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { "boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,112 @@
|
||||
// =====================================================================
|
||||
// e2e_04_synthdef_compile.scd
|
||||
// Charge engine + fx_bus + live + authentic et verifie que les
|
||||
// SynthDef critiques compilent sans erreur (.asBytes force la
|
||||
// compilation sans envoyer au serveur). Si une UGen manque, .asBytes
|
||||
// plante.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_04_synthdef_compile ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
// Charge tous les blocs top-level d'un fichier .scd multi-blocs.
|
||||
// Echoue silencieusement bloc par bloc pour ne pas couper le test.
|
||||
~loadAllBlocks = { |path|
|
||||
var src = File.readAllString(path);
|
||||
var lines = src.split($\n);
|
||||
var blocks = List.new;
|
||||
var capturing = false, balance = 0, current = nil;
|
||||
lines.do { |line|
|
||||
if (capturing.not and: { (line.size > 0) and: { line[0] == $( } }) {
|
||||
capturing = true; balance = 0; current = List.new;
|
||||
};
|
||||
if (capturing) {
|
||||
current.add(line);
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) {
|
||||
blocks.add(current.join($\n));
|
||||
capturing = false; current = nil;
|
||||
};
|
||||
};
|
||||
};
|
||||
blocks.do { |b|
|
||||
try { b.interpret } { |e|
|
||||
// Beaucoup de blocs sont des exemples qui necessitent
|
||||
// les Synth runtime ; on ignore les erreurs runtime
|
||||
// mais on log les erreurs de compilation/UGen manquante.
|
||||
if (e.errorString.contains("UGen") or:
|
||||
{ e.errorString.contains("doesNotUnderstand") and:
|
||||
{ e.errorString.contains("SynthDef") } }) {
|
||||
(" !! load " ++ path.basename ++ " : " ++ e.errorString).postln;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
s.sync;
|
||||
try { (~base ++ "engine.scd").load } { |e| ("engine err: " ++ e.errorString).postln };
|
||||
2.wait;
|
||||
s.sync;
|
||||
try { (~base ++ "synthdefs/asia.scd").load } { |e| ("asia err: " ++ e.errorString).postln };
|
||||
try { (~base ++ "synthdefs/extra.scd").load } { |e| ("extra err: " ++ e.errorString).postln };
|
||||
try { (~base ++ "synthdefs/authentic.scd").load } { |e| ("authn err: " ++ e.errorString).postln };
|
||||
// Multi-blocs : charge bloc par bloc
|
||||
~loadAllBlocks.(~base ++ "live/fx_bus.scd");
|
||||
~loadAllBlocks.(~base ++ "live/live.scd");
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
// Liste des SynthDef critiques
|
||||
// (on verifie qu'ils sont enregistres dans SynthDescLib.global ;
|
||||
// l'enregistrement implique une compilation .asBytes reussie cote sclang)
|
||||
[
|
||||
// fx_bus.scd : version sans Decimator
|
||||
\fxBitcrush, \fxDelay, \fxReverb, \fxChorus, \fxPhaser, \fxFlanger,
|
||||
\fxTape, \fxShimmer, \fxDist, \fxSend,
|
||||
// authentic.scd : scratch fixe avec Select.kr
|
||||
\scratch,
|
||||
// live.scd : VCF master
|
||||
\vcfMoog, \vcfMs20, \vcfLadder, \vcfFormant, \vcfComb,
|
||||
\vcfHpf, \vcfBpf, \vcfNotch,
|
||||
// live.scd : FX additionnels
|
||||
\fxRingMod, \fxFreqShift, \fxGran, \fxComb, \fxFormant,
|
||||
\fxAutoFilter, \fxTremolo, \fxAutopan, \fxStutter,
|
||||
\fxResonator, \fxSpringRev, \fxPlate,
|
||||
// live.scd : master comp/sat
|
||||
\masterComp, \masterSat,
|
||||
// live.scd : FX master one-shots
|
||||
\fxMasterPitch, \fxMasterRing, \fxMasterFreqShift, \fxMasterGran,
|
||||
\fxMasterBitcrush
|
||||
].do { |sym|
|
||||
var defined = SynthDescLib.global.synthDescs[sym].notNil;
|
||||
~assert.("synthdef " ++ sym ++ " compile", defined,
|
||||
"absent (UGen manquante ? compilation echouee ?)");
|
||||
};
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { "boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,179 @@
|
||||
// =====================================================================
|
||||
// e2e_05_melodies.scd
|
||||
// Verifie les melodies/helpers de palette/melodies/index.scd :
|
||||
// ~m1..~m78 (32 steps), ~ml1..~ml30 (64), ~mxl1..~mxl15 (96),
|
||||
// ~mepic1..~mepic10 (128), ~useMelody, ~melodyByGenre,
|
||||
// ~stretchPattern, ~mirror.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_05_melodies ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
// Le module melodies est multi-blocs reparti dans plusieurs fichiers.
|
||||
// On split chaque fichier en blocs et on interprete bloc par bloc,
|
||||
// en sautant les blocs IDE-only ou les blocs qui font reference a des
|
||||
// helpers non definis (rares).
|
||||
~loadAllBlocks = { |path|
|
||||
var src = File.readAllString(path);
|
||||
var lines, blocks, capturing, balance, current;
|
||||
lines = src.split($\n);
|
||||
blocks = List.new;
|
||||
capturing = false; balance = 0; current = nil;
|
||||
lines.do { |line|
|
||||
if (capturing.not and: { (line.size > 0) and: { line[0] == $( } }) {
|
||||
capturing = true;
|
||||
balance = 0;
|
||||
current = List.new;
|
||||
};
|
||||
if (capturing) {
|
||||
current.add(line);
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) {
|
||||
blocks.add(current.join($\n));
|
||||
capturing = false;
|
||||
current = nil;
|
||||
};
|
||||
};
|
||||
};
|
||||
blocks;
|
||||
};
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
var blocks, idx = 0, nFail = 0;
|
||||
var initial, lookupHits = 0;
|
||||
s.sync;
|
||||
try { (~base ++ "engine.scd").load } { |e| ("engine err: " ++ e.errorString).postln };
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
// Charge palette/scales.scd (scales + helpers melodiques)
|
||||
try { (~base ++ "palette/scales.scd").load } { |e|
|
||||
("scales err: " ++ e.errorString).postln };
|
||||
s.sync;
|
||||
|
||||
// Charge chaque sous-fichier melodies bloc par bloc
|
||||
[
|
||||
"palette/melodies/helpers.scd",
|
||||
"palette/melodies/short.scd",
|
||||
"palette/melodies/long.scd",
|
||||
"palette/melodies/xlong.scd",
|
||||
"palette/melodies/epic.scd",
|
||||
"palette/melodies/bank.scd",
|
||||
"palette/melodies/tracks.scd"
|
||||
].do { |relPath|
|
||||
var bs = ~loadAllBlocks.(~base ++ relPath);
|
||||
bs.do { |b|
|
||||
idx = idx + 1;
|
||||
try { b.interpret } { |e| nFail = nFail + 1;
|
||||
(" !! " ++ relPath ++ " bloc#" ++ idx ++ " : " ++ e.errorString).postln };
|
||||
};
|
||||
blocks = blocks ?? { List.new };
|
||||
bs.do { |b| blocks.add(b) };
|
||||
};
|
||||
~assert.("melodies module : " ++ blocks.size ++ " blocs interpretes",
|
||||
nFail == 0, nFail.asString ++ " blocs en echec");
|
||||
s.sync;
|
||||
|
||||
// --- m1..m78 (32 steps) ---
|
||||
// Note : 4 indices sont des "blocs demo" qui ne creent pas de var ~m6
|
||||
// m6 = random walk (genere a la volee)
|
||||
// m22 = modulating runs (evolutif)
|
||||
// m25 = counter melody (set ~harmonyNotes pas ~melodyNotes)
|
||||
// m26 = cascade 32nd (pareil)
|
||||
// -> on les exclut. Verifier (1..78).reject({ ... }).
|
||||
(1..78).reject { |i| #[6, 22, 25, 26].includes(i) }.do { |i|
|
||||
var sym = ("m" ++ i).asSymbol;
|
||||
var notes = currentEnvironment[sym];
|
||||
if (notes.isNil or: { notes.isArray.not } or: { notes.size == 0 }) {
|
||||
~assert.("~" ++ sym ++ " defini (32 steps attendus)", false,
|
||||
"missing/empty (size=" ++ notes.tryPerform(\size) ++ ")");
|
||||
} {
|
||||
~assert.("~" ++ sym ++ " defini (size=" ++ notes.size ++ ")", true);
|
||||
};
|
||||
};
|
||||
|
||||
// --- ml1..ml30 (64) ---
|
||||
(1..30).do { |i|
|
||||
var sym = ("ml" ++ i).asSymbol;
|
||||
var notes = currentEnvironment[sym];
|
||||
~assert.("~" ++ sym ++ " = 64 steps",
|
||||
notes.notNil and: { notes.size == 64 },
|
||||
"size=" ++ notes.tryPerform(\size));
|
||||
};
|
||||
|
||||
// --- mxl1..mxl15 (96) ---
|
||||
(1..15).do { |i|
|
||||
var sym = ("mxl" ++ i).asSymbol;
|
||||
var notes = currentEnvironment[sym];
|
||||
~assert.("~" ++ sym ++ " = 96 steps",
|
||||
notes.notNil and: { notes.size == 96 },
|
||||
"size=" ++ notes.tryPerform(\size));
|
||||
};
|
||||
|
||||
// --- mepic1..mepic10 (128) ---
|
||||
(1..10).do { |i|
|
||||
var sym = ("mepic" ++ i).asSymbol;
|
||||
var notes = currentEnvironment[sym];
|
||||
~assert.("~" ++ sym ++ " = 128 steps",
|
||||
notes.notNil and: { notes.size == 128 },
|
||||
"size=" ++ notes.tryPerform(\size));
|
||||
};
|
||||
|
||||
// --- ~useMelody.(\m50) ---
|
||||
~useMelody.(\m50);
|
||||
~assert.("~useMelody.(\\m50) -> ~melodyNotes == ~m50",
|
||||
~melodyNotes == ~m50);
|
||||
|
||||
// --- ~melodyByGenre.(\acid) ---
|
||||
~melodyByGenre.(\acid);
|
||||
~assert.("~melodyByGenre.(\\acid) set ~melodyNotes",
|
||||
~melodyNotes.notNil and: { ~melodyNotes.size > 0 });
|
||||
|
||||
// --- Lookup indirect : redefinir ~m29 et verifier que ~melodyByGenre
|
||||
// finit par utiliser la nouvelle valeur (preuve que le bank ne
|
||||
// stocke pas une copie figee de l'ancienne).
|
||||
~m29 = [99, 99, 99];
|
||||
// Le bank \acid contient \m29 entre autres. On boucle jusqu'a 30
|
||||
// tentatives pour avoir une chance d'aterrir sur \m29.
|
||||
lookupHits = 0;
|
||||
50.do {
|
||||
~melodyByGenre.(\acid);
|
||||
if (~melodyNotes == [99, 99, 99]) { lookupHits = lookupHits + 1 };
|
||||
};
|
||||
~assert.("~melodyByGenre lookup indirect (m29 modifie pris en compte)",
|
||||
lookupHits > 0,
|
||||
"0 hits sur 50 essais -- bank a peut-etre fige les valeurs");
|
||||
|
||||
// --- ~stretchPattern.([1,2,3,4], 2) -> 8 elements ---
|
||||
~assert.("~stretchPattern factor=2", ~stretchPattern.([1,2,3,4], 2).size == 8);
|
||||
|
||||
// --- ~mirror.([1,2,3]) -> [1,2,3,3,2,1] ---
|
||||
~assert.("~mirror retourne palindrome",
|
||||
~mirror.([1,2,3]) == [1,2,3,3,2,1]);
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { "boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,128 @@
|
||||
// =====================================================================
|
||||
// e2e_06_mixer.scd
|
||||
// Verifie l'API mixer.scd : ~setVol, ~masterVol, ~mute, ~unmute,
|
||||
// ~solo, ~unsolo, ~mixReset.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_06_mixer ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
~loadAllBlocks = { |path|
|
||||
var src = File.readAllString(path);
|
||||
var lines = src.split($\n);
|
||||
var blocks = List.new;
|
||||
var capturing = false, balance = 0, current = nil;
|
||||
lines.do { |line|
|
||||
if (capturing.not and: { (line.size > 0) and: { line[0] == $( } }) {
|
||||
capturing = true; balance = 0; current = List.new;
|
||||
};
|
||||
if (capturing) {
|
||||
current.add(line);
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) {
|
||||
blocks.add(current.join($\n));
|
||||
capturing = false; current = nil;
|
||||
};
|
||||
};
|
||||
};
|
||||
blocks;
|
||||
};
|
||||
|
||||
~floatEq = { |a, b, eps = 1e-6| (a - b).abs < eps };
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
var kickInit, hatInit, refKick, refHat;
|
||||
var blocks, idx = 0;
|
||||
s.sync;
|
||||
try { (~base ++ "engine.scd").load } { |e| ("engine err: " ++ e.errorString).postln };
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
// Charge le SETUP de mixer.scd : 1er gros bloc seulement (les blocs
|
||||
// suivants sont des exemples a la demande).
|
||||
blocks = ~loadAllBlocks.(~base ++ "live/mixer.scd");
|
||||
// Le 1er bloc top-level est le SETUP complet
|
||||
if (blocks.size > 0) {
|
||||
try { blocks[0].interpret } { |e|
|
||||
("mixer setup err: " ++ e.errorString).postln };
|
||||
};
|
||||
s.sync;
|
||||
|
||||
~assert.("~setVol defini", ~setVol.notNil);
|
||||
~assert.("~masterVol defini", ~masterVol.notNil);
|
||||
~assert.("~mute defini", ~mute.notNil);
|
||||
~assert.("~solo defini", ~solo.notNil);
|
||||
~assert.("~mixReset defini", ~mixReset.notNil);
|
||||
|
||||
kickInit = ~kickAmp;
|
||||
refKick = ~mixRef[\kick];
|
||||
|
||||
// ~setVol.(\kick, 0.5) : amp = ref * 0.5 * mixMaster(=1) = ref * 0.5
|
||||
~setVol.(\kick, 0.5);
|
||||
~assert.("~setVol kick 0.5 -> kickAmp = ref * 0.5",
|
||||
~floatEq.(~kickAmp, refKick * 0.5),
|
||||
"got " ++ ~kickAmp ++ " expected " ++ (refKick * 0.5));
|
||||
|
||||
// ~masterVol.(0.5) : amp = ref * 0.5 (coef voie) * 0.5 (master)
|
||||
~masterVol.(0.5);
|
||||
~assert.("~mixMaster == 0.5", ~floatEq.(~mixMaster, 0.5));
|
||||
~assert.("~kickAmp = ref * 0.5 * 0.5",
|
||||
~floatEq.(~kickAmp, refKick * 0.5 * 0.5),
|
||||
"got " ++ ~kickAmp);
|
||||
|
||||
// ~masterVol.(1.0) : kickAmp doit revenir a ref * 0.5
|
||||
~masterVol.(1.0);
|
||||
~assert.("~masterVol(1) restore : kickAmp = ref * 0.5 (non-destructif)",
|
||||
~floatEq.(~kickAmp, refKick * 0.5),
|
||||
"got " ++ ~kickAmp);
|
||||
|
||||
// ~mixReset : tous les coefs a 1
|
||||
~mixReset.value;
|
||||
~assert.("~mixReset : ~mix[\\kick] == 1", ~floatEq.(~mix[\kick], 1.0));
|
||||
~assert.("~mixReset : ~mix[\\hat] == 1", ~floatEq.(~mix[\hat], 1.0));
|
||||
~assert.("~mixReset : ~kickAmp == ref", ~floatEq.(~kickAmp, refKick));
|
||||
|
||||
// ~mute / ~unmute
|
||||
~mute.(\kick);
|
||||
~assert.("~mute kick -> kickAmp == 0", ~kickAmp == 0,
|
||||
"got " ++ ~kickAmp);
|
||||
~unmute.(\kick);
|
||||
~assert.("~unmute kick -> kickAmp restored",
|
||||
~floatEq.(~kickAmp, refKick),
|
||||
"got " ++ ~kickAmp);
|
||||
|
||||
// ~solo / ~unsolo
|
||||
~solo.(\melody);
|
||||
~assert.("~solo melody -> kickAmp == 0", ~kickAmp == 0);
|
||||
~assert.("~solo melody -> melodyAmp != 0", ~melodyAmp != 0);
|
||||
~unsolo.value;
|
||||
~assert.("~unsolo -> kickAmp restored",
|
||||
~floatEq.(~kickAmp, refKick),
|
||||
"got " ++ ~kickAmp);
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { "boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,107 @@
|
||||
// =====================================================================
|
||||
// e2e_07_jump.scd
|
||||
// Verifie le SETUP de jump.scd et l'execution d'une section.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_07_jump ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
// Charge tous les blocs top-level d'un fichier .scd multi-blocs
|
||||
// jusqu'a un bloc cible (predicat sur le contenu).
|
||||
~loadAllBlocks = { |path, untilPred|
|
||||
var src = File.readAllString(path);
|
||||
var lines = src.split($\n);
|
||||
var blocks = List.new;
|
||||
var capturing = false, balance = 0, current = nil, stop = false;
|
||||
lines.do { |line|
|
||||
if (stop.not) {
|
||||
if (capturing.not and: { (line.size > 0) and: { line[0] == $( } }) {
|
||||
capturing = true; balance = 0; current = List.new;
|
||||
};
|
||||
if (capturing) {
|
||||
current.add(line);
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) {
|
||||
var blk = current.join($\n);
|
||||
blocks.add(blk);
|
||||
capturing = false; current = nil;
|
||||
if (untilPred.notNil and: { untilPred.value(blk) }) {
|
||||
stop = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
blocks;
|
||||
};
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
var blocks, setupOk = true, sectionAOk = true;
|
||||
var jumpedOk = true, jumpedNonExistent = true;
|
||||
s.sync;
|
||||
try { (~base ++ "engine.scd").load } { |e| ("engine err: " ++ e.errorString).postln };
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
// Charge les blocs jump.scd jusqu'a et y compris le bloc TRACK A
|
||||
// (~sections['A'] = ...).
|
||||
blocks = ~loadAllBlocks.(~base ++ "control/jump.scd", { |b|
|
||||
b.contains("~sections['A']") or: { b.contains("~sections[\\A]") }
|
||||
});
|
||||
|
||||
// Execute le 1er bloc (SETUP) et le bloc TRACK A
|
||||
try { blocks[0].interpret } { |e|
|
||||
setupOk = false; ("setup err: " ++ e.errorString).postln };
|
||||
~assert.("jump SETUP execute", setupOk);
|
||||
~assert.("~jumpTo defini", ~jumpTo.notNil);
|
||||
~assert.("~sections defini", ~sections.notNil);
|
||||
|
||||
// Cherche le bloc qui contient ~sections['A'] ou ~sections[\A]
|
||||
blocks.do { |b|
|
||||
if (b.contains("~sections['A']") or: { b.contains("~sections[\\A]") }) {
|
||||
try { b.interpret } { |e|
|
||||
sectionAOk = false; ("track A err: " ++ e.errorString).postln };
|
||||
};
|
||||
};
|
||||
~assert.("track A bloc execute", sectionAOk);
|
||||
~assert.("~sections['A'] presente", ~sections['A'.asSymbol].notNil
|
||||
or: { ~sections[\A].notNil });
|
||||
|
||||
// ~jumpTo.('A', 'minimal_kick_t5_sub_melody_pad')
|
||||
try { ~jumpTo.('A', 'minimal_kick_t5_sub_melody_pad') }
|
||||
{ |e| jumpedOk = false; ("jumpTo err: " ++ e.errorString).postln };
|
||||
~assert.("~jumpTo('A','minimal_..._pad') sans erreur", jumpedOk);
|
||||
~assert.("section a set ~melodyInst = \\pad", ~melodyInst == \pad,
|
||||
"got: " ++ ~melodyInst);
|
||||
|
||||
// ~jumpTo.('A', 'inexistante_xxx') : doit poster mais ne pas crasher
|
||||
try { ~jumpTo.('A', 'inexistante_xxx') }
|
||||
{ |e| jumpedNonExistent = false; ("err: " ++ e.errorString).postln };
|
||||
~assert.("~jumpTo section inexistante : pas de crash", jumpedNonExistent);
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { "boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,106 @@
|
||||
// =====================================================================
|
||||
// e2e_08_live.scd
|
||||
// Verifie les helpers live.scd (LFO, vcf, drop, ...) et le bon
|
||||
// fonctionnement d'un LFO sur une variable globale (sans serveur).
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_08_live ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
~loadAllBlocks = { |path|
|
||||
var src = File.readAllString(path);
|
||||
var lines = src.split($\n);
|
||||
var blocks = List.new;
|
||||
var capturing = false, balance = 0, current = nil;
|
||||
lines.do { |line|
|
||||
if (capturing.not and: { (line.size > 0) and: { line[0] == $( } }) {
|
||||
capturing = true; balance = 0; current = List.new;
|
||||
};
|
||||
if (capturing) {
|
||||
current.add(line);
|
||||
line.do { |c|
|
||||
if (c == $( ) { balance = balance + 1 };
|
||||
if (c == $) ) { balance = balance - 1 };
|
||||
};
|
||||
if (balance == 0) {
|
||||
blocks.add(current.join($\n));
|
||||
capturing = false; current = nil;
|
||||
};
|
||||
};
|
||||
};
|
||||
blocks;
|
||||
};
|
||||
|
||||
s = Server.internal;
|
||||
s.waitForBoot({
|
||||
Routine({
|
||||
var initialKick, valueAfterLfo, blocksFx, blocksLive;
|
||||
s.sync;
|
||||
try { (~base ++ "engine.scd").load } { |e| ("engine err: " ++ e.errorString).postln };
|
||||
2.wait;
|
||||
s.sync;
|
||||
|
||||
// fx_bus.scd : on charge le 1er bloc (defs SynthDef + setup buses)
|
||||
blocksFx = ~loadAllBlocks.(~base ++ "live/fx_bus.scd");
|
||||
blocksFx.do { |b|
|
||||
try { b.interpret } { |e|
|
||||
// ignore les erreurs runtime non critiques
|
||||
};
|
||||
};
|
||||
|
||||
// live.scd : pareil, on charge tous les blocs (le 1er bloc est le SETUP
|
||||
// gigantesque qui contient les SynthDef + les helpers)
|
||||
blocksLive = ~loadAllBlocks.(~base ++ "live/live.scd");
|
||||
blocksLive.do { |b|
|
||||
try { b.interpret } { |e| /* ignore demos errors */ };
|
||||
};
|
||||
s.sync;
|
||||
|
||||
~assert.("~lfoTo defini", ~lfoTo.notNil);
|
||||
~assert.("~lfoStopVar defini", ~lfoStopVar.notNil);
|
||||
~assert.("~vcfOn defini", ~vcfOn.notNil);
|
||||
~assert.("~vcfOff defini", ~vcfOff.notNil);
|
||||
~assert.("~drop defini", ~drop.notNil);
|
||||
~assert.("~breakdown defini", ~breakdown.notNil);
|
||||
~assert.("~stutter defini", ~stutter.notNil);
|
||||
~assert.("~handsUp defini", ~handsUp.notNil);
|
||||
|
||||
// --- Test LFO sur ~kickAmp (sans audio, juste Routine sclang) ---
|
||||
initialKick = ~kickAmp ? 0.5;
|
||||
~kickAmp = 0.5; // baseline
|
||||
~lfoTo.(\kickAmp, 2.0, 0.3, \sin, 0.5); // 2Hz pour bouger vite
|
||||
1.0.wait;
|
||||
valueAfterLfo = ~kickAmp;
|
||||
~assert.("LFO modifie ~kickAmp",
|
||||
valueAfterLfo != 0.5,
|
||||
"kickAmp inchange (" ++ valueAfterLfo ++ ")");
|
||||
~assert.("LFO depth respecte (0.5 +/- 0.3)",
|
||||
(valueAfterLfo > 0.15) and: { valueAfterLfo < 0.85 },
|
||||
"value " ++ valueAfterLfo);
|
||||
|
||||
~lfoStopVar.(\kickAmp);
|
||||
~assert.("~lfoStopVar -> ~lfos[\\kickAmp].isNil",
|
||||
~lfos[\kickAmp].isNil,
|
||||
"still: " ++ ~lfos[\kickAmp]);
|
||||
|
||||
~report.value;
|
||||
}).play;
|
||||
}, 15, { "boot timeout".postln; 1.exit });
|
||||
@@ -0,0 +1,38 @@
|
||||
// =====================================================================
|
||||
// e2e_09_tracks.scd
|
||||
// Verifie que chaque tracks/*.scd compile (.compile retourne une
|
||||
// Function et non nil) sans executer la Routine.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_09_tracks ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
PathName(~base ++ "tracks/").files.do { |pn|
|
||||
if (pn.fullPath.endsWith(".scd")) {
|
||||
var src = File.readAllString(pn.fullPath);
|
||||
var compiled = src.compile;
|
||||
~assert.("compile track " ++ pn.fileName,
|
||||
compiled.isKindOf(Function),
|
||||
"got class " ++ compiled.class);
|
||||
};
|
||||
};
|
||||
|
||||
~report.value;
|
||||
@@ -0,0 +1,103 @@
|
||||
// =====================================================================
|
||||
// e2e_10_timestamps.scd
|
||||
// Verifie que les timestamps `[X M:SS]` dans les .postln des
|
||||
// tracks/*.scd sont monotoniquement croissants.
|
||||
// Detecte les copy-paste casses ou les sections "new --" hors
|
||||
// chronologie (cf timestamps refacto F/G/M/N).
|
||||
// Pure analyse statique : ne lance aucune Routine.
|
||||
// =====================================================================
|
||||
|
||||
"=== e2e_10_timestamps ===".postln;
|
||||
|
||||
~base = "/Users/electron/Documents/Projets_Creatifs/sound_algo/";
|
||||
~testCount = 0;
|
||||
~testFailed = 0;
|
||||
|
||||
~assert = { |label, cond, info|
|
||||
~testCount = ~testCount + 1;
|
||||
if (cond) {
|
||||
(" [OK] " ++ label).postln;
|
||||
} {
|
||||
~testFailed = ~testFailed + 1;
|
||||
(" [FAIL] " ++ label ++ if (info.notNil) { " : " ++ info } { "" }).postln;
|
||||
};
|
||||
};
|
||||
|
||||
~report = {
|
||||
("== " ++ ~testCount ++ " tests, " ++ ~testFailed ++ " failed ==").postln;
|
||||
if (~testFailed > 0) { 1.exit } { 0.exit };
|
||||
};
|
||||
|
||||
// Parse "M:SS" -> seconds. Returns nil si format invalide.
|
||||
~parseTs = { |str|
|
||||
var parts, m, s;
|
||||
parts = str.split($:);
|
||||
if (parts.size != 2) { nil } {
|
||||
m = parts[0].asInteger;
|
||||
s = parts[1].asInteger;
|
||||
(m * 60) + s;
|
||||
};
|
||||
};
|
||||
|
||||
// Extrait les couples (timestamp_seconds, line_number) d'un fichier
|
||||
// en cherchant les "[X M:SS] ...".postln; ou .postln (parenthese).
|
||||
~extractTimestamps = { |srcLines, letter|
|
||||
var pattern, results = List.new;
|
||||
// pattern : [<letter> <m>:<ss>]
|
||||
pattern = "[" ++ letter ++ " ";
|
||||
srcLines.do { |line, i|
|
||||
var startIdx, endIdx, tsStr, ts;
|
||||
startIdx = line.find(pattern);
|
||||
if (startIdx.notNil) {
|
||||
endIdx = line.find("]", false, startIdx);
|
||||
if (endIdx.notNil) {
|
||||
tsStr = line.copyRange(startIdx + pattern.size, endIdx - 1);
|
||||
ts = ~parseTs.(tsStr);
|
||||
if (ts.notNil) {
|
||||
results.add([ts, i + 1, tsStr]);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
results.array;
|
||||
};
|
||||
|
||||
// Verifie monotonie pour une track donnee
|
||||
~checkTrack = { |trackPath|
|
||||
var fileName, src, lines, letter, timestamps, prevTs, allOk;
|
||||
fileName = PathName(trackPath).fileName;
|
||||
// letter = premier char du nom (A_acid_journey -> A)
|
||||
letter = fileName[0].asString;
|
||||
src = File.readAllString(trackPath);
|
||||
lines = src.split($\n);
|
||||
timestamps = ~extractTimestamps.(lines, letter);
|
||||
|
||||
// Au moins 2 timestamps attendus (intro + outro minimum)
|
||||
~assert.(fileName ++ " has timestamps",
|
||||
timestamps.size >= 2,
|
||||
"found " ++ timestamps.size);
|
||||
|
||||
// Monotonie : chaque ts >= precedent
|
||||
prevTs = -1;
|
||||
allOk = true;
|
||||
timestamps.do { |triple|
|
||||
var ts = triple[0], lineNum = triple[1], tsStr = triple[2];
|
||||
if (ts < prevTs) {
|
||||
allOk = false;
|
||||
(" -> regression line " ++ lineNum
|
||||
++ " : [" ++ letter ++ " " ++ tsStr ++ "] vient apres "
|
||||
++ prevTs).postln;
|
||||
};
|
||||
prevTs = ts;
|
||||
};
|
||||
~assert.(fileName ++ " timestamps monotones", allOk);
|
||||
};
|
||||
|
||||
// Iter sur tous les tracks/*.scd
|
||||
PathName(~base ++ "tracks/").files.do { |pn|
|
||||
if (pn.fullPath.endsWith(".scd")) {
|
||||
~checkTrack.(pn.fullPath);
|
||||
};
|
||||
};
|
||||
|
||||
~report.value;
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
# =====================================================================
|
||||
# run_all.sh -- runner pour la suite de tests E2E sound_algo
|
||||
# Execute chaque tests/e2e_NN_xxx.scd et reporte PASS/FAIL.
|
||||
#
|
||||
# Note : sclang termine parfois en exit code != 0 (libc++abi sur quit
|
||||
# du serveur interne) meme quand tous les tests passent. On parse la
|
||||
# ligne "== N tests, M failed ==" dans la sortie au lieu de l'exit code.
|
||||
# =====================================================================
|
||||
|
||||
set -u
|
||||
cd "$(dirname "$0")/.." # racine du projet
|
||||
|
||||
SCLANG="${SCLANG:-/Applications/SuperCollider.app/Contents/MacOS/sclang}"
|
||||
TESTS_DIR="tests"
|
||||
LOGS_DIR="tests/.logs"
|
||||
mkdir -p "$LOGS_DIR"
|
||||
|
||||
if [ ! -x "$SCLANG" ]; then
|
||||
echo "[ERROR] sclang introuvable a $SCLANG"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
results=()
|
||||
total_pass=0
|
||||
total_fail=0
|
||||
total_skip=0
|
||||
|
||||
for scd in "$TESTS_DIR"/e2e_*.scd; do
|
||||
name=$(basename "$scd" .scd)
|
||||
label="${name#e2e_}"
|
||||
log="$LOGS_DIR/${name}.log"
|
||||
|
||||
echo "----------------------------------------------------------------"
|
||||
echo "[RUN] $label"
|
||||
echo "----------------------------------------------------------------"
|
||||
|
||||
# Limite de temps : 60s par test (perl alarm si timeout coreutils absent)
|
||||
# 2>&1 dans le sous-shell pour eviter le "Abort trap: 6" de sclang
|
||||
# (innofensif, vient du arret du serveur interne ; on parse la sortie SC).
|
||||
( perl -e 'alarm 60; exec @ARGV' "$SCLANG" "$scd" ) > "$log" 2>&1
|
||||
rc=$?
|
||||
|
||||
# Parse le resume "== N tests, M failed =="
|
||||
summary=$(grep -E '^== [0-9]+ tests, [0-9]+ failed ==' "$log" | tail -1)
|
||||
if [ -z "$summary" ]; then
|
||||
# Pas de resume -> SKIP/CRASH
|
||||
total_skip=$((total_skip + 1))
|
||||
results+=("[SKIP] $label")
|
||||
echo " -> [SKIP] (pas de resume; rc=$rc)"
|
||||
# Affiche les 30 dernieres lignes pour debug
|
||||
echo " --- last 30 lines of $log ---"
|
||||
tail -30 "$log" | sed 's/^/ /'
|
||||
continue
|
||||
fi
|
||||
|
||||
n_tests=$(echo "$summary" | sed -E 's/^== ([0-9]+) tests, ([0-9]+) failed ==/\1/')
|
||||
n_failed=$(echo "$summary" | sed -E 's/^== ([0-9]+) tests, ([0-9]+) failed ==/\2/')
|
||||
|
||||
if [ "$n_failed" = "0" ]; then
|
||||
total_pass=$((total_pass + 1))
|
||||
results+=("[OK] $label ($n_tests tests)")
|
||||
echo " -> [OK] $n_tests tests"
|
||||
else
|
||||
total_fail=$((total_fail + 1))
|
||||
results+=("[FAIL] $label ($n_failed/$n_tests)")
|
||||
echo " -> [FAIL] $n_failed/$n_tests failed"
|
||||
# Affiche les FAIL specifiques
|
||||
grep -E '^\s*\[FAIL\]' "$log" | sed 's/^/ /'
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "================================================================"
|
||||
echo " RESUME FINAL"
|
||||
echo "================================================================"
|
||||
for r in "${results[@]}"; do
|
||||
echo " $r"
|
||||
done
|
||||
echo
|
||||
echo " Tests OK : $total_pass"
|
||||
echo " Tests FAIL : $total_fail"
|
||||
echo " Tests SKIP : $total_skip"
|
||||
echo "================================================================"
|
||||
|
||||
if [ "$total_fail" -gt 0 ] || [ "$total_skip" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,148 @@
|
||||
// =====================================================================
|
||||
// A_acid_journey.scd
|
||||
// Track autonome -- Cmd+Entree sur le bloc (...) pour la lancer.
|
||||
// PREREQUIS : engine.scd evalue (les SynthDef + helpers doivent exister).
|
||||
// =====================================================================
|
||||
|
||||
// --- TRACK A : "ACID JOURNEY" 7 minutes -----------------------------
|
||||
// 0:00 minimal -> 2:00 acid rave -> 4:00 detroit -> 5:30 hard -> 6:30 outro
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[A 0:00] minimal -- kick T5 sub + melody PAD...".postln;
|
||||
~bpm = 124; ~acidCutoff = 500; ~acidRq = 0.25; ~acidDrive = 1.5; ~acidAmp = 0.3;
|
||||
~kickAmp = 0.5; ~hatAmp = 0.08; ~melodyAmp = 0.14;
|
||||
~kickFreq = 42; ~kickPitchAmt = 2.0; ~kickDecay = 0.5;
|
||||
~kickDrive = 1.0; ~kickClick = 0.05; // T5 sub deep
|
||||
~melodyInst = \pad; // PAD pour l'intro
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 1500;
|
||||
~melodyNotes = [60,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0,
|
||||
60,0,0,0,0,0,0,0, 65,0,0,0,0,0,0,0];
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\third);
|
||||
120.wait;
|
||||
|
||||
"[A 2:00] acid rave -- kick T1 + melody LEAD + variations...".postln;
|
||||
~bpm = 132; ~acidCutoff = 800; ~acidRq = 0.15; ~acidDrive = 2.5;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.32;
|
||||
~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~melodyInst = \lead; // LEAD pour le drop
|
||||
~melodyAttack = 0.012; ~melodyRelease = 0.25; ~melodyCutoff = 2400;
|
||||
~melodyAmp = 0.16;
|
||||
~acidNotes = [36,36,48,36,39,36,43,39, 36,41,36,39,43,36,36,41];
|
||||
~acidSlides = [0,0,1,0,0,0,0,1, 0,0,0,1,0,0,0,0];
|
||||
~melodyNotes = [60,0,67,0,70,0,67,65, 63,0,60,0,0,67,70,72,
|
||||
75,0,72,70,67,0,0,65, 63,60,0,67,70,0,72,0];
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
// 120s avec micro-variations toutes les 4s
|
||||
30.do { |k|
|
||||
if (0.25.coin) { ~acidCutoff = rrand(600, 1400); ~reload.value };
|
||||
// Melodie : alterne entre genMelody + mutate de l'existant
|
||||
if (0.20.coin) {
|
||||
if (0.5.coin) {
|
||||
// 50% : nouveau pattern dans une scale aleatoire
|
||||
~melodyNotes = ~genMelody.(0.55,
|
||||
[~scaleMinorPent, ~scaleMinor, ~scaleDorian, ~scaleHigh].choose);
|
||||
} {
|
||||
// 50% : mutation legere du pattern existant
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.2);
|
||||
};
|
||||
~reload.value;
|
||||
};
|
||||
if (0.10.coin) { ~acidSlides = ~genAcidSlides.(0.3); ~reload.value };
|
||||
// 5% chance d'octavate la melodie
|
||||
if (0.05.coin) { ~melodyNotes = ~octavate.(~melodyNotes, 0.25); ~reload.value };
|
||||
4.wait;
|
||||
};
|
||||
|
||||
"[A 4:00] detroit stabs -- kick T2 + melody STAB...".postln;
|
||||
~bpm = 128; ~acidCutoff = 700; ~acidDrive = 2.2;
|
||||
~kickFreq = 65; ~kickPitchAmt = 4.0; ~kickDecay = 0.18;
|
||||
~kickDrive = 1.8; ~kickClick = 0.45;
|
||||
~melodyInst = \stab; // STAB style Detroit
|
||||
~melodyDrive = 2.8; ~melodyCutoff = 1500;
|
||||
~melodyNotes = [63,0,0,0,70,0,67,0, 65,0,0,0,70,0,72,0,
|
||||
63,0,0,0,67,0,70,0, 65,0,60,0,67,0,0,0];
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.06;
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
// 90s avec stabs qui mutent (Detroit = Cm avec variations chromatiques)
|
||||
18.do { |k|
|
||||
if (0.3.coin) {
|
||||
~melodyNotes = ~genMelody.(0.35,
|
||||
[~scaleMinor, ~scaleDorian, ~scaleHarmonicMin].choose);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.2.coin) { ~acidCutoff = rrand(500, 1500); ~reload.value };
|
||||
if (0.15.coin) { ~kickClick = rrand(0.2, 0.55); ~reload.value };
|
||||
// Transposition aleatoire (-5/+5 semi-tons) toutes les ~30s
|
||||
if (0.07.coin) {
|
||||
~melodyNotes = ~transpose.(~melodyNotes, [-5, -3, 3, 5, 7].choose);
|
||||
~reload.value;
|
||||
" -> melodie transposee".postln;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
|
||||
"[A 5:30] hard push -- kick T4 distordu...".postln;
|
||||
~bpm = 140; ~acidCutoff = 1500; ~acidRq = 0.08; ~acidDrive = 3.8;
|
||||
~kickSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0];
|
||||
~kickFreq = 60; ~kickPitchAmt = 5.0; ~kickDecay = 0.28;
|
||||
~kickDrive = 3.5; ~kickClick = 0.3; // T4 distordu
|
||||
~melodyAmp = 0;
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
60.wait;
|
||||
"[A 6:30] new -- supersaw + ml1 long melody + vcf moog + dub fx...".postln;
|
||||
~melodyInst = \supersaw;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.35; ~melodyCutoff = 2200;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = (~ml1 ? [60,0,67,0,70,0,67,65, 63,0,60,0,0,67,70,72]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.3, 1500, \sin, 2500) };
|
||||
~vcfOn !? { ~vcfOn.(\moog, 1200, 0.45) };
|
||||
~fxPreset !? { ~fxPreset.(\dub) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[A 7:15] new -- guzheng + acid evolve...".postln;
|
||||
~melodyInst = \guzheng;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.6; ~melodyCutoff = 4000;
|
||||
~melodyAmp = 0.18;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
~stutter !? { ~stutter.(8, 1.5) };
|
||||
~fxPreset !? { ~fxPreset.(\space) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
30.wait;
|
||||
~lfoStopEverything !? { ~lfoStopEverything.() };
|
||||
|
||||
|
||||
"[A 7:45] outro -- melody PAD qui s'efface...".postln;
|
||||
~melodyInst = \pad; // PAD doux pour finir
|
||||
~melodyAttack = 0.5; ~melodyRelease = 2.0; ~melodyAmp = 0.12;
|
||||
~reload.value;
|
||||
30.do { |k|
|
||||
var x = 1 - ((k + 1) / 30);
|
||||
~acidCutoff = 200 + (x * 1300);
|
||||
~acidAmp = x * 0.32; ~kickAmp = x * 0.5; ~hatAmp = x * 0.16;
|
||||
~melodyAmp = x * 0.12;
|
||||
~reload.value;
|
||||
1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[A 8:15] === fin ACID JOURNEY ===".postln;
|
||||
}).play;
|
||||
"=== TRACK A : ACID JOURNEY 7 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,154 @@
|
||||
// =====================================================================
|
||||
// B_deep_to_hard.scd
|
||||
// Track autonome -- Cmd+Entree sur le bloc (...) pour la lancer.
|
||||
// PREREQUIS : engine.scd evalue (les SynthDef + helpers doivent exister).
|
||||
// =====================================================================
|
||||
|
||||
// --- TRACK B : "DEEP TO HARD" 8 minutes ------------------------------
|
||||
// demarre dub, monte progressivement vers hard techno
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[B 0:00] dub start -- kick T3 boomy + melody PAD...".postln;
|
||||
~bpm = 110; ~acidCutoff = 400; ~acidRq = 0.2; ~acidDrive = 1.6; ~acidAmp = 0.22;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~kickAmp = 0.45; ~hatAmp = 0.08;
|
||||
~kickFreq = 48; ~kickPitchAmt = 2.5; ~kickDecay = 0.6;
|
||||
~kickDrive = 1.2; ~kickClick = 0.08;
|
||||
~melodyInst = \pad; // PAD pour dub
|
||||
~hatSteps = [0,0,0,0, 0,0,1,0, 0,0,0,0, 0,0,1,0];
|
||||
~melodyNotes = [60,0,0,0,63,0,0,0, 67,0,0,0,70,0,0,0,
|
||||
72,0,0,0,70,0,0,0, 67,0,0,0,63,0,0,0];
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyAmp = 0.14;
|
||||
~melodyCutoff = 1500;
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\bassline);
|
||||
// 150s de dub avec nappes qui mutent doucement
|
||||
30.do { |k|
|
||||
// Mutation legere du pad toutes les ~10s
|
||||
if (0.20.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.15,
|
||||
[~scaleMinor, ~scaleDorian, ~scalePhrygian].choose);
|
||||
~reload.value;
|
||||
};
|
||||
// Cutoff melody varie (atmosphere)
|
||||
if (0.20.coin) { ~melodyCutoff = rrand(1200, 2200); ~reload.value };
|
||||
// Acid cutoff doux
|
||||
if (0.15.coin) { ~acidCutoff = rrand(300, 700); ~reload.value };
|
||||
// Octavate occasionnelle
|
||||
if (0.05.coin) { ~melodyNotes = ~octavate.(~melodyNotes, 0.2); ~reload.value };
|
||||
5.wait;
|
||||
};
|
||||
|
||||
"[B 2:30] tempo monte 110->125 -- melody SAW3 (epaissit)...".postln;
|
||||
~melodyInst = \saw3; // SAW3 pour epaisseur
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyDrive = 1.4;
|
||||
~reload.value;
|
||||
30.do { |k|
|
||||
~bpm = 110 + ((k + 1) * 0.5);
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
2.wait;
|
||||
};
|
||||
// 3:30
|
||||
|
||||
"[B 3:30] kick 4/4 + acid ouvre -- kick T1 + melody PLUCK...".postln;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~kickAmp = 0.5;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.32;
|
||||
~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~melodyInst = \pluck; // PLUCK pour la transition
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.5; ~melodyCutoff = 5000;
|
||||
~acidCutoff = 900; ~acidDrive = 2.2; ~acidAmp = 0.28;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~hatAmp = 0.14;
|
||||
~reload.value;
|
||||
// 90s avec acid qui mute progressivement
|
||||
18.do { |k|
|
||||
if (0.3.coin) {
|
||||
~acidNotes = ~genAcidNotes.value;
|
||||
~acidAccents = ~genAcidAccents.(0.4);
|
||||
~acidSlides = ~genAcidSlides.(0.3);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.2.coin) { ~acidCutoff = rrand(700, 1400); ~reload.value };
|
||||
if (0.15.coin) {
|
||||
// ghost notes occasionnelles dans le kick
|
||||
~kickSteps = ~genKickPattern.(0.25);
|
||||
~reload.value;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
// remettre kick 4/4 propre avant la suite
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~reload.value;
|
||||
|
||||
"[B 5:00] tempo monte 125->140...".postln;
|
||||
30.do { |k|
|
||||
~bpm = 125 + ((k + 1) * 0.5);
|
||||
TempoClock.default.tempo = ~bpm / 60;
|
||||
2.wait;
|
||||
};
|
||||
// 6:00
|
||||
|
||||
"[B 6:00] hard push -- kick T4 distordu...".postln;
|
||||
~kickSteps = [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0];
|
||||
~kickFreq = 60; ~kickPitchAmt = 5.0; ~kickDecay = 0.28;
|
||||
~kickDrive = 3.5; ~kickClick = 0.3; // T4 distordu
|
||||
~hatSteps = [0,1,1,1, 0,1,1,0, 0,1,1,1, 0,1,1,0];
|
||||
~hatAmp = 0.15;
|
||||
~acidCutoff = 1500; ~acidRq = 0.08; ~acidDrive = 3.5;
|
||||
~melodyAmp = 0;
|
||||
~reload.value;
|
||||
90.wait;
|
||||
"[B 7:30] new -- rhodes + ml5 + fxPreset dream...".postln;
|
||||
~melodyInst = \rhodes;
|
||||
~melodyAttack = 0.01; ~melodyRelease = 0.7; ~melodyCutoff = 3500;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = (~ml5 ? [60,0,0,0,0,0,0,0,67,0,0,0,0,0,0,0]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.2, 1200, \tri, 2800) };
|
||||
~fxPreset !? { ~fxPreset.(\dream) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
40.wait;
|
||||
|
||||
"[B 8:10] new -- vcf ladder + hooverbass push...".postln;
|
||||
~melodyInst = \hooverbass;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.3; ~melodyCutoff = 1800;
|
||||
~melodyAmp = 0.18;
|
||||
~vcfOn !? { ~vcfOn.(\ladder, 1500, 0.5) };
|
||||
~breakdown !? { ~breakdown.(8) };
|
||||
~fxPreset !? { ~fxPreset.(\industrial) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
25.wait;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
|
||||
|
||||
"[B 8:35] outro -- melody PAD qui revient...".postln;
|
||||
~melodyInst = \pad; // PAD pour finir
|
||||
~melodyAttack = 0.5; ~melodyRelease = 2.0; ~melodyAmp = 0.10;
|
||||
~reload.value;
|
||||
30.do { |k|
|
||||
var x = 1 - ((k + 1) / 30);
|
||||
~acidCutoff = 200 + (x * 1300);
|
||||
~acidAmp = x * 0.32; ~kickAmp = x * 0.5; ~hatAmp = x * 0.15;
|
||||
~melodyAmp = x * 0.10;
|
||||
~reload.value;
|
||||
1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[B 9:05] === fin DEEP TO HARD ===".postln;
|
||||
}).play;
|
||||
"=== TRACK B : DEEP TO HARD 8 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,49 @@
|
||||
# tracks/ — Tracks autonomes A-W
|
||||
|
||||
23 tracks live, une lettre par track, ~5-10 minutes chacune.
|
||||
Cmd+Entree sur le bloc `(...)` pour lancer.
|
||||
|
||||
## Structure type
|
||||
|
||||
```supercollider
|
||||
(
|
||||
~track !? { ~track.stop }; // stop l'ancienne Routine
|
||||
~track = Routine({
|
||||
"[X 0:00] section ...".postln;
|
||||
~bpm = 124; ~kickFreq = 42; ~melodyInst = \pad;
|
||||
~melodyNotes = [60,0,...];
|
||||
TempoClock.default.tempo = ~bpm/60;
|
||||
~reload.value; // rebuild Pdef
|
||||
[\kickSeq, \hatSeq, ...].do { |k| Pdef(k).play };
|
||||
120.wait; // 2 minutes
|
||||
|
||||
"[X 2:00] next section ...".postln;
|
||||
~bpm = 132; ...
|
||||
~reload.value;
|
||||
...
|
||||
}).play;
|
||||
)
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- En-tete commentaire : nom + duree + sections + timestamps (0:00 -> X:XX)
|
||||
- `~track.stop` AVANT chaque relance pour eviter superposition
|
||||
- `~reload.value` apres chaque modification de `~xxx` -> Pdef
|
||||
- Sections delimitees par `.wait` (secondes) + log `"[X M:SS] ...".postln`
|
||||
- BPM via `TempoClock.default.tempo = ~bpm/60`
|
||||
- Variations live via `if (0.20.coin) { ... }` dans des `.do` loops
|
||||
- Nommage : `<LETTER>_<slug>.scd`, ex `A_acid_journey.scd`
|
||||
|
||||
## Section helpers
|
||||
|
||||
Chaque section devrait etre referencee dans `control/jump.scd`
|
||||
via `~sections[\X][\slug] = { ... }` pour permettre `~jumpTo.(\X, \slug)`.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Ne pas oublier `~track !? { ~track.stop }` -> Routines empilees
|
||||
- Ne pas omettre `~reload.value` apres modif `~xxx` -> Pdef stale
|
||||
- Ne pas appeler `Pdef(k).play` sans avoir defini les patterns dans engine
|
||||
- Ne pas hardcoder de chemins absolus (utiliser `~base`)
|
||||
- Ne pas creer de tracks > 10 min sans transition (fatigue auditive)
|
||||
@@ -0,0 +1,188 @@
|
||||
// =====================================================================
|
||||
// C_hypnotic_loop.scd
|
||||
// Track autonome -- Cmd+Entree sur le bloc (...) pour la lancer.
|
||||
// PREREQUIS : engine.scd evalue (les SynthDef + helpers doivent exister).
|
||||
// =====================================================================
|
||||
|
||||
// --- TRACK C : "HYPNOTIC LOOP" 10 minutes ----------------------------
|
||||
// minimal qui evolue lentement, melodie ostinato qui se developpe
|
||||
(
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[C 0:00] hypnotic -- kick T6 + fmBell DUBSTEP wobble...".postln;
|
||||
~bpm = 126; ~acidCutoff = 600; ~acidRq = 0.2; ~acidDrive = 1.8; ~acidAmp = 0.26;
|
||||
~kickFreq = 70; ~kickPitchAmt = 3.5; ~kickDecay = 0.22;
|
||||
~kickDrive = 2.0; ~kickClick = 0.35;
|
||||
~melodyInst = \fmBell; // FM Bell dubstep
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyCutoff = 400;
|
||||
~melodyDrive = 3.5;
|
||||
~melodyWobbleRate = 4;
|
||||
~melodyWobbleDepth = 1800;
|
||||
~melodyWobbleShape = 0;
|
||||
~melodySubAmt = 0.9; // SUB MASSIF dubstep
|
||||
~acidNotes = [36,0,36,0,36,0,41,0, 36,0,36,0,36,0,39,0];
|
||||
~acidAccents = [1,0,0,0,1,0,0,0, 1,0,0,0,1,0,0,0];
|
||||
~acidSlides = [0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0];
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~kickAmp = 0.5;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~hatAmp = 0.10;
|
||||
~melodyNotes = [60,0,0,67,0,70,0,67, 60,0,0,67,0,70,0,72,
|
||||
60,0,0,67,0,70,0,67, 63,0,0,70,0,72,0,75];
|
||||
~melodyAmp = 0.13;
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\arp);
|
||||
// 120s avec ostinato qui mute lentement (mutations + scales variees)
|
||||
24.do { |k|
|
||||
// Mutation/regen avec scales japonaise/dorian/harmonique (timbre fmBell aime)
|
||||
if (0.2.coin) {
|
||||
~melodyNotes = ~genMelody.(0.5,
|
||||
[~scaleMinorPent, ~scaleDorian, ~scaleJapanese, ~scaleHarmonicMin].choose);
|
||||
~reload.value;
|
||||
};
|
||||
// Mutation legere du pattern courant
|
||||
if (0.15.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.15);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.15.coin) { ~melodyCutoff = rrand(1500, 2500); ~reload.value };
|
||||
if (0.1.coin) { ~acidAccents = ~genAcidAccents.(0.3); ~reload.value };
|
||||
// Octavate occasionnelle
|
||||
if (0.05.coin) { ~melodyNotes = ~octavate.(~melodyNotes, 0.2); ~reload.value };
|
||||
5.wait;
|
||||
};
|
||||
|
||||
"[C 2:00] cutoff up doucement...".postln;
|
||||
60.do { |k|
|
||||
var x = (k + 1) / 60;
|
||||
~acidCutoff = 600 + (x * 1500);
|
||||
~melodyCutoff = 1800 + (x * 1500);
|
||||
~reload.value;
|
||||
2.wait;
|
||||
};
|
||||
// 4:00
|
||||
|
||||
"[C 4:00] hat 16ths -- kick T1 + melody SAW3 + variations...".postln;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
~hatAmp = 0.08;
|
||||
~kickFreq = 55; ~kickPitchAmt = 3.0; ~kickDecay = 0.32;
|
||||
~kickDrive = 1.3; ~kickClick = 0.2;
|
||||
~melodyInst = \saw3;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.25; ~melodyCutoff = 2200;
|
||||
~melodyDrive = 1.4;
|
||||
~reload.value;
|
||||
// 120s avec melodie qui se transforme (mutate + transpose + scales)
|
||||
24.do { |k|
|
||||
// Generation nouvelle (40%) ou mutation (60%) du pattern
|
||||
if (0.25.coin) {
|
||||
if (0.4.coin) {
|
||||
~melodyNotes = ~genMelody.(0.5,
|
||||
[~scaleMinorPent, ~scaleDorian, ~scaleHigh].choose);
|
||||
} {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.2);
|
||||
};
|
||||
~reload.value;
|
||||
};
|
||||
if (0.15.coin) { ~melodyCutoff = rrand(1800, 3500); ~reload.value };
|
||||
// Tous les ~30s, transposition par intervalle musical
|
||||
if (0.07.coin) {
|
||||
~melodyNotes = ~transpose.(~melodyNotes, [-7, -5, 5, 7].choose);
|
||||
~reload.value;
|
||||
" -> melodie transposee".postln;
|
||||
};
|
||||
// Octavate occasionnelle
|
||||
if (0.05.coin) { ~melodyNotes = ~octavate.(~melodyNotes, 0.2); ~reload.value };
|
||||
5.wait;
|
||||
};
|
||||
|
||||
"[C 6:00] resonance push -- kick T2 + melody mute progressivement...".postln;
|
||||
~kickFreq = 65; ~kickPitchAmt = 4.0; ~kickDecay = 0.18;
|
||||
~kickDrive = 1.8; ~kickClick = 0.45;
|
||||
30.do { |k|
|
||||
var x = (k + 1) / 30;
|
||||
~acidRq = 0.2 - (x * 0.13);
|
||||
~acidCutoffEnv = 3500 + (x * 2000);
|
||||
// Mutation acide progressive sur la melodie aussi
|
||||
if (0.2.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.2,
|
||||
[~scaleHarmonicMin, ~scalePhrygian].choose);
|
||||
};
|
||||
// Cutoff melody monte avec la resonance acid
|
||||
~melodyCutoff = 2200 + (x * 1500);
|
||||
~reload.value;
|
||||
2.wait;
|
||||
};
|
||||
// 7:00
|
||||
|
||||
"[C 7:00] full ressu + chaos + rotation timbres + wobble dubstep...".postln;
|
||||
24.do { |k|
|
||||
~randomTweak.(0.4);
|
||||
if (0.2.coin) { ~acidNotes = ~genAcidNotes.value; ~reload.value };
|
||||
if (0.15.coin) { ~hatSteps = ~genKickPattern.(0.5); ~reload.value };
|
||||
// Rotation timbre + wobble aleatoire pour fmBell
|
||||
if (0.25.coin) {
|
||||
~melodyInst = [\lead, \fmBell, \saw3, \pluck].choose;
|
||||
if (~melodyInst == \fmBell) {
|
||||
~melodyWobbleRate = [2, 4, 8, 16].choose;
|
||||
~melodyWobbleShape = [0, 1].choose;
|
||||
~melodyWobbleDepth = rrand(1000, 3000);
|
||||
~melodyCutoff = rrand(300, 800);
|
||||
(" -> fmBell wobble " ++ ~melodyWobbleRate ++ "Hz").postln;
|
||||
} { ~melodyCutoff = rrand(1500, 3500) };
|
||||
~reload.value;
|
||||
(" -> melody " ++ ~melodyInst).postln;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
"[C 9:00] new -- vocalPad ambient + mxl1 long + freeze...".postln;
|
||||
~melodyInst = \vocalPad;
|
||||
~melodyAttack = 0.5; ~melodyRelease = 2.0; ~melodyCutoff = 2200;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = (~mxl1 ? [60,0,67,0,70,0,67,65, 63,0,60,0,0,67,70,72]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.15, 800, \sin, 2200) };
|
||||
~fxPreset !? { ~fxPreset.(\dream) };
|
||||
~freeze !? { ~freeze.(4) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
60.wait;
|
||||
|
||||
"[C 10:00] new -- drone + reverbTail final...".postln;
|
||||
~melodyInst = \drone;
|
||||
~melodyAttack = 1.5; ~melodyRelease = 3.0; ~melodyCutoff = 1500;
|
||||
~melodyAmp = 0.16;
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
~reverbTail !? { ~reverbTail.(6) };
|
||||
~fxPreset !? { ~fxPreset.(\cosmic) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
40.wait;
|
||||
|
||||
|
||||
"[C 10:40] outro long -- melody PAD qui s'efface lentement...".postln;
|
||||
~melodyInst = \pad; // PAD pour finir
|
||||
~melodyAttack = 0.6; ~melodyRelease = 2.5;
|
||||
~reload.value;
|
||||
60.do { |k|
|
||||
var x = 1 - ((k + 1) / 60);
|
||||
~acidCutoff = 200 + (x * 1900);
|
||||
~acidAmp = x * 0.26; ~kickAmp = x * 0.5; ~hatAmp = x * 0.10;
|
||||
~melodyAmp = x * 0.13;
|
||||
~reload.value;
|
||||
1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[C 11:40] === fin HYPNOTIC LOOP ===".postln;
|
||||
}).play;
|
||||
"=== TRACK C : HYPNOTIC LOOP 10 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,207 @@
|
||||
// =====================================================================
|
||||
// D_wobble_drop.scd
|
||||
// Track autonome -- Cmd+Entree sur le bloc (...) pour la lancer.
|
||||
// PREREQUIS : engine.scd evalue (les SynthDef + helpers doivent exister).
|
||||
// =====================================================================
|
||||
|
||||
// --- TRACK D : "WOBBLE DROP" -- 7 minutes dubstep --------------------
|
||||
// 140 BPM half-time : kick 1+9, snare 5+13, hat 16ths, fmBell wobble
|
||||
// intro / drop1 / break / drop2 / outro
|
||||
(
|
||||
[~track1, ~track2, ~track3, ~track4].do { |t| t !? { t.stop } };
|
||||
[~chaosRoutine, ~breathRoutine, ~rythmRoutine, ~accelRoutine,
|
||||
~filterSweep, ~introRoutine, ~outroRoutine].do { |r| r !? { r.stop } };
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[D 0:00] === WOBBLE DROP -- 7 minutes 140 BPM ===".postln;
|
||||
[\acidSeq, \kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
TempoClock.default.tempo = 140 / 60;
|
||||
|
||||
// ------ 0:00 INTRO -- pad atmospherique seul ------
|
||||
"[D 0:00] intro pad sombre...".postln;
|
||||
~melodyInst = \pad;
|
||||
~melodyAttack = 0.5; ~melodyRelease = 2.0; ~melodyCutoff = 1200;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = [60, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
|
||||
65, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0];
|
||||
~kickSteps = (0 ! 16); ~snareSteps = (0 ! 16);
|
||||
~hatSteps = (0 ! 16); ~acidAmp = 0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\dubBass);
|
||||
30.wait;
|
||||
|
||||
// ------ 0:30 DRUM ENTRY -- kick + snare half-time ------
|
||||
"[D 0:30] drum entry half-time...".postln;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~kickFreq = 48; ~kickPitchAmt = 3.5; ~kickDecay = 0.5;
|
||||
~kickDrive = 1.5; ~kickClick = 0.15; ~kickAmp = 0.6;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~snareAmp = 0.45; ~snareFreq = 220; ~snareNoiseAmt = 0.65; ~snareDecay = 0.16;
|
||||
~reload.value;
|
||||
30.wait;
|
||||
|
||||
// ------ 1:00 BUILD -- hat 16ths + riser ------
|
||||
"[D 1:00] build avec hat 16ths + riser...".postln;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~reload.value;
|
||||
Synth(\riser, [\dur, 12, \startCutoff, 200, \endCutoff, 8000, \amp, 0.25]);
|
||||
12.wait;
|
||||
|
||||
// ------ 1:12 IMPACT + DROP 1 ------
|
||||
"[D 1:12] === IMPACT + DROP 1 wobble dubstep ===".postln;
|
||||
Synth(\impact, [\freq, 45, \decay, 1.8, \amp, 0.7]);
|
||||
0.1.wait;
|
||||
~melodyInst = \fmBell;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4;
|
||||
~melodyCutoff = 350; ~melodyDrive = 4.0;
|
||||
~melodyWobbleRate = 4; ~melodyWobbleDepth = 2200;
|
||||
~melodyWobbleShape = 0; ~melodySubAmt = 0.95;
|
||||
~melodyAmp = 0.20; ~melodyBoost = 1.8;
|
||||
~melodyNotes = [36, 0, 0, 0, 36, 0, 0, 0,
|
||||
39, 0, 0, 0, 39, 0, 0, 0,
|
||||
36, 0, 0, 0, 36, 0, 0, 0,
|
||||
41, 0, 0, 0, 39, 0, 0, 0];
|
||||
~hatAmp = 0.08;
|
||||
~reload.value;
|
||||
18.do { |k|
|
||||
if (0.3.coin) {
|
||||
~melodyWobbleRate = [2, 4, 4, 8].choose;
|
||||
~melodyWobbleShape = [0, 0, 1].choose;
|
||||
~melodyWobbleDepth = rrand(1500, 2800);
|
||||
~reload.value;
|
||||
(" -> wobble " ++ ~melodyWobbleRate ++ "Hz shape" ++ ~melodyWobbleShape).postln;
|
||||
};
|
||||
if (0.2.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.15,
|
||||
[24, 36, 36, 39, 41, 43, 48]);
|
||||
~reload.value;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
// 2:42
|
||||
|
||||
// ------ 2:42 MID BREAKDOWN ------
|
||||
"[D 2:42] mid breakdown -- pad seul...".postln;
|
||||
~kickSteps = (0 ! 16); ~snareSteps = (0 ! 16);
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.06;
|
||||
~melodyInst = \pad;
|
||||
~melodyAttack = 0.6; ~melodyRelease = 2.0; ~melodyCutoff = 1500;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = [60, 0, 0, 0, 63, 0, 0, 0, 65, 0, 0, 0, 67, 0, 0, 0,
|
||||
65, 0, 0, 0, 63, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0];
|
||||
~reload.value;
|
||||
30.wait;
|
||||
|
||||
// ------ 3:12 BUILD 2 -- snare roll + riser ------
|
||||
"[D 3:12] build 2 avec snare roll...".postln;
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 9000, \amp, 0.3]);
|
||||
16.do { |k|
|
||||
var rate = (k / 4).floor + 2;
|
||||
if (k.mod((16 / rate).round.max(1)) == 0) {
|
||||
Synth(\snare, [\amp, 0.35 + (k * 0.012), \decay, 0.06]);
|
||||
};
|
||||
~hatAmp = 0.06 + (k * 0.005);
|
||||
~reload.value;
|
||||
1.wait;
|
||||
};
|
||||
// 3:28
|
||||
|
||||
// ------ 3:28 IMPACT + DROP 2 -- wobble CHOP ------
|
||||
"[D 3:28] === IMPACT + DROP 2 wobble chop ===".postln;
|
||||
Synth(\impact, [\freq, 40, \decay, 2.0, \amp, 0.75]);
|
||||
0.1.wait;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~melodyInst = \fmBell;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.3;
|
||||
~melodyCutoff = 300; ~melodyDrive = 4.5;
|
||||
~melodyWobbleRate = 8; ~melodyWobbleDepth = 2800;
|
||||
~melodyWobbleShape = 1; // CHOP square wobble
|
||||
~melodySubAmt = 1.0;
|
||||
~melodyAmp = 0.22;
|
||||
~melodyNotes = [36, 0, 39, 0, 36, 0, 0, 41,
|
||||
36, 0, 39, 41, 0, 0, 36, 0,
|
||||
36, 0, 39, 0, 36, 0, 43, 41,
|
||||
39, 0, 0, 36, 0, 41, 39, 0];
|
||||
~reload.value;
|
||||
20.do { |k|
|
||||
if (0.4.coin) {
|
||||
~melodyWobbleRate = [4, 8, 8, 16].choose;
|
||||
~melodyWobbleShape = [0, 1, 1].choose;
|
||||
~melodyWobbleDepth = rrand(1500, 3200);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.25.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.2, [24, 36, 39, 41, 43, 48]);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.1.coin) {
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0];
|
||||
~reload.value;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
// 5:08
|
||||
|
||||
// ------ 5:08 OUTRO -- fade out ------
|
||||
"[D 5:08] new -- DROP 3 ringMod + reeseHard fx industrial...".postln;
|
||||
~melodyInst = \reeseHard;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.3; ~melodyCutoff = 280;
|
||||
~melodyDrive = 4.5; ~melodyAmp = 0.20;
|
||||
~melodyNotes = [36, 0, 0, 0, 39, 0, 0, 0,
|
||||
36, 0, 41, 0, 39, 0, 36, 0,
|
||||
36, 0, 0, 0, 41, 0, 43, 0,
|
||||
39, 0, 36, 0, 41, 0, 39, 0];
|
||||
~ringMod !? { ~ringMod.(220, 3) };
|
||||
~vcfOn !? { ~vcfOn.(\ladder, 800, 0.55) };
|
||||
~fxPreset !? { ~fxPreset.(\industrial) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
35.wait;
|
||||
|
||||
"[D 5:43] new -- vocalPad breakdown + mepic1 cinematic...".postln;
|
||||
~melodyInst = \vocalPad;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.8; ~melodyCutoff = 2200;
|
||||
~melodyAmp = 0.18;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~melodyNotes = (~mepic1 ? [60,0,63,0,67,0,70,0, 72,0,70,67,63,0,60,0]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.2, 1000, \sin, 2200) };
|
||||
~fxPreset !? { ~fxPreset.(\dream) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
25.wait;
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
|
||||
"[D 6:08] outro fade...".postln;
|
||||
~melodyInst = \pad;
|
||||
~melodyAttack = 0.6; ~melodyRelease = 2.5; ~melodyCutoff = 800;
|
||||
~reload.value;
|
||||
60.do { |k|
|
||||
var x = 1 - ((k + 1) / 60);
|
||||
~kickAmp = x * 0.6;
|
||||
~snareAmp = x * 0.45;
|
||||
~hatAmp = x * 0.10;
|
||||
~melodyAmp = x * 0.18;
|
||||
~melodyCutoff = 200 + (x * 600);
|
||||
~reload.value;
|
||||
2.wait;
|
||||
};
|
||||
// 7:08
|
||||
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq].do { |k| Pdef(k).stop };
|
||||
"[D 8:08] === fin WOBBLE DROP ===".postln;
|
||||
}).play;
|
||||
"=== TRACK D : WOBBLE DROP 7 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,308 @@
|
||||
// =====================================================================
|
||||
// E_vietnam_hard.scd
|
||||
//
|
||||
// Hard dubstep vietnamien -- 8 minutes, 150 BPM half-time
|
||||
// - Melodie en pentatonique vietnamienne (Đờn ca tài tử)
|
||||
// notes : C D F G A (60, 62, 65, 67, 69) en majeur, 60 63 65 67 70 en mineur
|
||||
// - Synthe melodique \pipa (luth) puis \erhu (violon) + \growl (drop)
|
||||
// - Kick T4 distordu + snare crack + hat 16ths
|
||||
// - 2 drops, breakdown au gong, build avec snare roll
|
||||
//
|
||||
// PREREQUIS : engine.scd ET synthdefs_asia.scd evalues.
|
||||
// Pour stopper en cours : (~track.stop;)
|
||||
// =====================================================================
|
||||
|
||||
(
|
||||
[~track1, ~track2, ~track3, ~track4].do { |t| t !? { t.stop } };
|
||||
[~chaosRoutine, ~breathRoutine, ~rythmRoutine, ~accelRoutine,
|
||||
~filterSweep, ~introRoutine, ~outroRoutine,
|
||||
~melodyEvolve, ~lRotate, ~randomLoop].do { |r| r !? { r.stop } };
|
||||
~track !? { ~track.stop };
|
||||
|
||||
// Pentatonique vietnamienne (Đờn ca tài tử style)
|
||||
~scaleVietnamMin = [60, 63, 65, 67, 70, 72, 75, 77]; // pent mineure
|
||||
~scaleVietnamMaj = [60, 62, 65, 67, 69, 72, 74, 77]; // pent majeure (đờn xuân)
|
||||
|
||||
~track = Routine({
|
||||
"[E 0:00] === HARD DUBSTEP VIETNAM -- 8 min 150 BPM ===".postln;
|
||||
[\acidSeq, \kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
TempoClock.default.tempo = 150 / 60;
|
||||
|
||||
// ------ 0:00 INTRO -- gong + pipa solo (melodie vietnamienne) ----
|
||||
"[E 0:00] intro gong + pipa...".postln;
|
||||
Synth(\gong, [\freq, 55, \decay, 6, \amp, 0.55]);
|
||||
~melodyInst = \pipa;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.6;
|
||||
~melodyCutoff = 4000; ~melodyDrive = 1.4;
|
||||
~melodyAmp = 0.24; ~melodyBoost = 1.8;
|
||||
// Phrase pent vietnamienne -- mineur ascendant (si bemol est la couleur asiatique)
|
||||
~melodyNotes = [ 60, 0, 63, 0, 65, 67, 70, 0,
|
||||
72, 0, 0, 70, 67, 0, 63, 60,
|
||||
63, 0, 65, 0, 67, 70, 72, 75,
|
||||
70, 67, 0, 65, 67, 0, 63, 60 ];
|
||||
~kickSteps = (0 ! 16); ~snareSteps = (0 ! 16);
|
||||
~hatSteps = (0 ! 16); ~clapSteps = (0 ! 16);
|
||||
~percSteps = (0 ! 16); ~acidAmp = 0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\dubBass);
|
||||
20.wait;
|
||||
|
||||
// ------ 0:20 ERHU vibrato par-dessus pipa ------------------------
|
||||
"[E 0:20] passage erhu (violon chinois)...".postln;
|
||||
~melodyInst = \erhu;
|
||||
~melodyAttack = 0.05; ~melodyRelease = 0.4;
|
||||
~melodyCutoff = 2200;
|
||||
~reload.value;
|
||||
20.wait;
|
||||
|
||||
// ------ 0:40 KICK + HAT entrent (montee) ------------------------
|
||||
"[E 0:40] kick T4 + hat 16ths...".postln;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0];
|
||||
~kickFreq = 60; ~kickPitchAmt = 5.0; ~kickDecay = 0.28;
|
||||
~kickDrive = 3.5; ~kickClick = 0.3; ~kickAmp = 0.55; // T4 distordu
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~snareAmp = 0.5; ~snareFreq = 230; ~snareNoiseAmt = 0.7; ~snareDecay = 0.13;
|
||||
~reload.value;
|
||||
25.wait;
|
||||
|
||||
// ------ 1:05 RISER + IMPACT vers DROP 1 ------------------------
|
||||
"[E 1:05] build vers DROP...".postln;
|
||||
Synth(\riser, [\dur, 8, \startCutoff, 300, \endCutoff, 10000, \amp, 0.25]);
|
||||
8.wait;
|
||||
Synth(\impact, [\freq, 38, \decay, 2.0, \amp, 0.5]); // moins fort
|
||||
|
||||
// ------ 1:13 DROP 1 -- GROWL hard dubstep + melodie pipa ---------
|
||||
"[E 1:13] === DROP 1 GROWL DUBSTEP ===".postln;
|
||||
~melodyInst = \growl;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.3;
|
||||
~melodyCutoff = 250; ~melodyDrive = 3.0; // moins violent
|
||||
~melodyWobbleRate = 4; ~melodyWobbleDepth = 2500; ~melodyWobbleShape = 0;
|
||||
~melodySubAmt = 0.7; // sub modere
|
||||
~melodyAmp = 0.16; ~melodyBoost = 1.4;
|
||||
// Notes graves vietnamiennes (pentatonique mineure, octave -2)
|
||||
~melodyNotes = [ 36, 0, 0, 0, 36, 0, 0, 39,
|
||||
36, 0, 0, 0, 41, 0, 0, 0,
|
||||
36, 0, 0, 39, 36, 0, 0, 41,
|
||||
43, 0, 41, 0, 39, 0, 36, 0 ];
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.4;
|
||||
~reload.value;
|
||||
// 90s de drop avec wobble qui mute
|
||||
18.do { |k|
|
||||
if (0.4.coin) {
|
||||
~melodyWobbleRate = [2, 4, 4, 8].choose;
|
||||
~melodyWobbleShape = [0, 0, 1].choose;
|
||||
~melodyWobbleDepth = rrand(2000, 3500);
|
||||
~reload.value;
|
||||
(" -> wobble " ++ ~melodyWobbleRate ++ "Hz shape" ++ ~melodyWobbleShape).postln;
|
||||
};
|
||||
if (0.25.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.2,
|
||||
[24, 36, 36, 39, 41, 43, 48]);
|
||||
~reload.value;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
// 2:43
|
||||
|
||||
// ------ 2:43 BREAKDOWN -- erhu solo + gong --------------------
|
||||
"[E 2:43] breakdown erhu + gong vietnamien...".postln;
|
||||
Synth(\gong, [\freq, 70, \decay, 5, \amp, 0.5]);
|
||||
~melodyInst = \erhu;
|
||||
~melodyAttack = 0.05; ~melodyRelease = 0.5;
|
||||
~melodyCutoff = 2000; ~melodyAmp = 0.22;
|
||||
~kickSteps = (0 ! 16); ~snareSteps = (0 ! 16);
|
||||
~clapSteps = (0 ! 16); ~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0];
|
||||
~hatAmp = 0.06;
|
||||
// Melodie expressive pentatonique majeure
|
||||
~melodyNotes = [ 60, 0, 65, 0, 67, 0, 69, 0,
|
||||
72, 0, 69, 67, 0, 65, 0, 60,
|
||||
65, 0, 69, 0, 72, 0, 74, 0,
|
||||
69, 67, 0, 65, 67, 0, 60, 0 ];
|
||||
~reload.value;
|
||||
// Breakdown 30s avec mutations subtiles
|
||||
6.do { |k|
|
||||
if (0.3.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.15, ~scaleVietnamMaj);
|
||||
~reload.value;
|
||||
};
|
||||
5.wait;
|
||||
};
|
||||
// 3:13
|
||||
|
||||
// ------ 3:13 BUILD 2 -- snare roll + riser long --------------
|
||||
"[E 3:13] build 2 -- snare roll + riser...".postln;
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.4]);
|
||||
// Snare roll qui s'accelere
|
||||
16.do { |k|
|
||||
var rate = ((k / 4).floor + 2).min(8);
|
||||
if (k.mod((16 / rate).round.max(1)) == 0) {
|
||||
Synth(\snare, [\amp, 0.3 + (k * 0.015), \decay, 0.05]);
|
||||
};
|
||||
~hatAmp = 0.06 + (k * 0.005);
|
||||
~reload.value;
|
||||
1.wait;
|
||||
};
|
||||
// 3:29
|
||||
|
||||
// ------ 3:29 DROP 2 -- GROWL CHOP + melodie hard ---------------
|
||||
"[E 3:29] === DROP 2 GROWL CHOP + Vietnam melody ===".postln;
|
||||
Synth(\impact, [\freq, 32, \decay, 2.5, \amp, 0.55]);
|
||||
0.1.wait;
|
||||
~kickSteps = [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]; ~kickAmp = 0.55;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~snareAmp = 0.5;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.35;
|
||||
~melodyInst = \growl;
|
||||
~melodyCutoff = 220; ~melodyDrive = 3.5;
|
||||
~melodyWobbleRate = 8; ~melodyWobbleDepth = 3000;
|
||||
~melodyWobbleShape = 1; // CHOP
|
||||
~melodySubAmt = 0.7;
|
||||
~melodyAmp = 0.16;
|
||||
// Pattern hard syncope avec Bb (couleur asiatique)
|
||||
~melodyNotes = [ 36, 0, 39, 0, 36, 0, 41, 0,
|
||||
36, 39, 0, 41, 0, 0, 36, 0,
|
||||
36, 0, 39, 41, 0, 43, 0, 41,
|
||||
39, 0, 0, 36, 41, 0, 39, 36 ];
|
||||
~reload.value;
|
||||
// 90s avec variations rapides
|
||||
18.do { |k|
|
||||
if (0.4.coin) {
|
||||
~melodyWobbleRate = [4, 8, 8, 16].choose;
|
||||
~melodyWobbleShape = [0, 1, 1].choose;
|
||||
~melodyWobbleDepth = rrand(2200, 3800);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.3.coin) {
|
||||
// Garder l'ame vietnamienne dans les mutations
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.2, [24, 36, 39, 41, 43, 48]);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.1.coin) {
|
||||
// Snare ghost roll
|
||||
~snareFill !? { ~snareFill.(4, 0.5, 0.3, 0.5) };
|
||||
};
|
||||
if (0.05.coin) { Synth(\impact, [\freq, 40, \decay, 1, \amp, 0.5]); };
|
||||
5.wait;
|
||||
};
|
||||
// 4:59
|
||||
|
||||
// ------ 4:59 SECOND BREAKDOWN -- pipa + erhu duo ---------------
|
||||
"[E 4:59] duo pipa + erhu...".postln;
|
||||
Synth(\gong, [\freq, 60, \decay, 5, \amp, 0.45]);
|
||||
~melodyInst = \pipa;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.5;
|
||||
~melodyCutoff = 4500; ~melodyAmp = 0.22;
|
||||
~kickSteps = (0 ! 16); ~snareSteps = (0 ! 16);
|
||||
~clapSteps = (0 ! 16); ~hatSteps = (0 ! 16);
|
||||
~melodyNotes = [ 72, 70, 67, 65, 63, 60, 0, 0,
|
||||
65, 67, 70, 72, 75, 0, 0, 0,
|
||||
72, 70, 67, 65, 67, 70, 72, 0,
|
||||
75, 72, 70, 67, 65, 63, 60, 0 ];
|
||||
~reload.value;
|
||||
25.wait;
|
||||
|
||||
// ------ 5:24 DROP 3 FINAL -- combo growl + reese hard ---------
|
||||
"[E 5:24] === DROP 3 FINAL chaos ===".postln;
|
||||
Synth(\impact, [\freq, 30, \decay, 2.5, \amp, 0.6]);
|
||||
0.1.wait;
|
||||
~kickSteps = [1,0,1,0, 0,0,0,0, 1,0,0,0, 0,0,1,0]; ~kickAmp = 0.5;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,1, 0,0,0,0, 1,0,1,0]; ~snareAmp = 0.5;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1]; ~hatAmp = 0.10;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~clapAmp = 0.4;
|
||||
~melodyInst = \growl;
|
||||
~melodyCutoff = 200; ~melodyDrive = 4.0;
|
||||
~melodyWobbleRate = 8; ~melodyWobbleDepth = 3500;
|
||||
~melodyWobbleShape = 1; ~melodySubAmt = 0.8; ~melodyAmp = 0.18;
|
||||
~reload.value;
|
||||
// 70s avec rotation timbre + chaos max
|
||||
14.do { |k|
|
||||
if (0.5.coin) {
|
||||
~melodyInst = [\growl, \reeseHard, \growl].choose;
|
||||
~melodyWobbleRate = [4, 8, 16].choose;
|
||||
~melodyWobbleShape = [0, 1, 1].choose;
|
||||
~reload.value;
|
||||
(" -> " ++ ~melodyInst ++ " wobble " ++ ~melodyWobbleRate).postln;
|
||||
};
|
||||
if (0.3.coin) {
|
||||
~melodyNotes = ~mutate.(~melodyNotes, 0.25, [24, 36, 39, 41, 43, 48]);
|
||||
~reload.value;
|
||||
};
|
||||
if (0.1.coin) { ~snareFill !? { ~snareFill.(8, 0.5, 0.3, 0.55) } };
|
||||
5.wait;
|
||||
};
|
||||
// 6:34
|
||||
|
||||
// ------ 6:34 OUTRO -- gong + erhu qui s'efface ----------------
|
||||
"[E 6:34] new -- taiko + shakuhachi + ml10 vietnam epic...".postln;
|
||||
~melodyInst = \shakuhachi;
|
||||
~melodyAttack = 0.05; ~melodyRelease = 0.8; ~melodyCutoff = 3500;
|
||||
~melodyAmp = 0.20;
|
||||
~melodyNotes = (~ml10 ? [60,0,65,0,67,0,69,0, 72,0,69,67,65,0,60,0]).copy;
|
||||
~percInst = \taiko; ~tomFreq = 75; ~percAmp = 0.4;
|
||||
~percSteps = [1,0,0,0, 0,0,1,0, 1,0,0,0, 0,1,0,0];
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.25, 1200, \sin, 3500) };
|
||||
~fxPreset !? { ~fxPreset.(\space) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
35.wait;
|
||||
|
||||
"[E 7:09] new -- guzheng + tabla + tapeReverse cinematic...".postln;
|
||||
~melodyInst = \guzheng;
|
||||
~melodyAttack = 0.001; ~melodyRelease = 0.7; ~melodyCutoff = 4500;
|
||||
~melodyAmp = 0.22;
|
||||
~percInst = \tabla; ~percAmp = 0.32;
|
||||
~percSteps = [1,0,1,0, 0,1,0,1, 1,0,1,0, 0,1,0,0];
|
||||
~tapeReverse !? { ~tapeReverse.(2.5) };
|
||||
~vcfOn !? { ~vcfOn.(\formant, 800, 0.4) };
|
||||
~fxPreset !? { ~fxPreset.(\dream) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
25.wait;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
|
||||
"[E 7:34] outro gong + erhu fade...".postln;
|
||||
Synth(\gong, [\freq, 50, \decay, 8, \amp, 0.6]);
|
||||
~melodyInst = \erhu;
|
||||
~melodyAttack = 0.06; ~melodyRelease = 0.6;
|
||||
~melodyCutoff = 1800; ~melodyAmp = 0.22;
|
||||
~melodyNotes = [ 60, 0, 0, 0, 65, 0, 0, 0,
|
||||
67, 0, 0, 0, 70, 0, 0, 0,
|
||||
67, 0, 0, 0, 65, 0, 0, 0,
|
||||
63, 0, 0, 0, 60, 0, 0, 0 ];
|
||||
~reload.value;
|
||||
// 90s d'outro avec fade lent
|
||||
45.do { |k|
|
||||
var x = 1 - ((k + 1) / 45);
|
||||
~kickAmp = x * 0.55;
|
||||
~snareAmp = x * 0.5;
|
||||
~hatAmp = x * 0.10;
|
||||
~clapAmp = x * 0.4;
|
||||
~melodyAmp = x * 0.22;
|
||||
~melodyCutoff = 200 + (x * 1600);
|
||||
~reload.value;
|
||||
2.wait;
|
||||
};
|
||||
// 8:04
|
||||
Synth(\gong, [\freq, 40, \decay, 10, \amp, 0.7]);
|
||||
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[E 9:04] === fin HARD DUBSTEP VIETNAM ===".postln;
|
||||
}).play;
|
||||
"=== TRACK E : HARD DUBSTEP VIETNAM 8 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,151 @@
|
||||
// =====================================================================
|
||||
// F_trance_uplifter.scd -- 10 min, 138 BPM, trance classique
|
||||
// warmPad + arp squareLead + organLead, build/drop epique
|
||||
// PREREQUIS : engine + extra
|
||||
// =====================================================================
|
||||
(
|
||||
[~track1, ~track2, ~track3, ~track4].do { |t| t !? { t.stop } };
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[F 0:00] === TRANCE UPLIFTER 138 BPM ===".postln;
|
||||
[\acidSeq, \kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
TempoClock.default.tempo = 138 / 60;
|
||||
|
||||
"[F 0:00] intro warmPad...".postln;
|
||||
~melodyInst = \warmPad; ~melodyAttack = 0.6; ~melodyRelease = 2.0;
|
||||
~melodyCutoff = 1800; ~melodyAmp = 0.18;
|
||||
~melodyNotes = [60,0,0,0,67,0,0,0, 70,0,0,0,72,0,0,0,
|
||||
72,0,0,0,70,0,0,0, 67,0,0,0,63,0,0,0];
|
||||
~kickSteps = (0!16); ~hatSteps = (0!16); ~snareSteps = (0!16);
|
||||
~clapSteps = (0!16); ~percSteps = (0!16); ~acidAmp = 0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\tranceLayer);
|
||||
45.wait;
|
||||
|
||||
"[F 0:45] kick 4/4 + hat offbeat...".postln;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 50; ~kickPitchAmt = 2.8; ~kickDecay = 0.32; ~kickClick = 0.15;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.16;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.3;
|
||||
~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[F 1:30] arp squareLead entre...".postln;
|
||||
~melodyInst = \squareLead;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.2; ~melodyCutoff = 5000;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = [60, 67, 70, 72, 70, 67, 60, 67,
|
||||
63, 70, 72, 75, 72, 70, 63, 70,
|
||||
65, 72, 75, 77, 75, 72, 65, 72,
|
||||
63, 70, 72, 75, 72, 70, 63, 60];
|
||||
~reload.value;
|
||||
60.wait;
|
||||
|
||||
"[F 2:30] BUILD vers DROP...".postln;
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 11000, \amp, 0.3]);
|
||||
16.do { |k|
|
||||
var x = (k + 1) / 16;
|
||||
~hatAmp = 0.16 + (x * 0.08);
|
||||
~melodyCutoff = 5000 + (x * 3000);
|
||||
~reload.value;
|
||||
1.wait;
|
||||
};
|
||||
Synth(\impact, [\freq, 45, \decay, 2.5, \amp, 0.6]);
|
||||
|
||||
"[F 2:46] === DROP organLead trance ===".postln;
|
||||
~melodyInst = \organLead;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.15; ~melodyCutoff = 4500;
|
||||
~melodyAmp = 0.20;
|
||||
~kickAmp = 0.55;
|
||||
~reload.value;
|
||||
90.wait;
|
||||
|
||||
"[F 4:16] verse hardLead...".postln;
|
||||
~melodyInst = \hardLead;
|
||||
~melodyAttack = 0.002; ~melodyRelease = 0.25; ~melodyCutoff = 5500;
|
||||
~reload.value;
|
||||
60.wait;
|
||||
|
||||
"[F 5:16] breakdown choir + strings...".postln;
|
||||
~kickSteps = (0!16); ~hatAmp = 0.06; ~clapSteps = (0!16);
|
||||
~melodyInst = \choir;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 2500;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = [60, 0, 0, 0, 63, 0, 0, 0, 67, 0, 0, 0, 70, 0, 0, 0,
|
||||
72, 0, 0, 0, 70, 0, 0, 0, 67, 0, 0, 0, 63, 0, 0, 0];
|
||||
~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[F 6:01] BUILD 2 + impact final...".postln;
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 500, \endCutoff, 12000, \amp, 0.4]);
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~hatSteps = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
|
||||
16.do { |k| ~hatAmp = 0.06 + ((k + 1) / 16 * 0.10); ~reload.value; 1.wait };
|
||||
Synth(\impact, [\freq, 38, \decay, 3, \amp, 0.7]);
|
||||
Synth(\crash, [\decay, 4, \amp, 0.4]);
|
||||
|
||||
"[F 6:17] === DROP FINAL squareLead arp ===".postln;
|
||||
~melodyInst = \squareLead;
|
||||
~melodyAttack = 0.003; ~melodyRelease = 0.2; ~melodyCutoff = 6500;
|
||||
~melodyAmp = 0.20;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~reload.value;
|
||||
150.wait;
|
||||
"[F 8:47] new -- supersaw + mxl1 trance epic + lfo cutoff...".postln;
|
||||
~melodyInst = \supersaw;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyCutoff = 4500;
|
||||
~melodyAmp = 0.20;
|
||||
~melodyNotes = (~mxl1 ? [60,67,72,75, 70,67,63,60, 65,72,77,79, 75,72,70,67]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.5, 2000, \sin, 5000) };
|
||||
~vcfOn !? { ~vcfOn.(\moog, 2200, 0.4) };
|
||||
~fxPreset !? { ~fxPreset.(\trance) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
50.wait;
|
||||
|
||||
"[F 9:37] new -- vocalPad breakdown + buildup + drop final...".postln;
|
||||
~melodyInst = \vocalPad;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.8; ~melodyCutoff = 2500;
|
||||
~melodyAmp = 0.20;
|
||||
~breakdown !? { ~breakdown.(6) };
|
||||
~fxPreset !? { ~fxPreset.(\space) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
20.wait;
|
||||
~buildup !? { ~buildup.(6) };
|
||||
~drop !? { ~drop.() };
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
20.wait;
|
||||
|
||||
|
||||
"[F 10:17] outro warmPad fade...".postln;
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.6; ~melodyRelease = 2.5; ~melodyCutoff = 1500;
|
||||
~reload.value;
|
||||
60.do { |k|
|
||||
var x = 1 - ((k + 1) / 60);
|
||||
~kickAmp = x * 0.55; ~hatAmp = x * 0.18; ~clapAmp = x * 0.3;
|
||||
~melodyAmp = x * 0.18; ~melodyCutoff = 200 + (x * 1300);
|
||||
~reload.value; 1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[F 11:17] === fin TRANCE UPLIFTER ===".postln;
|
||||
}).play;
|
||||
"=== TRACK F : TRANCE UPLIFTER 10 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,122 @@
|
||||
// =====================================================================
|
||||
// G_detroit_soulful.scd -- 8 min, 124 BPM, Detroit house
|
||||
// organLead stabs + warmPad fond + kick 4/4 + clap backbeat
|
||||
// PREREQUIS : engine + extra
|
||||
// =====================================================================
|
||||
(
|
||||
[~track1, ~track2, ~track3, ~track4].do { |t| t !? { t.stop } };
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[G 0:00] === DETROIT SOULFUL 124 BPM ===".postln;
|
||||
[\acidSeq, \kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
TempoClock.default.tempo = 124 / 60;
|
||||
|
||||
"[G 0:00] intro warmPad accords...".postln;
|
||||
~melodyInst = \warmPad; ~melodyAttack = 0.5; ~melodyRelease = 1.8;
|
||||
~melodyCutoff = 1800; ~melodyAmp = 0.18;
|
||||
~melodyNotes = [60,0,0,0, 63,0,0,0, 67,0,0,0, 70,0,0,0,
|
||||
72,0,0,0, 70,0,0,0, 67,0,0,0, 63,0,0,0];
|
||||
~kickSteps=(0!16); ~hatSteps=(0!16); ~snareSteps=(0!16);
|
||||
~clapSteps=(0!16); ~percSteps=(0!16); ~acidAmp=0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\chord);
|
||||
30.wait;
|
||||
|
||||
"[G 0:30] kick 4/4 + clap...".postln;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 50; ~kickPitchAmt = 2.8; ~kickDecay = 0.35; ~kickClick = 0.12;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.15;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.35;
|
||||
~reload.value;
|
||||
30.wait;
|
||||
|
||||
"[G 1:00] organ stabs Detroit...".postln;
|
||||
~melodyInst = \organLead;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.15; ~melodyCutoff = 4500;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = [63,0,0,0, 67,0,70,0, 65,0,0,0, 70,0,72,0,
|
||||
63,0,0,0, 67,0,70,0, 60,0,67,0, 63,0,0,0];
|
||||
~reload.value;
|
||||
60.wait;
|
||||
|
||||
"[G 2:00] verse hardLead phrase...".postln;
|
||||
~melodyInst = \hardLead;
|
||||
~melodyAttack = 0.003; ~melodyRelease = 0.25; ~melodyCutoff = 5000;
|
||||
~melodyNotes = [60,67,72,75, 70,67,63,60, 65,70,75,77, 72,70,67,63,
|
||||
63,70,75,79, 75,72,70,67, 60,65,70,75, 67,63,60,0];
|
||||
~reload.value;
|
||||
60.wait;
|
||||
|
||||
"[G 3:00] breakdown strings + choir...".postln;
|
||||
~kickSteps=(0!16); ~hatAmp=0.06; ~clapSteps=(0!16);
|
||||
~melodyInst = \strings;
|
||||
~melodyAttack = 0.3; ~melodyRelease = 1.2; ~melodyCutoff = 3500;
|
||||
~melodyAmp = 0.20;
|
||||
~melodyNotes = [60,0,0,0, 67,0,0,0, 70,0,0,0, 72,0,0,0,
|
||||
70,0,0,0, 67,0,0,0, 63,0,0,0, 60,0,0,0];
|
||||
~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[G 3:45] DROP retour + organ...".postln;
|
||||
Synth(\impact, [\freq, 45, \decay, 2, \amp, 0.5]);
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.16;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~melodyInst = \organLead;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.15; ~melodyCutoff = 5500;
|
||||
~reload.value;
|
||||
120.wait;
|
||||
"[G 5:45] new -- rhodes detroit + ml5 + dub fx...".postln;
|
||||
~melodyInst = \rhodes;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.6; ~melodyCutoff = 3500;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = (~ml5 ? [60,0,67,0,70,0,67,65, 63,0,60,0,0,67,70,72]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.25, 1500, \sin, 3500) };
|
||||
~vcfOn !? { ~vcfOn.(\moog, 2200, 0.4) };
|
||||
~fxPreset !? { ~fxPreset.(\dub) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
40.wait;
|
||||
|
||||
"[G 6:25] new -- vocalPad detroit soulful + glitch...".postln;
|
||||
~melodyInst = \vocalPad;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.8; ~melodyCutoff = 2500;
|
||||
~melodyAmp = 0.20;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
~glitch !? { ~glitch.(2) };
|
||||
~fxPreset !? { ~fxPreset.(\dream) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
25.wait;
|
||||
|
||||
|
||||
"[G 6:50] outro warmPad fade...".postln;
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.5; ~melodyRelease = 2.0; ~melodyCutoff = 1500;
|
||||
~reload.value;
|
||||
60.do { |k|
|
||||
var x = 1 - ((k + 1) / 60);
|
||||
~kickAmp = x * 0.5; ~hatAmp = x * 0.16; ~clapAmp = x * 0.35;
|
||||
~melodyAmp = x * 0.18;
|
||||
~reload.value; 1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[G 7:50] === fin DETROIT SOULFUL ===".postln;
|
||||
}).play;
|
||||
"=== TRACK G : DETROIT SOULFUL 8 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,143 @@
|
||||
// =====================================================================
|
||||
// H_acid_trance.scd -- 8 min, 145 BPM, acid trance epique
|
||||
// Acid 303 + warmPad + arp squareLead + build classique trance
|
||||
// PREREQUIS : engine + extra
|
||||
// =====================================================================
|
||||
(
|
||||
[~track1, ~track2, ~track3, ~track4].do { |t| t !? { t.stop } };
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[H 0:00] === ACID TRANCE 145 BPM ===".postln;
|
||||
[\acidSeq, \kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
TempoClock.default.tempo = 145 / 60;
|
||||
|
||||
"[H 0:00] intro pad...".postln;
|
||||
~melodyInst = \warmPad; ~melodyAttack = 0.6; ~melodyRelease = 2.0;
|
||||
~melodyCutoff = 1800; ~melodyAmp = 0.16;
|
||||
~melodyNotes = [60,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0,
|
||||
63,0,0,0,0,0,0,0, 70,0,0,0,0,0,0,0];
|
||||
~kickSteps=(0!16); ~hatSteps=(0!16); ~snareSteps=(0!16);
|
||||
~clapSteps=(0!16); ~percSteps=(0!16);
|
||||
~acidNotes = [36,36,48,36,39,36,43,39, 36,41,36,39,43,36,36,41];
|
||||
~acidAccents = [1,0,0,0,1,0,1,0, 0,1,0,0,1,0,0,1];
|
||||
~acidSlides = [0,0,1,0,0,0,0,1, 0,0,0,1,0,0,0,0];
|
||||
~acidCutoff = 600; ~acidRq = 0.18; ~acidDrive = 2.5; ~acidAmp = 0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\tranceLayer);
|
||||
30.wait;
|
||||
|
||||
"[H 0:30] kick 4/4 trance + acid entre...".postln;
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0]; ~kickAmp = 0.55;
|
||||
~kickFreq = 60; ~kickPitchAmt = 3.5; ~kickDecay = 0.25; ~kickClick = 0.2;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.15;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]; ~clapAmp = 0.3;
|
||||
~acidAmp = 0.28;
|
||||
~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[H 1:15] BUILD long vers DROP acid...".postln;
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 12000, \amp, 0.35]);
|
||||
16.do { |k|
|
||||
var x = (k + 1) / 16;
|
||||
~acidCutoff = 600 + (x * 1500); ~acidRq = 0.18 - (x * 0.10);
|
||||
~hatAmp = 0.15 + (x * 0.06);
|
||||
~reload.value; 1.wait;
|
||||
};
|
||||
Synth(\impact, [\freq, 45, \decay, 2.5, \amp, 0.6]);
|
||||
|
||||
"[H 1:31] === DROP ACID + lead arp ===".postln;
|
||||
~melodyInst = \squareLead;
|
||||
~melodyAttack = 0.003; ~melodyRelease = 0.15; ~melodyCutoff = 6000;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = [60, 67, 72, 75, 70, 67, 60, 67,
|
||||
63, 70, 75, 77, 72, 70, 63, 67,
|
||||
65, 72, 75, 79, 75, 72, 65, 67,
|
||||
60, 67, 72, 75, 70, 67, 63, 60];
|
||||
~reload.value;
|
||||
90.wait;
|
||||
|
||||
"[H 3:01] breakdown choir + acid mute...".postln;
|
||||
~kickSteps=(0!16); ~hatAmp=0.05; ~clapSteps=(0!16);
|
||||
~acidAmp = 0;
|
||||
~melodyInst = \choir;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 2500;
|
||||
~melodyAmp = 0.20;
|
||||
~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[H 3:46] BUILD 2 + DROP FINAL...".postln;
|
||||
Synth(\riser, [\dur, 16, \startCutoff, 400, \endCutoff, 13000, \amp, 0.4]);
|
||||
~kickSteps = [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0];
|
||||
16.do { |k|
|
||||
var x = (k + 1) / 16;
|
||||
~hatAmp = 0.05 + (x * 0.13);
|
||||
~reload.value; 1.wait;
|
||||
};
|
||||
Synth(\impact, [\freq, 38, \decay, 3, \amp, 0.7]);
|
||||
Synth(\crash, [\decay, 4, \amp, 0.4]);
|
||||
|
||||
"[H 4:02] === DROP FINAL hardLead + acid push ===".postln;
|
||||
~melodyInst = \hardLead;
|
||||
~melodyAttack = 0.002; ~melodyRelease = 0.25; ~melodyCutoff = 6000;
|
||||
~melodyAmp = 0.18;
|
||||
~hatSteps = [0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0]; ~hatAmp = 0.18;
|
||||
~clapSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0];
|
||||
~acidAmp = 0.32; ~acidCutoff = 1500; ~acidRq = 0.08; ~acidDrive = 3.5;
|
||||
~reload.value;
|
||||
150.wait;
|
||||
"[H 6:32] new -- supersaw acid + mxl1 + vcf moog + lfo cutoff...".postln;
|
||||
~melodyInst = \supersaw;
|
||||
~melodyAttack = 0.003; ~melodyRelease = 0.3; ~melodyCutoff = 5000;
|
||||
~melodyAmp = 0.20;
|
||||
~melodyNotes = (~mxl1 ? [60,67,72,75, 70,67,63,67, 65,72,77,79, 75,72,65,67]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.4, 2500, \sin, 5500) };
|
||||
~vcfOn !? { ~vcfOn.(\moog, 2500, 0.4) };
|
||||
~fxPreset !? { ~fxPreset.(\trance) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
45.wait;
|
||||
|
||||
"[H 7:17] new -- hooverbass + drop + bitCrush hardfloor...".postln;
|
||||
~melodyInst = \hooverbass;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.25; ~melodyCutoff = 1500;
|
||||
~melodyAmp = 0.20;
|
||||
~drop !? { ~drop.() };
|
||||
~bitCrushNow !? { ~bitCrushNow.(8, 8000, 2) };
|
||||
~fxPreset !? { ~fxPreset.(\industrial) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
25.wait;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
|
||||
|
||||
"[H 7:42] outro fade...".postln;
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.6; ~melodyRelease = 2.5;
|
||||
~reload.value;
|
||||
60.do { |k|
|
||||
var x = 1 - ((k + 1) / 60);
|
||||
~kickAmp = x * 0.55; ~hatAmp = x * 0.18; ~clapAmp = x * 0.3;
|
||||
~acidAmp = x * 0.32; ~melodyAmp = x * 0.20;
|
||||
~acidCutoff = 200 + (x * 1300);
|
||||
~reload.value; 1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[H 8:42] === fin ACID TRANCE ===".postln;
|
||||
}).play;
|
||||
"=== TRACK H : ACID TRANCE 8 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
@@ -0,0 +1,130 @@
|
||||
// =====================================================================
|
||||
// I_liquid_dnb.scd -- 7 min, 174 BPM, liquid drum'n'bass
|
||||
// amen-like + warmPad + smooth lead, atmospheric
|
||||
// PREREQUIS : engine + extra
|
||||
// =====================================================================
|
||||
(
|
||||
[~track1, ~track2, ~track3, ~track4].do { |t| t !? { t.stop } };
|
||||
~track !? { ~track.stop };
|
||||
~track = Routine({
|
||||
"[I 0:00] === LIQUID DNB 174 BPM ===".postln;
|
||||
[\acidSeq, \kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
TempoClock.default.tempo = 174 / 60;
|
||||
|
||||
"[I 0:00] intro warmPad...".postln;
|
||||
~melodyInst = \warmPad; ~melodyAttack = 0.5; ~melodyRelease = 1.8;
|
||||
~melodyCutoff = 2000; ~melodyAmp = 0.18;
|
||||
~melodyNotes = [60,0,0,0,0,0,0,0, 67,0,0,0,0,0,0,0,
|
||||
63,0,0,0,0,0,0,0, 70,0,0,0,0,0,0,0];
|
||||
~kickSteps=(0!16); ~hatSteps=(0!16); ~snareSteps=(0!16);
|
||||
~clapSteps=(0!16); ~percSteps=(0!16); ~acidAmp=0;
|
||||
~reload.value;
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).play };
|
||||
~enableHarmony.(\bassline);
|
||||
20.wait;
|
||||
|
||||
"[I 0:20] amen break entre...".postln;
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0]; ~kickAmp = 0.5;
|
||||
~kickFreq = 55; ~kickPitchAmt = 4.0; ~kickDecay = 0.18; ~kickClick = 0.3;
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1]; ~snareAmp = 0.5;
|
||||
~snareFreq = 240; ~snareNoiseAmt = 0.7; ~snareDecay = 0.10;
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1]; ~hatAmp = 0.12;
|
||||
~reload.value;
|
||||
40.wait;
|
||||
|
||||
"[I 1:00] smooth lead par-dessus...".postln;
|
||||
~melodyInst = \fmLead;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyCutoff = 5000;
|
||||
~melodyAmp = 0.16;
|
||||
~melodyNotes = [60,0,67,0,70,0,67,65, 63,0,60,0,0,67,70,72,
|
||||
75,0,72,70,67,0,0,65, 63,60,0,67,70,0,72,0];
|
||||
~reload.value;
|
||||
80.wait;
|
||||
|
||||
"[I 2:20] reese sub bass entre...".postln;
|
||||
~acidAmp = 0;
|
||||
~kickAmp = 0.55;
|
||||
// sub bass via melody 2eme couche par modification
|
||||
~melodyInst = \subBoom;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.6;
|
||||
~melodyAmp = 0.30;
|
||||
~melodyNotes = [36,0,0,0, 36,0,0,0, 39,0,0,0, 41,0,0,0,
|
||||
36,0,0,0, 36,0,0,0, 41,0,0,0, 39,0,0,0];
|
||||
~reload.value;
|
||||
60.wait;
|
||||
|
||||
"[I 3:20] breakdown smooth choir...".postln;
|
||||
~kickSteps=(0!16); ~snareSteps=(0!16); ~hatAmp=0.06;
|
||||
~melodyInst = \choir;
|
||||
~melodyAttack = 0.4; ~melodyRelease = 1.5; ~melodyCutoff = 2800;
|
||||
~melodyAmp = 0.20;
|
||||
~melodyNotes = [60,0,0,0,67,0,0,0, 70,0,0,0,72,0,0,0,
|
||||
70,0,0,0,67,0,0,0, 63,0,0,0,60,0,0,0];
|
||||
~reload.value;
|
||||
40.wait;
|
||||
|
||||
"[I 4:00] DROP retour amen + lead...".postln;
|
||||
Synth(\impact, [\freq, 45, \decay, 2, \amp, 0.5]);
|
||||
~kickSteps = [1,0,0,0, 0,0,1,0, 0,0,1,0, 1,0,0,0];
|
||||
~snareSteps = [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1];
|
||||
~hatSteps = [1,1,1,1, 0,1,1,1, 1,1,1,1, 0,1,1,1]; ~hatAmp = 0.13;
|
||||
~melodyInst = \fmLead;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyCutoff = 5500;
|
||||
~melodyAmp = 0.18;
|
||||
~melodyNotes = [60,67,72,75, 70,67,63,60, 65,70,75,77, 72,70,67,63,
|
||||
63,70,75,79, 75,72,70,67, 60,65,70,75, 67,63,60,0];
|
||||
~reload.value;
|
||||
120.wait;
|
||||
"[I 6:00] new -- reeseDnB + ml1 + vcf ladder + lfo wobble...".postln;
|
||||
~melodyInst = \reeseDnB;
|
||||
~melodyAttack = 0.005; ~melodyRelease = 0.4; ~melodyCutoff = 1200;
|
||||
~melodyDrive = 2.2; ~melodyAmp = 0.20;
|
||||
~melodyNotes = (~ml1 ? [36,0,0,0,36,0,0,0, 39,0,0,0,41,0,0,0]).copy;
|
||||
~lfoTo !? { ~lfoTo.(\melodyCutoff, 0.4, 1200, \sin, 2000) };
|
||||
~vcfOn !? { ~vcfOn.(\ladder, 1500, 0.5) };
|
||||
~fxPreset !? { ~fxPreset.(\dub) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
40.wait;
|
||||
|
||||
"[I 6:40] new -- rhodes liquid + vocalPad + reverbTail...".postln;
|
||||
~melodyInst = \rhodes;
|
||||
~melodyAttack = 0.01; ~melodyRelease = 0.7; ~melodyCutoff = 3500;
|
||||
~melodyAmp = 0.18;
|
||||
~vcfOff !? { ~vcfOff.() };
|
||||
~lfoStopVar !? { ~lfoStopVar.(\melodyCutoff) };
|
||||
~reverbTail !? { ~reverbTail.(4) };
|
||||
~fxPreset !? { ~fxPreset.(\dream) };
|
||||
TempoClock.default.tempo = ~bpm/60; ~reload.value;
|
||||
25.wait;
|
||||
|
||||
|
||||
"[I 7:05] outro pad fade...".postln;
|
||||
~melodyInst = \warmPad;
|
||||
~melodyAttack = 0.5; ~melodyRelease = 2.0;
|
||||
~reload.value;
|
||||
60.do { |k|
|
||||
var x = 1 - ((k + 1) / 60);
|
||||
~kickAmp = x * 0.5; ~snareAmp = x * 0.5; ~hatAmp = x * 0.13;
|
||||
~melodyAmp = x * 0.20;
|
||||
~reload.value; 1.wait;
|
||||
};
|
||||
[\kickSeq, \hatSeq, \snareSeq, \clapSeq, \percSeq, \acidSeq, \melodySeq, \harmonySeq]
|
||||
.do { |k| Pdef(k).stop };
|
||||
"[I 8:05] === fin LIQUID DNB ===".postln;
|
||||
}).play;
|
||||
"=== TRACK I : LIQUID DNB 7 min lancee ===".postln;
|
||||
)
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// TWEAKS LIVE -- voir palette/tweaks_template.scd (charge dans 00_load)
|
||||
// Ouvrir tweaks_template.scd et Cmd+Entree sur une ligne.
|
||||
// =====================================================================
|
||||
|
||||
// =====================================================================
|
||||
// SECTIONS / JUMP TO -- voir jump.scd
|
||||
// Ouvrir jump.scd, evaluer SETUP JUMP, puis le bloc TRACK X correspondant,
|
||||
// puis Cmd+Entree sur la ligne ~jumpTo.('X', 'slug').
|
||||
// =====================================================================
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user