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:
electron-rare
2026-05-04 20:32:58 +02:00
commit a10dc7cb16
114 changed files with 23969 additions and 0 deletions
+108
View File
@@ -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.).
+98
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
)
+41
View File
@@ -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
```
+79
View File
@@ -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)
+55
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+119
View File
@@ -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;
)
+279
View File
@@ -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
View File
@@ -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;
};
)
+60
View File
@@ -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);
};
)
+93
View File
@@ -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.(); )
+76
View File
@@ -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;
)
+102
View File
@@ -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;
)
+117
View File
@@ -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;
)
+132
View File
@@ -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;
)
+128
View File
@@ -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;
)
+118
View File
@@ -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;
)
+96
View File
@@ -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;
)
+88
View File
@@ -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;
)
+95
View File
@@ -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;
)
+87
View File
@@ -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)
+126
View File
@@ -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;
)
+128
View File
@@ -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;
)
+114
View File
@@ -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;
)
+274
View File
@@ -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;
)
+63
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+826
View File
@@ -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
View File
@@ -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; )
//
// =====================================================================
+222
View File
@@ -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
View File
@@ -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); )
+538
View File
@@ -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
View File
@@ -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
View File
@@ -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; )
+43
View File
@@ -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`
+533
View File
@@ -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;
)
+26
View File
@@ -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; )
+200
View File
@@ -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;)
+70
View File
@@ -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;
)
+16
View File
@@ -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;
)
+104
View File
@@ -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;
)
+102
View File
@@ -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;
)
+119
View File
@@ -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;
)
+112
View File
@@ -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;
)
+32
View File
@@ -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;
)
+219
View File
@@ -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;
)
+91
View File
@@ -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;
)
+322
View File
@@ -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;
)
+144
View File
@@ -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;
)
+268
View File
@@ -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;
)
+37
View File
@@ -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
+223
View File
@@ -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; )
+579
View File
@@ -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;
)
+194
View File
@@ -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; )
+578
View File
@@ -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.
+109
View File
@@ -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;
)
+123
View File
@@ -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;
)
+207
View File
@@ -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]);)
+235
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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); )
+779
View File
@@ -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.(); )
+47
View File
@@ -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)
+157
View File
@@ -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;
)
+317
View File
@@ -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;
)
+267
View File
@@ -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;
)
+62
View File
@@ -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)
+164
View File
@@ -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;
+108
View File
@@ -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 });
+72
View File
@@ -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 });
+112
View File
@@ -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 });
+179
View File
@@ -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 });
+128
View File
@@ -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 });
+107
View File
@@ -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 });
+106
View File
@@ -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 });
+38
View File
@@ -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;
+103
View File
@@ -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;
+89
View File
@@ -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
+148
View File
@@ -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').
// =====================================================================
+154
View File
@@ -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').
// =====================================================================
+49
View File
@@ -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)
+188
View File
@@ -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').
// =====================================================================
+207
View File
@@ -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').
// =====================================================================
+308
View File
@@ -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').
// =====================================================================
+151
View File
@@ -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').
// =====================================================================
+122
View File
@@ -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').
// =====================================================================
+143
View File
@@ -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').
// =====================================================================
+130
View File
@@ -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