{"id":20102442,"url":"https://github.com/clickhouse/noisql","last_synced_at":"2026-01-28T04:48:14.953Z","repository":{"id":151877769,"uuid":"622205108","full_name":"ClickHouse/NoiSQL","owner":"ClickHouse","description":"NoiSQL — Generating Music With SQL Queries","archived":false,"fork":false,"pushed_at":"2024-01-01T15:12:06.000Z","size":25928,"stargazers_count":276,"open_issues_count":1,"forks_count":2,"subscribers_count":47,"default_branch":"main","last_synced_at":"2025-04-27T22:32:35.187Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"SQL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ClickHouse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-04-01T12:39:59.000Z","updated_at":"2025-02-01T19:00:00.000Z","dependencies_parsed_at":"2023-09-16T06:46:37.675Z","dependency_job_id":null,"html_url":"https://github.com/ClickHouse/NoiSQL","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ClickHouse/NoiSQL","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClickHouse%2FNoiSQL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClickHouse%2FNoiSQL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClickHouse%2FNoiSQL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClickHouse%2FNoiSQL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ClickHouse","download_url":"https://codeload.github.com/ClickHouse/NoiSQL/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ClickHouse%2FNoiSQL/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28838794,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T02:10:51.810Z","status":"ssl_error","status_checked_at":"2026-01-28T02:10:50.806Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T17:30:47.063Z","updated_at":"2026-01-28T04:48:14.920Z","avatar_url":"https://github.com/ClickHouse.png","language":"SQL","readme":"# NoiSQL — Generating Music With SQL Queries\n\nNoiSQL (named after [Robert Noyce](https://en.wikipedia.org/wiki/Robert_Noyce)) shows how to play sound and music with declarative SQL queries.\n\nIt contains oscillators for basic waves, envelopes, sequencers, arpeggiators, effects (distortion, delay), noise generators, AM and FM, and LFO, ...\nSometimes it can generate something nice, but usually not. \n\n# Table of Contents\n- [NoiSQL — Generating Music With SQL Queries](#noisql---generating-music-with-sql-queries)\n  * [Quick Start - Linux](#quick-start---linux)\n  * [Quick Start - MacOS](#quick-start---macos)\n  * [Bleeps and Bloops - a demonstration](#bleeps-and-bloops---a-demonstration)\n  * [Examples](#examples)\n- [How It Works](#how-it-works)\n  * [Making Something Interesting](#making-something-interesting)\n    + [Input](#input)\n    + [Output Control](#output-control)\n    + [Basic waves](#basic-waves)\n    + [Helpers and LFO](#helpers-and-lfo)\n    + [Noise](#noise)\n    + [Distortion](#distortion)\n    + [Envelopes](#envelopes)\n    + [Sequencers](#sequencers)\n    + [Delay](#delay)\n    + [Components](#components)\n    + [Combine It](#combine-it)\n    + [Additional Commands](#additional-commands)\n  * [Limitations](#limitations)\n  * [Further Directions](#further-directions)\n- [Motivation](#motivation)\n- [Contributing](#contributing)\n  * [Reading Corner](#reading-corner)\n\n## Quick Start - Linux\nClone the Repository.\n\nDownload clickhouse-local:\n```\ncurl https://clickhouse.com/ | sh\n```\n\nInstall (Linux):\n```\nsudo ./clickhouse install\n```\n\nCheck the installation:\n```\nclickhouse-local --version\n```\n\n## Quick Start - MacOS\nBefore beginning, please ensure that you have [homebrew](https://brew.sh/) installed.\n\nClone the Repository.\n\nChange to the Repository folder (i.e. `cd NoiSQL`)\n\nInstall ClickHouse (macOS):\n```\nmkdir -p bin\ncurl https://clickhouse.com/ | sh\nmv clickhouse bin/clickhouse-local\nexport PATH=\"$(pwd)/bin:$PATH\"\n```\n\n*NOTE: If you want this to live past a terminal restart add to your profile. That may look something like the below or `.bash_profile` or `.zshrc` depending on your terminal of choice.*\n\n```\necho 'export PATH=\"'$(pwd)'/bin:$PATH\"' \u003e\u003e .profile\n```\n\nIn order to playback audio from the terminal (via STDIN) we use an open source project (with a convenient brew recipe) called 'sox' (note that Xcode developer tools is a dependency, and if you don't have it installed, you will need to install it first via `xcode-select --install`)\n\n```\nbrew install sox\n```\n\n## Bleeps and Bloops - a demonstration\nNow, ClickHouse Local is setup and it is time to make our first noises.\n\nDemo (Linux):\n```\n./music2.sql.sh | aplay -f cd\n```\n\nDemo (macOS):\n```\n./music2.sql.sh | play -t raw -b 16 -e signed -c 2 -r 44100 -v .75 -\n```\n\nLive editing (Linux):\n```\nsudo apt install inotifytools\n./play.sh music0.sql\n```\n\nYou can edit the `music0.sql` file, and the changes will automatically apply while playing. On macOS this is not possible due to the lack of inotifytools BUT the play script can be used to play any of the samples music*.sql files provided\n\n## Examples\nIf, you are unable to use it yourself. You can still hear the output as .mp4 here.\n\nhttps://user-images.githubusercontent.com/18581488/229301700-d71d5a9c-ad7e-492b-80ba-d49114fd0bfe.mp4\n\nhttps://user-images.githubusercontent.com/18581488/229301704-d82d89b7-7650-44eb-a525-0630888d2080.mp4\n\nhttps://user-images.githubusercontent.com/18581488/229301706-8e14b0c1-01a9-47a5-84dd-8a069832e63f.mp4\n\nhttps://user-images.githubusercontent.com/18581488/229301709-9a102865-be02-4072-8707-48a6a571c500.mp4\n\n--------------------------\n# How It Works\n\nAn SQL query selects from the `system.numbers` table, containing a sequence of natural numbers, and transforms this sequence into a PCM audio signal in the CD format. This output signal is piped to the `aplay -f cd` tool (on Linux) to play it.\n\nThe CD (Compact Disc Audio) format is a 44100 Hz 16-bit stereo PCM signal.\n- **44100 Hz** is the \"sampling frequency\", meaning that the signal has a value 44 100 times every second;\n- **16 bit** is the precision of every value, and the value is represented by `Int16` (signed, two's complement, little endian) integer; \n- **stereo** means that we have two values at every sample - for the left channel and for the right channel;\n\nThe signal is represented in binary, corresponding to the ClickHouse's `RowBinary` format. Therefore, the bit rate of the signal is 16 * 2 * 44100 = 1411 kBit.\n\nAlthough we could also use the classic 8-bit mono 9 kHz format, the CD format gives more possibilities. \n\nTo get the idea, run this:\n```\nclickhouse-local --query \"\n    SELECT \n        (number % 44100)::Int16           AS left, \n        ((number + 22050) % 44100)::Int16 AS right \n    FROM system.numbers\n    FORMAT RowBinary\" | aplay -f cd\n```\n\nIt will give you an uninteresting clicky sound.\n\n```\nclickhouse-local --query \"\n    WITH number * 2 * pi() / 44100 AS time \n    SELECT\n        (sin(time * 200) * 0x7FFF)::Int16 AS left,\n        (sin(time * 400) * 0x7FFF)::Int16 AS right\n    FROM system.numbers\n    FORMAT RowBinary\" | aplay -f cd\n```\n\nIt will give you uninteresting waves.\n\n## Making Something Interesting\n\nHere is a query from [music0.sql](music0.sql), that generates something at least listenable. Let's walk through this SQL query.\n\nThe WITH clause in the SQL query allows defining expressions for further use.\nWe can define both constants and functions (in form of lambda expressions).\nWe use the `allow_experimental_analyzer` setting to make this query possible.\n\n### Input\n\nLet's define the `time` column to be a floating point value representing the number of seconds.\n\n```\nWITH\n\n44100 AS sample_frequency\n, number AS tick\n, tick / sample_frequency AS time\n```\n\n### Output Control\n\nLet us work with the signal in the floating point format, with values in the `[-1, 1]` range.\nHere are the functions to convert it to the output PCM CD signal.\n\nA knob for the volume:\n```\n, 1 AS master_volume\n```\n\nIf the signal exceeds the boundaries, it will be clipped:\n```\n, level -\u003e least(1.0, greatest(-1.0, level)) AS clamp\n```\n\nFloating point values are converted to Int16 for the output:\n```\n, level -\u003e (clamp(level) * 0x7FFF * master_volume)::Int16 AS output\n```\n\nIf we don't care about stereo - we can simply output a tuple (pair) of identical values:\n```\n, x -\u003e (x, x) AS mono\n```\n\n### Basic waves\n\nWe define oscillators as functions of time, with the period adjusted to be one second.\nYou can modify the frequency simply by multiplying the time argument.\nFor example, `sine_wave(time * 400)` - a sine wave of 400 Hz frequency.\n\nThe sine wave gives the cleanest and most boring sound.\n```\n, time -\u003e sin(time * 2 * pi()) AS sine_wave\n```\n\nThe [square wave](https://en.wikipedia.org/wiki/Square_wave) gives a very harsh sound; it can be imagined as a maximally-distorted sine wave.\n``` \n, time -\u003e time::UInt64 % 2 * 2 - 1 AS square_wave\n```\n\nSawtooth wave\n``` \n, time -\u003e (time - floor(time)) * 2 - 1 AS sawtooth_wave\n```\n\nTriangle wave\n``` \n, time -\u003e abs(sawtooth_wave(time)) * 2 - 1 AS triangle_wave\n```\n\n### Helpers and LFO\n\nLFO means \"Low-Frequency Oscillation,\" and it is used to control a parameter of one signal with another low-frequency signal.\nIt can have multiple interesting effects. \n\nFor example, AM - amplitude modulation is modulating the volume of one signal with another signal, and it will give a trembling effect, making your sine waves sound more natural.\n\nAnother example, FM - frequency modulation, is making the frequency of one signal change with another frequency.\nSee [the explanation](https://www.youtube.com/watch?v=vvBl3YUBUyY).\n\nWe take the wave and map it to the `[from, to]` interval:\n```\n, (from, to, wave, time) -\u003e from + ((wave(time) + 1) / 2) * (to - from) AS lfo\n```\n\nHere is a discrete version of an LFO. It allows changing the signal as a step function:\n```\n, (from, to, steps, time) -\u003e from + floor((time - floor(time)) * steps) / steps * (to - from) AS step_lfo\n```\n\nFor some unknown reason, the frequencies of musical notes (\"musical scale\") are exponentially distributed, so sometimes we have to apply computations in the [logarithmic coordinates](https://en.wikipedia.org/wiki/Curvilinear_coordinates) to make a more pleasant sound:\n```\n, (from, to, steps, time) -\u003e exp(step_lfo(log(from), log(to), steps, time)) AS exp_step_lfo\n```\n\n### Noise\n\nGenerating noise is easy. We just need random numbers.\n\nBut we want the noise to be deterministic (determined by the time) for further processing.\nThat's why we use `cityHash64` instead of a random and `erf` instead of `randNormal`.\n\nAll the following are variants of white noise. Although we can also generate [brown noise](https://en.wikipedia.org/wiki/Brownian_noise) with the help of `runningAccumulate`.\n\n``` \n, time -\u003e cityHash64(time) / 0xFFFFFFFFFFFFFFFF AS uniform_noise\n, time -\u003e erf(uniform_noise(time)) AS white_noise\n, time -\u003e cityHash64(time) % 2 ? 1 : -1 AS bernoulli_noise\n```\n\n### Distortion\n\nDistortion alters the signal in various ways to make it sound less boring.\n\nThe harshest distortion - clipping - amplifies the signal, then clips what's above the range.\nIt adds higher harmonics and makes sound more metallic, and makes sine waves more square.\n```\n, (x, amount) -\u003e clamp(x * amount) AS clipping\n```\n\nFor a milder version, it makes sense to apply the `pow` function, such as square root to the `[-1, 1]` signal:\n```\n, (x, amount) -\u003e clamp(x \u003e 0 ? pow(x, amount) : -pow(-x, amount)) AS power_distortion\n```\n\nWe can reduce the number of bits in the values of the signal, making it more coarse.\nIt adds some sort of noise, making it sound worn out.\n```\n, (x, amount) -\u003e round(x * exp2(amount)) / exp2(amount) AS bitcrush\n```\n\nLowering the sample rate makes the signal dirty. Try to apply it for white noise.\n```\n, (time, sample_frequency) -\u003e round(time * sample_frequency) / sample_frequency AS desample\n```\n\nSomething like compressing the periodic components in time and adding empty space - no idea why I need it:\n``` \n, (time, wave, amount) -\u003e (time - floor(time) \u003c (1 - amount)) ? wave(time * (1 - amount)) : 0 AS thin\n```\n\nSkewing the waves in time making sine ways more similar to sawtooth waves:\n``` \n, (time, wave, amount) -\u003e wave(floor(time) + pow(time - floor(time), amount)) AS skew\n```\n\n### Envelopes\n\nThe envelope is a way to make the signal sound like a note of a keyboard musical instrument, such as a piano.\n\nIt modulates the volume of the signal by:\n- attack - time for the sound to appear;\n- hold - time for the sound to play at maximum volume; \n- release - time for the sound to decay to zero;\n\nThis is a simplification of what typical envelopes are, but it's good enough.\n```\n, (time, offset, attack, hold, release) -\u003e\n       time \u003c offset ? 0\n    : (time \u003c offset + attack                  ? ((time - offset) / attack)\n    : (time \u003c offset + attack + hold           ? 1\n    : (time \u003c offset + attack + hold + release ? (offset + attack + hold + release - time) / release\n    : 0))) AS envelope\n```\n\nWe can make the musical note sound periodically to define a rhythm.\nFor convenience, we define \"bpm\" as \"beats per minute\" and make it sound once in every beat.\n```\n, (bpm, time, offset, attack, hold, release) -\u003e\n    envelope(\n        time * (bpm / 60) - floor(time * (bpm / 60)),\n        offset,\n        attack,\n        hold,\n        release) AS running_envelope\n```\n\n### Sequencers\n\nTo create a melody, we need a sequence of notes. A sequencer generates it.\n\nIn the first example, we simply take it from an array and make it repeat indefinitely:\n``` \n, (sequence, time) -\u003e sequence[1 + time::UInt64 % length(sequence)] AS sequencer\n```\n\nBut the obvious way to generate a melody is to take a [Sierpinski triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle).\n\nSierpinski triangles sound delicious:\n```\n, time -\u003e bitAnd(time::UInt8, time::UInt8 * 8) AS sierpinski\n```\n\nAnother way is to map the number of bits in a number to a musical note:\n```\n, time -\u003e bitCount(time::UInt64) AS bit_count\n```\n\nCalculating the number of trailing zero bits gives us a nice arpeggiator:\n```\n, time -\u003e log2(time::UInt64 \u003e 0 ? bitXor(time::UInt64, time::UInt64 - 1) : 1) AS trailing_zero_bits\n```\n\n### Delay\n\nIf you ever wanted to generate dub music, you cannot go without a delay effect:\n```\n, (time, wave, delay, decay, count) -\u003e arraySum(n -\u003e wave(time - delay * n) * pow(decay, n), range(count)) AS delay\n```\n\n### Components\n\nHere is a kick:\n```\nsine_wave(time * 50) * running_envelope(120, time, 0, 0.01, 0.01, 0.025) AS kick,\n```\n\nHere is a snare:\n```\nwhite_noise(time) * running_envelope(120, time, 0.5, 0.01, 0.01, 0.05) AS snare,\n```\n\nLet's also define five melodies. \n\nWhat is the idea? Let's take a [Sierpinski triangle](https://www.youtube.com/watch?v=IZHiBJGcrqI), put it into a sine wave, add FM to make it even fancier, and apply a few LFOs over the place.\n\n```\nsine_wave(\n    time * (100 * exp2(trailing_zero_bits(time * 8) % 12 / 6))\n  + sine_wave(time * 3 + 1/4)) * 0.25 * lfo(0.5, 1, sine_wave, time * 11)\n    * running_envelope(480, time, 0, 0.01, 0.1, 0.5)\n    * lfo(0, 1, sine_wave, time / 12\n    ) AS melody1,\n  \nsine_wave(time * (200 * exp2(bit_count(time * 8) % 12 / 6))\n  + sine_wave(time * 3 + 1/4)) * 0.25 * lfo(0.5, 1, sine_wave, time * 11)\n    * running_envelope(480, time, 0, 0.11, 0.1, 0.5) * lfo(0, 1, sine_wave, time / 24\n    ) AS melody2,\n    \nsine_wave(time * (400 * exp2(sierpinski(time * 8) % 12 / 6))\n    + sine_wave(time * 3 + 1/4)) * 0.25 * lfo(0.5, 1, sine_wave, time * 11)\n    * running_envelope(480, time, 0, 0.21, 0.1, 0.5) * lfo(0, 1, sine_wave, time / 32\n    ) AS melody3,\n    \nsine_wave(time * (800 / exp2(trailing_zero_bits(time * 8) % 12 / 6))\n    + sine_wave(time * 3 + 1/4)) * 0.25 * lfo(0.5, 1, sine_wave, time * 11)\n    * running_envelope(480, time, 0, 0.31, 0.1, 0.5) * lfo(0, 1, sine_wave, time / 16\n    ) AS melody4\n```\n\n### Combine It\n\nSo, what will happen if we mix together some garbage and listen to it?\n```\nSELECT\n\nmono(output(\n      1.0   * melody1\n    + 0.5   * melody2\n    + 0.25  * melody3\n    + 1.0   * melody4\n    + 1     * kick\n    + 0.025 * snare))\n\nFROM table;\n```\n\n### Additional Commands\n\nGenerate five minutes of audio and write to a `.pcm` file:\n```\nclickhouse-local --format RowBinary --query \"SELECT * FROM system.numbers LIMIT 44100 * 5 * 60\" \\\n | clickhouse-local --allow_experimental_analyzer 1 --format RowBinary --structure \"number UInt64\" --queries-file music0.sql \\\n\u003e music0.pcm\n```\n\nConvert `pcm` to `wav`:\n```\nffmpeg -f s16le -ar 44.1k -ac 2 -i music0.pcm music0.wav\n```\n\nConvert `pcm` to `mp4`:\n```\nffmpeg -f s16le -ar 44.1k -ac 2 -i music0.pcm music0.mp4\n```\n\n## Limitations\n\nI haven't, yet, found a good way to implement filters (low-pass, high-pass, band-pass, etc.). It does not have Fourier transform, and we cannot operate on the frequency domain. However, the moving average can suffice as a simple filter.\n\n## Further Directions\n\nYou can use ClickHouse as a sampler - storing the prepared musical samples in the table and arranging them with SELECT queries. For example, the [Mod Archive](https://modarchive.org/) can help.\n\nYou can use ClickHouse as a vocoder. Just provide the microphone input signal instead of the `system.numbers` as a table to `clickhouse-local`.\n\nYou can make the queries parameterized, replacing all the hundreds of constants with parameters. Then attach a device with hundreds of knobs and faders to your PC and provide their values of them as a streaming input table. Then you can control your sound like a pro. \n\nReal-time video generation can be added as well.\n\n# Motivation\n\nThis is a fun project and neither a good nor convenient solution to a problem. Better solutions exist. \n\nThere is not much sense in this project, although it can facilitate testing ClickHouse.\n\nYou could argue that modern AI, for example, [Riffusion](https://www.riffusion.com/), can do a better job. The counterargument is - if you enjoy what you are doing, it's better not to care if someone does it better but with less pleasure.\n\n# Contributing\n\nIf you want to share new interesting examples, please make a pull request, adding them directly to this repository!\n\n\n## Reading Corner\n\n- [Sound](https://ciechanow.ski/sound/) by Bartosz Ciechanowski;\n- [Bytebeat](https://www.youtube.com/watch?v=tCRPUv8V22o);\n- [Color of Noise](https://en.wikipedia.org/wiki/Colors_of_noise);\n- [Glitchmachine](https://www.youtube.com/watch?v=adoF2Lc70J8);\n- [Audio Synthesis](https://www.youtube.com/watch?v=F1RsE4J9k9w);\n- [44,100 Hz](https://en.wikipedia.org/wiki/44,100_Hz);\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclickhouse%2Fnoisql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclickhouse%2Fnoisql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclickhouse%2Fnoisql/lists"}