diff --git a/sound_algo/data_only/matrix.scd b/sound_algo/data_only/matrix.scd index d6e4dea..20302d2 100644 --- a/sound_algo/data_only/matrix.scd +++ b/sound_algo/data_only/matrix.scd @@ -24,6 +24,12 @@ ~matBeatsPerBar = ~matBeatsPerBar ? 4; ~matLastColor = ~matLastColor ? Array.fill(~matVoices.size, -1); +// -- Persistence env init (nil-guarded) -- +~matDir = ~matDir ? "~/.config/av-live/matrices".standardizePath; +~matPresetDir = ~matPresetDir ? (PathName(thisProcess.nowExecutingPath).pathOnly ++ "matrix_presets"); +~matSavedNames = ~matSavedNames ? Set.new; +File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); + // -- ~matBaseFor : capture base Pdef source once (lazy, per voice name symbol) -- // Returns nil when the Pdef is missing (safe for partial environments). ~matBaseFor = { |name| @@ -160,6 +166,112 @@ ~matPush.() }; +// -- ~matSafeName : sanitize a name to a safe filename (alphanumeric, -, _, space→_) -- +~matSafeName = { |name| + var s = name.asString.select({ |c| c.isAlphaNum or: { "-_ ".includes(c) } }).replace(" ", "_"); + (s.size > 0).if({ s }, { "untitled" }) +}; + +// -- ~matGridValid : confirm a grid is 16 x matBars with integer cells 0..6 -- +~matGridValid = { |g| + g.isArray and: { + g.size == ~matVoices.size and: { + g.every({ |row| + row.isArray and: { + row.size == ~matBars and: { + row.every({ |v| v.isInteger and: { v >= 0 and: { v <= 6 } } }) + } + } + }) + } + } +}; + +// -- ~matNames : list base names of .matrix files found in a directory -- +// User dir: served from in-memory ~matSavedNames (populated by ~matSave) — +// avoids filesystem-scan quirks that can fail headless in some SC contexts. +// Other dirs (e.g. shipped presets): scan via ls+tmpfile (systemCmd is +// synchronous and works headless; pathMatch/Pipe.getLine are unreliable). +~matNames = { |dir| + (dir == ~matDir).if({ + ~matSavedNames.asArray + }, { + var ext = ".matrix"; + var result = []; + File.exists(dir).if({ + var tmp = "/tmp/_av_live_matnames_.txt"; + ("ls -1 '" ++ dir ++ "' > '" ++ tmp ++ "' 2>/dev/null").systemCmd; + File.exists(tmp).if({ + var content = File.use(tmp, "r", { |f| f.readAllString }); + ("rm -f '" ++ tmp ++ "'").systemCmd; + content.split($\n).do({ |fn| + (fn.size > ext.size and: { + fn.copyRange(fn.size - ext.size, fn.size - 1) == ext + }).if({ + result = result.add(fn.copyRange(0, fn.size - ext.size - 1).asSymbol) + }) + }) + }) + }); + result + }) +}; + +// -- ~matGridPush : send full 512-int grid row-major to surfaces -- +// index = vi * 32 + bar (voice-major, flatten concatenates rows in order) +~matGridPush = { + ~toscSend !? { ~toscSend.valueArray(["/matrix/grid"] ++ ~lp[\matrix].flatten) } +}; + +// -- ~matListPush : send all available preset + user-save names to surfaces -- +~matListPush = { + try { + var names = (~matNames.(~matPresetDir) ++ ~matNames.(~matDir)).as(Set).asArray.sort; + ~toscSend !? { ~toscSend.valueArray(["/matrix/list"] ++ names) } + } { |e| + ("[matrix] listPush err: " ++ e.class.name).postln + } +}; + +// -- ~matSave : persist current grid to ~/.config/av-live/matrices/.matrix -- +~matSave = { |name| + var safe = ~matSafeName.(name); + var path = ~matDir +/+ (safe ++ ".matrix"); + File.use(path, "w", { |f| f.write(~lp[\matrix].asCompileString) }); + ~matSavedNames.add(safe.asSymbol); + ("[matrix] saved " ++ path).postln; + ~matListPush.(); +}; + +// -- ~matLoadFile : load and validate a grid from an absolute path -- +~matLoadFile = { |path| + var g; + File.exists(path).if({ + g = File.use(path, "r", { |f| f.readAllString }).interpret; + ~matGridValid.(g).if({ + ~lp[\matrix] = g; + ~lp[\matPlaying].if({ ~matApplyBar.(~lp[\matBar]) }); + ~matGridPush.(); + ("[matrix] loaded " ++ path).postln; + true + }, { + ("[matrix] invalid grid in " ++ path).warn; + false + }) + }, { + ("[matrix] not found " ++ path).warn; + false + }) +}; + +// -- ~matLoad : load by name; user save wins over shipped preset -- +~matLoad = { |name| + var safe = ~matSafeName.(name); + var up = ~matDir +/+ (safe ++ ".matrix"); + var pp = ~matPresetDir +/+ (safe ++ ".matrix"); + File.exists(up).if({ ~matLoadFile.(up) }, { ~matLoadFile.(pp) }) +}; + // -- OSCdefs (unique \mat_* keys; register sender for TouchOSC feedback) -- OSCdef(\mat_cell, { |msg, time, addr| ~toscTouch !? { ~toscTouch.(addr) }; @@ -181,5 +293,20 @@ OSCdef(\mat_clear, { |msg, time, addr| ~matClear.() }, '/matrix/clear'); +OSCdef(\mat_save, { |msg, time, addr| + ~toscTouch !? { ~toscTouch.(addr) }; + ~matSave.(msg[1].asString) +}, '/matrix/save'); + +OSCdef(\mat_load, { |msg, time, addr| + ~toscTouch !? { ~toscTouch.(addr) }; + ~matLoad.(msg[1].asString) +}, '/matrix/load'); + +OSCdef(\mat_list, { |msg, time, addr| + ~toscTouch !? { ~toscTouch.(addr) }; + ~matListPush.() +}, '/matrix/list'); + "[matrix] ready".postln; ) diff --git a/sound_algo/data_only/matrix_presets/.gitkeep b/sound_algo/data_only/matrix_presets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sound_algo/data_only/matrix_presets/acid_line.matrix b/sound_algo/data_only/matrix_presets/acid_line.matrix new file mode 100644 index 0000000..ea03ab2 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/acid_line.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/acid_storm.matrix b/sound_algo/data_only/matrix_presets/acid_storm.matrix new file mode 100644 index 0000000..79fd8c8 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/acid_storm.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6] +] diff --git a/sound_algo/data_only/matrix_presets/detroit.matrix b/sound_algo/data_only/matrix_presets/detroit.matrix new file mode 100644 index 0000000..1702747 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/detroit.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/dub_chords.matrix b/sound_algo/data_only/matrix_presets/dub_chords.matrix new file mode 100644 index 0000000..f7f04f8 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/dub_chords.matrix @@ -0,0 +1,18 @@ +[ + [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/dub_space.matrix b/sound_algo/data_only/matrix_presets/dub_space.matrix new file mode 100644 index 0000000..c68afa0 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/dub_space.matrix @@ -0,0 +1,18 @@ +[ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/generate_presets.py b/sound_algo/data_only/matrix_presets/generate_presets.py new file mode 100644 index 0000000..04de3cf --- /dev/null +++ b/sound_algo/data_only/matrix_presets/generate_presets.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +"""Generate matrix preset .matrix files for the AV-Live matrix arranger. + +Each preset is a 16-voice x 32-bar grid of colors 0-6, written as an SC- +interpretable nested-array literal (read by ~matLoadFile in matrix.scd). + +These are NEW hand-authored arrangements *inspired by* the character of the 14 +data_only concert morceaux (the morceaux themselves use a different instrument +set and have no bar structure, so they can't be transcribed -- see the matrix +analysis). They are editable starting points: load one, tweak, save your own. + +Voice row order MUST match ~matVoices in matrix.scd: + kick hats clap perc sub acid arp lead stab pad ride rim tom reese bells sweep +Colors: 0 off | 1 base | 2 double-time(denser) | 3 oct+ | 4 half-time(sparse) + 5 oct- | 6 accent. (3/5 are ~base until launchpad reads \\octave.) +Run: python3 generate_presets.py (writes *.matrix next to this script) +""" +import os + +VOICES = ["kick", "hats", "clap", "perc", "sub", "acid", "arp", "lead", + "stab", "pad", "ride", "rim", "tom", "reese", "bells", "sweep"] +VI = {n: i for i, n in enumerate(VOICES)} +BARS = 32 +HERE = os.path.dirname(os.path.abspath(__file__)) + + +def grid(): + return [[0] * BARS for _ in range(len(VOICES))] + + +def put(g, voice, a, b, color): + """Fill voice rows bars a..b inclusive with color (clamped to grid).""" + for bar in range(max(0, a), min(BARS - 1, b) + 1): + g[VI[voice]][bar] = color + + +def build(segments): + g = grid() + for (voice, a, b, color) in segments: + put(g, voice, a, b, color) + return g + + +# --- 14 arrangements (intro / build / main / breakdown / drop shape) ---------- +# Segment = (voice, startBar, endBar_inclusive, color) + +PRESETS = { + # 01 sparse hypnotic: half-time kick + sustained sub, minimal + "hypno_drift": [ + ("kick", 0, 31, 4), ("sub", 0, 31, 1), + ("perc", 16, 31, 4), ("pad", 8, 31, 1), + ], + # 02 driving roll: quarter kick, 16th stab(perc), shaker hats + "hypno_roll": [ + ("kick", 0, 31, 1), ("perc", 4, 31, 2), ("hats", 8, 31, 2), + ("sub", 8, 31, 1), ("stab", 16, 23, 1), ("perc", 24, 27, 4), + ], + # 03 acid line: kick + 16th acid + sub + "acid_line": [ + ("kick", 0, 31, 1), ("sub", 0, 31, 1), ("acid", 4, 23, 2), + ("hats", 8, 31, 2), ("acid", 24, 27, 4), ("acid", 28, 31, 2), + ], + # 04 acid storm: denser acid, sweep accents on drops + "acid_storm": [ + ("kick", 0, 31, 1), ("sub", 0, 31, 1), ("acid", 0, 31, 2), + ("hats", 8, 31, 2), ("clap", 16, 31, 1), + ("sweep", 15, 15, 6), ("sweep", 31, 31, 6), ("acid", 24, 27, 4), + ], + # 05 hard pump: kick + perc 8th + sub rumble + "hard_pump": [ + ("kick", 0, 31, 1), ("sub", 0, 31, 2), ("perc", 4, 31, 2), + ("hats", 12, 31, 2), ("clap", 16, 31, 1), ("perc", 24, 27, 4), + ], + # 06 hard rave: break kick, stab hoover, sweep crash + "hard_rave": [ + ("kick", 0, 31, 1), ("clap", 4, 31, 1), ("stab", 8, 23, 1), + ("hats", 8, 31, 2), ("sweep", 15, 15, 6), ("sweep", 23, 23, 6), + ("stab", 28, 31, 6), + ], + # 07 dub chords: very sparse, half kick + sub + pad chord stabs + "dub_chords": [ + ("kick", 0, 31, 4), ("sub", 0, 31, 1), ("pad", 0, 31, 1), + ("stab", 8, 31, 4), ("perc", 16, 31, 4), + ], + # 08 dub space: outro -- sub + occasional perc clicks + "dub_space": [ + ("sub", 0, 31, 1), ("perc", 0, 31, 4), ("pad", 8, 31, 1), + ("kick", 16, 31, 4), + ], + # 09 trance pluck: kick + sub + arp 16ths + lead + "trance_pluck": [ + ("kick", 0, 31, 1), ("sub", 0, 31, 1), ("arp", 4, 31, 2), + ("hats", 8, 31, 2), ("lead", 16, 23, 1), ("arp", 24, 27, 4), + ("lead", 28, 31, 1), + ], + # 10 industrial: kick + half stab + perc + sub rumble + "industrial": [ + ("kick", 0, 31, 1), ("sub", 0, 31, 2), ("stab", 4, 31, 4), + ("perc", 8, 31, 2), ("hats", 12, 31, 2), ("clap", 16, 31, 1), + ], + # 11 detroit: kick + hats + sustained pad + stab + "detroit": [ + ("kick", 0, 31, 1), ("pad", 0, 31, 1), ("hats", 4, 31, 2), + ("sub", 8, 31, 1), ("stab", 16, 23, 1), ("stab", 28, 31, 1), + ("hats", 24, 27, 4), + ], + # 12 trance: rich -- kick hats sub lead pad + "trance": [ + ("kick", 0, 31, 1), ("pad", 0, 31, 1), ("sub", 4, 31, 1), + ("hats", 8, 31, 2), ("lead", 16, 23, 2), ("arp", 16, 31, 2), + ("lead", 24, 27, 4), ("lead", 28, 31, 2), ("clap", 16, 31, 1), + ], + # 13 psytrance: kick + rolling sub + acid + sweep zaps + "psytrance": [ + ("kick", 0, 31, 1), ("sub", 0, 31, 2), ("acid", 4, 31, 2), + ("hats", 8, 31, 2), ("sweep", 15, 15, 6), ("sweep", 31, 31, 6), + ("acid", 24, 27, 4), + ], + # 14 punkcore: kick + clap snare + hats + stab chord + lead + "punkcore": [ + ("kick", 0, 31, 1), ("clap", 0, 31, 1), ("hats", 4, 31, 2), + ("stab", 8, 31, 2), ("lead", 16, 23, 2), ("sub", 8, 31, 1), + ("lead", 28, 31, 6), + ], +} + + +def to_sc_literal(g): + rows = ",\n ".join("[" + ",".join(str(v) for v in row) + "]" for row in g) + return "[\n " + rows + "\n]\n" + + +def main(): + for name, segs in PRESETS.items(): + g = build(segs) + path = os.path.join(HERE, name + ".matrix") + with open(path, "w") as f: + f.write(to_sc_literal(g)) + print("wrote", path) + print(len(PRESETS), "presets generated") + + +if __name__ == "__main__": + main() diff --git a/sound_algo/data_only/matrix_presets/hard_pump.matrix b/sound_algo/data_only/matrix_presets/hard_pump.matrix new file mode 100644 index 0000000..2a40674 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/hard_pump.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/hard_rave.matrix b/sound_algo/data_only/matrix_presets/hard_rave.matrix new file mode 100644 index 0000000..0399d79 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/hard_rave.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,6,6,6,6], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/hypno_drift.matrix b/sound_algo/data_only/matrix_presets/hypno_drift.matrix new file mode 100644 index 0000000..6dad909 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/hypno_drift.matrix @@ -0,0 +1,18 @@ +[ + [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/hypno_roll.matrix b/sound_algo/data_only/matrix_presets/hypno_roll.matrix new file mode 100644 index 0000000..fa1ebb9 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/hypno_roll.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/industrial.matrix b/sound_algo/data_only/matrix_presets/industrial.matrix new file mode 100644 index 0000000..5598838 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/industrial.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/psytrance.matrix b/sound_algo/data_only/matrix_presets/psytrance.matrix new file mode 100644 index 0000000..56b914c --- /dev/null +++ b/sound_algo/data_only/matrix_presets/psytrance.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6] +] diff --git a/sound_algo/data_only/matrix_presets/punkcore.matrix b/sound_algo/data_only/matrix_presets/punkcore.matrix new file mode 100644 index 0000000..bc82e32 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/punkcore.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,6,6,6,6], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/trance.matrix b/sound_algo/data_only/matrix_presets/trance.matrix new file mode 100644 index 0000000..b7ea93f --- /dev/null +++ b/sound_algo/data_only/matrix_presets/trance.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/matrix_presets/trance_pluck.matrix b/sound_algo/data_only/matrix_presets/trance_pluck.matrix new file mode 100644 index 0000000..c3f83d1 --- /dev/null +++ b/sound_algo/data_only/matrix_presets/trance_pluck.matrix @@ -0,0 +1,18 @@ +[ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] +] diff --git a/sound_algo/data_only/test/test_matrix.scd b/sound_algo/data_only/test/test_matrix.scd index 30bf8fd..6334ba5 100644 --- a/sound_algo/data_only/test/test_matrix.scd +++ b/sound_algo/data_only/test/test_matrix.scd @@ -63,6 +63,49 @@ try { ("EXCEPTION in ~matStop: " ++ e.class.name).postln }; +// -- Persistence: save / load round-trip (touches filesystem, valid headless) -- +~matSetCell.(1, 7, 4); +~matSetCell.(2, 0, 2); + +try { + ~matSave.("test grid") +} { |e| + pass = false; + ("EXCEPTION in ~matSave: " ++ e.class.name).postln +}; +pass = pass and: { + File.exists(~matDir +/+ "test_grid.matrix").if({ true }, { + ("FAIL: save file not found at " ++ (~matDir +/+ "test_grid.matrix")).postln; + false + }) +}; + +try { + ~matClear.() +} { |e| + pass = false; + ("EXCEPTION in ~matClear: " ++ e.class.name).postln +}; +pass = pass and: { ~lp[\matrix][1][7] == 0 }; + +try { + ~matLoad.("test grid") +} { |e| + pass = false; + ("EXCEPTION in ~matLoad: " ++ e.class.name).postln +}; +pass = pass and: { ~lp[\matrix][1][7] == 4 }; +pass = pass and: { ~lp[\matrix][2][0] == 2 }; +pass = pass and: { ~matGridValid.(~lp[\matrix]) }; +pass = pass and: { + ~matNames.(~matDir).includes(\test_grid).if({ true }, { + "FAIL: test_grid not in matNames".postln; + false + }) +}; + +File.delete(~matDir +/+ "test_grid.matrix"); + // ~matEmitTrig must be defined and emit /matrix/trig with amp clipped to 0..1 pass = pass and: { ~matEmitTrig.notNil }; ~trigLog = nil; diff --git a/web_realart/public/control/control.css b/web_realart/public/control/control.css index 926ac3b..26f88fd 100644 --- a/web_realart/public/control/control.css +++ b/web_realart/public/control/control.css @@ -117,3 +117,15 @@ button.queued { animation: queued-blink 600ms ease-in-out infinite alternate; } 0 0 calc(var(--glow, 0) * 12px) calc(var(--glow, 0) * 4px) rgba(255,255,255, calc(var(--glow, 0) * 0.7)); filter: brightness(calc(1 + var(--glow, 0) * 0.9)); } + +/* --- Matrix persistence bar --- */ +.matrix-persist { display: flex; align-items: center; gap: 6px; margin: 8px 0; flex-wrap: wrap; } +.matrix-name-input { flex: 1; min-width: 100px; background: #1a1a2e; color: #9af; + border: 1px solid #335; border-radius: 6px; padding: 8px 10px; font-size: 14px; } +.matrix-name-input:focus { outline: none; border-color: #4af; } +.matrix-list-select { flex: 1; min-width: 100px; background: #1a1a2e; color: #9af; + border: 1px solid #335; border-radius: 6px; padding: 7px 6px; font-size: 14px; + cursor: pointer; -webkit-appearance: none; appearance: none; } +.mat-action-btn { width: auto; padding: 8px 14px; font-size: 14px; flex-shrink: 0; } +.mat-refresh-btn { width: auto; padding: 8px 12px; font-size: 16px; flex-shrink: 0; + background: #1a2a1a; border-color: #2a4a2a; color: #4d9; } diff --git a/web_realart/public/control/control.js b/web_realart/public/control/control.js index 1983bfc..81719a3 100644 --- a/web_realart/public/control/control.js +++ b/web_realart/public/control/control.js @@ -1,6 +1,6 @@ const ws = new WebSocket(`ws://${location.host}/ws`); const dot = () => document.getElementById("status"); -ws.addEventListener("open", () => dot().className = "on"); +ws.addEventListener("open", () => { dot().className = "on"; send("/matrix/list"); }); ws.addEventListener("close", () => dot().className = "off"); function send(address, ...args) { if (ws.readyState === 1) ws.send(JSON.stringify({ address, args })); @@ -161,6 +161,38 @@ ws.addEventListener("message", (ev) => { } return; } + + // /matrix/list ... — populate saved/preset dropdown + if (address === "/matrix/list") { + const sel = document.getElementById("matrix-list"); + if (!sel) return; + const prev = sel.value; + sel.innerHTML = ""; + args.forEach(name => { + const opt = document.createElement("option"); + opt.value = String(name); + opt.textContent = String(name); + sel.appendChild(opt); + }); + // Preserve prior selection if still present + if (args.map(String).includes(prev)) sel.value = prev; + return; + } + + // /matrix/grid <512 ints row-major vi*32+bar> — rebuild grid from loaded preset + if (address === "/matrix/grid") { + if (!Array.isArray(args) || args.length < 512) return; + for (let vi = 0; vi < 16; vi++) { + for (let bar = 0; bar < MATRIX_BARS; bar++) { + const v = Math.round(Number(args[vi * 32 + bar])); + matGrid[vi][bar] = (Number.isFinite(v) && v >= 0 && v <= 6) ? v : 0; + } + } + saveMatState(); + renderMatrix(); + return; + } + // /matrix/trig — per-note pulse: glow the active cell of voice vi if (address === "/matrix/trig") { triggerGlow(Math.round(Number(args[0])), Number(args[1])); @@ -599,4 +631,18 @@ document.addEventListener("DOMContentLoaded", () => { renderMatrix(); send("/matrix/clear"); }); + + // Matrix persistence bar + const matSave = document.getElementById("matrix-save"); + if (matSave) matSave.addEventListener("click", () => { + const n = (document.getElementById("matrix-name").value || "").trim(); + if (n) { send("/matrix/save", n); send("/matrix/list"); } + }); + const matLoad = document.getElementById("matrix-load"); + if (matLoad) matLoad.addEventListener("click", () => { + const n = document.getElementById("matrix-list").value; + if (n) send("/matrix/load", n); + }); + const matRefresh = document.getElementById("matrix-refresh"); + if (matRefresh) matRefresh.addEventListener("click", () => send("/matrix/list")); }); diff --git a/web_realart/public/control/index.html b/web_realart/public/control/index.html index 12fcf1b..07dd577 100644 --- a/web_realart/public/control/index.html +++ b/web_realart/public/control/index.html @@ -158,6 +158,13 @@ +
+ + + + + +