From 133dacf4770c4a77c68caa7a994c76bc2f09c08b Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Tue, 9 Jun 2026 16:48:46 +0530 Subject: Add audio generation + mario theme --- audio.sh | 40 ++++++++++++++++++++++++++++++++++++++++ flake.nix | 1 + justfile | 10 ++++++++++ setup.sql | 19 +++++++++++++++++++ src/supermariobros.audio.sql | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100755 audio.sh create mode 100644 src/supermariobros.audio.sql diff --git a/audio.sh b/audio.sh new file mode 100755 index 0000000..c5d3c06 --- /dev/null +++ b/audio.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env sh + +set -eu -o pipefail + +[ $# -lt 1 ] && echo "Fuck" && exit 1; +AUDIO_TRACK_ID="$1" +DB="${2:-fun.db}" + +db() { sqlite3 -tabs -noheader "$DB" "$@"; } + +samples() { + audio_track_id="$1" + db "SELECT value FROM audio_track_samples WHERE audio_track_id='$audio_track_id' ORDER BY position ASC" +} + +to_pcm() { + awk '{printf "%02x\n", $1}' | xxd -r -p +} + +play() { + format="$1" + sample_rate="$2" + ffplay -f "$format" -ar "$sample_rate" -b:a 128K -ch_layout mono -autoexit - +} + +track_info() { + local audio_id="$1" + db "SELECT format, sample_rate FROM audio_tracks WHERE id='$audio_id'" +} + + +# ## Main stuff + +data="$(track_info "$AUDIO_TRACK_ID")" +format="$(echo "$data" | cut -f1)" +sample_rate="$(echo "$data" | cut -f2)" + +echo "-----------$data--------" + +samples "$AUDIO_TRACK_ID" | to_pcm | play "$format" "$sample_rate" diff --git a/flake.nix b/flake.nix index 9aeb3e2..17276e7 100644 --- a/flake.nix +++ b/flake.nix @@ -19,6 +19,7 @@ buildInputs = with pkgs; [ imagemagick sqlite + unixtools.xxd ]; }; } diff --git a/justfile b/justfile index 69420b7..63f5eae 100644 --- a/justfile +++ b/justfile @@ -25,6 +25,16 @@ gen-video video_id: echo "Displaying {{video_id}}" 1>&2 ./video.sh "{{video_id}}" +audio file *args: + #!/usr/bin/env sh + set -eu + audio_id=$(just run "{{file}}" {{args}}) + just gen-audio "$audio_id" + +gen-audio audio_id: + echo "Displaying {{audio_id}}" 1>&2 + ./audio.sh "{{audio_id}}" + repl *args: rlwrap sqlite3 "{{DB}}" {{args}} diff --git a/setup.sql b/setup.sql index 0a56f55..18e34d7 100644 --- a/setup.sql +++ b/setup.sql @@ -29,6 +29,18 @@ CREATE TABLE pixels ( UNIQUE(image_id, x, y) ); +CREATE TABLE audio_tracks ( + id TEXT PRIMARY KEY, + sample_rate INTEGER NOT NULL, + format TEXT NOT NULL +); +CREATE TABLE audio_track_samples ( + value INTEGER NOT NULL, + position INTEGER NOT NULL, + audio_track_id TEXT, + FOREIGN KEY(audio_track_id) REFERENCES audio_tracks(id) ON DELETE CASCADE +); + CREATE TRIGGER delete_pixels_when_image_reinserted_because_i_said_so_and_to_make_rerunning_easier BEFORE INSERT ON images BEGIN @@ -40,3 +52,10 @@ BEFORE INSERT ON videos BEGIN DELETE FROM images WHERE video_id = NEW.id; END; + +CREATE TRIGGER delete_samples_when_track_reinserted_because_i_said_so_and_to_make_rerunning_easier +BEFORE INSERT ON audio_tracks +BEGIN + DELETE FROM audio_track_samples WHERE audio_track_id = NEW.id; +END; + diff --git a/src/supermariobros.audio.sql b/src/supermariobros.audio.sql new file mode 100644 index 0000000..b6ce0a7 --- /dev/null +++ b/src/supermariobros.audio.sql @@ -0,0 +1,33 @@ +INSERT OR REPLACE INTO audio_tracks (id, sample_rate, format) VALUES ('supermariobros', 8000, 'u8') RETURNING id; + +WITH RECURSIVE + audio AS (SELECT *, 250 AS n, 100 AS total_tones, 160 AS gain FROM audio_tracks WHERE id = 'supermariobros'), + notes AS (SELECT 659.225 AS E5, 523.2511 AS C5, 783.9909 AS G5, 391.9954 AS G4), + tone(position) AS (SELECT 0 UNION ALL SELECT position + 1 FROM tone, audio WHERE position < total_tones * n), + _samples(value, position) AS ( + SELECT + (CASE + WHEN position < 5*n THEN position * E5 + WHEN position < 6*n THEN 0 + WHEN position < 11*n THEN position * E5 + WHEN position < 17*n THEN 0 + WHEN position < 22*n THEN position * E5 + WHEN position < 28*n THEN 0 + WHEN position < (28+5)*n THEN position * C5 + WHEN position < (28+6)*n THEN 0 + WHEN position < (28+11)*n THEN position * E5 + WHEN position < (28+17)*n THEN 0 + WHEN position < (28+22)*n THEN position * G5 + WHEN position < (28+39)*n THEN 0 + WHEN position < (28+39+5)*n THEN position * G4 + ELSE 0 + END) AS value, + position + FROM tone, notes, audio + ), + samples(value, position) AS ( + SELECT MOD(FLOOR(value * 2.0 / sample_rate), 2) * gain, position + FROM _samples, audio + ) +-- SELECT value FROM samples ORDER BY position; +INSERT INTO audio_track_samples (audio_track_id, value, position) SELECT 'supermariobros', value, position FROM samples ORDER BY position; -- cgit v1.3.1