{"id":26536969,"url":"https://github.com/matdombrock/tidalua","last_synced_at":"2025-03-21T22:17:47.215Z","repository":{"id":282203376,"uuid":"947813490","full_name":"matdombrock/Tidalua","owner":"matdombrock","description":"An experimental synthesizer that uses Lua scripts to generate sound.","archived":false,"fork":false,"pushed_at":"2025-03-21T19:57:20.000Z","size":870,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-21T20:28:24.067Z","etag":null,"topics":["audio","c","live-coding","lua","music","portaudio","synthesizer"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matdombrock.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-13T09:39:53.000Z","updated_at":"2025-03-21T19:57:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"38dfe6d0-fa57-4e07-9b6b-3a5b722469a7","html_url":"https://github.com/matdombrock/Tidalua","commit_stats":null,"previous_names":["matdombrock/wavescript"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matdombrock%2FTidalua","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matdombrock%2FTidalua/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matdombrock%2FTidalua/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matdombrock%2FTidalua/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matdombrock","download_url":"https://codeload.github.com/matdombrock/Tidalua/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244875043,"owners_count":20524591,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["audio","c","live-coding","lua","music","portaudio","synthesizer"],"created_at":"2025-03-21T22:17:46.531Z","updated_at":"2025-03-21T22:17:47.207Z","avatar_url":"https://github.com/matdombrock.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🌘🌊 Tidalua 🌊🌒\nAn experimental synthesizer that uses Lua scripts to generate sound in a \"live coding\" environment.\n\nWhat is it?\n- A modular synthesizer\n- A tracker\n- A live coding environment\n- A fun programming toy\n\nWhat isn't it?\n- A full featured DAW\n- A \"professional\" synthesizer\n- A traditional tracker\n- A \"serious\" audio tool\n- Lab equipment\n\n### Scripting Example\n```lua\n-- Set the waveform for the first voice to square\nwave(2, 1)\n-- Play a note\nnote(\"C4\", 1)\n-- Create an LFO that oscillates between -1 and 1 every second\nlocal lfo = math.sin(seconds * 2)\n-- Set the pan of the first voice to the LFO value\npan(lfo, 1)\n-- We can use the same LFO again to detune the oscillator\n-- Set the detune of the first voice to the LFO value divided by 2\ndetune(lfo / 2, 1)\n```\n\n# OS Support\n- ✅ Linux\n- ✅ MacOS\n- ❓ Windows \n\n# Building\n## External Build Dependencies\n- `curl`\n- `tar`\n- `make`\n- `cmake`\n- `clang` or `gcc`\n\n## First Build\nInitialize the build environment. This script downloads and sets up the necessary dependencies and builds the project.\n```bash\n./init.sh\n```\n\nOnce the project has been initialized you can rebuild it with:\n```bash\n./build.sh\n```\n\nThe binary and scripts will be placed in the `./out` directory.\n\n# Running\n```bash\n./tidalua \u003cscript_path\u003e.lua [ d | v ] \n```\nExample:\n```bash\n./tidalua ./scripts/example1.lua\n```\n\n- `d` - Debug mode\n- `v` - Visual mode (experimental and not fully functional)\n\n# Scripting\n- Oscillator numbers start at 1.\n  - Lua indexes start at 1 in general.\n- There are 8 oscillators total.\n    - The range for any `oscillator_number` param is `1 -\u003e 8` (integer).\n- Most functions that take an `oscillator_numer` param will default to 1 if not provided.\n- Only the first oscillator is enabled by default.\n    - Use `enable(oscillator_number)` to enable others.\n- Lua scripts are run in full before the any samples are generated\n    - This means whatever the last state the script leaves the synth in is what will be heard.\n- Scripts are run periodically as the synth is running (once per tick).\n- The lua environment is reset every time the script is run.\n\t- This means that any variables set in the script will be lost.\n- Scripts will \"hot reload\" as the synth is running. Providing a \"live coding\" environment.\n- Use the `tick` or `seconds` globals to track time. \n    - This is the basis for creating time based effect.\n\n## Lua API Globals\n\n### `seconds`\nThe number of seconds that have passed since the synth started.\n\n### `tick`\nThe current tick number. This is the basis for creating time based effects.\n\nBy default, there are 128 ticks per second. See `speed()` for info about changing this. \n\n## Lua API Functions\n### `dbg(message)`\nPrints a message to the console if the console output mode is set to debug.\n\n```lua\n-- Prints \"Hello, world!\" to the console if the console output mode is set to debug\ndbg(\"Hello, world!\")\n```\n\n### `enable(oscillator_number)`\nEnables an oscillator. The first oscillator is enabled by default.\n\n```lua\n-- Enable the second oscillator\nenable(2)\n```\n\n### `disable(oscillator_number)`\nDisables an oscillator.\n\n```Lua\n-- Disable the first oscillator\ndisable(1)\n```\n\n### `freq(frequency, oscillator_number)`\nSets the frequency of an oscillator in Hz.\n\n```lua\n-- Set the frequency of the first oscillator to 440 Hz\nfreq(440, 1)\n```\n\n*Range Float: `0.0 -\u003e 22050.0`*\n\n### `note(note, oscillator_number)`\nSets the frequency of an oscillator to a given note name (string) or MIDI note value (number).\n\n```lua\n-- Set the frequency of the first oscillator to A4\nnote(\"A4\", 1)\n-- Set the frequency of the second oscillator to A4 using midi notes\nnote(69, 2)\n```\n\n*Range String: `C0 -\u003e C17`*\n\n*Range Integer: `0 -\u003e 127`*\n\n### `detune(cents, oscillator_number)`\nSets the detune of an oscillator as a factor of the frequency.\n\n```Lua\n-- Detune the first oscillator by 50%\ndetune(0.5, 1)\n```\n\n*Range Float: `0.0 -\u003e infinity`*\n\n### `amp(amplitude, oscillator_number)`\nSets the amplitude of an oscillator.\n\nThis is independent of the master volume and amplitude envelopes.\n\n```lua\n-- Set the amplitude of the first oscillator to 0.5\namp(0.5, 1)\n```\n\n*Range Float: `0.0 -\u003e 1.0`*\n\n### `env(attack, sustain, release, oscillator_number)`\nSets the attack, sustain and release (measured in ticks) of an oscillator for use in an amplitude envelope.\n\n- The amplitude envelope is applied as a factor of the amplitude set with `amp()`.\n- By default, an oscillator does not use an amplitude envelope at all.\n- The amplitude envelope will be applied to the oscillator only after it's been enabled by the `env` function.\n- For an amplitude envelope to work, the note must be triggered only once then allowed to play out.\n- The envelope position is reset every time the note is triggered.\n\t- We need to make sure the total length of the envelope is less than the total length of the note.\n\n```lua\n-- Set the attack, sustain and release of the first oscillator to 8, 64, 128 ticks\nenv(8, 64, 128, 1)\n-- The total length of this envelope is 200 ticks\n-- Play it every 256 ticks to allow it to play out\nif tick % 256 == 1 then\n  note(\"C4\", 1)\nend\n```\n\n*Range Float: `0.0 -\u003e infinity`*\n\n### `wave(waveform_number, oscillator_number)`\nSets the waveform of an oscillator.\n```\n-- waveform_number\n-- 0 = Off      1 = Sine\n-- 2 = Square   3 = Sawtooth\n-- 4 = Triangle 5 = Noise\n```\n\n```lua\n-- Set the waveform of the first oscillator to Square\nwave(2, 1)\n```\n\n*Range Integer: `0 -\u003e 5`*\n\n### `pan(pan, oscillator_number)`\nSets the pan of an oscillator.\n\nA value of -1 is full left, 0 is center, and 1 is full right.\n\n```lua\n-- Set the pan of the first oscillator to full left\npan(-1, 1)\n```\n\n*Range Float: `-1.0 -\u003e 1.0`*\n\n### `solo(oscillator_number)`\nSets an oscillator to solo mode. Only the soloed oscillator will be heard.\n\nThis is mostly used for debugging scripts. There is no easy way to \"un-solo\" an oscillator.\n\n```lua\n-- Solo the first oscillator\nsolo(1)\n```\n\n### `lowpass(cutoff, resonance, oscillator_number)`\nSets the lowpass filter of an oscillator.\n\n```lua\n-- Set the lowpass filter of the first oscillator_number\nlowpass(1000, 0.5, 1)\n```\n\n*Cutoff Range Float: `0.0 -\u003e 22050.0`*\n\n*Resonance Range Float: `0.0 -\u003e infinity`*\n\n### `highpass(cutoff, resonance, oscillator_number)`\nSets the highpass filter of an oscillator.\n\n```lua\n-- Set the highpass filter of the first oscillator_number\nhighpass(1000, 0.5, 1)\n```\n\n*Cutoff Range Float: `0.0 -\u003e 22050.0`*\n\n*Resonance Range Float: `0.0 -\u003e infinity`*\n\n### `speed(speed)`\nSets the tick rate for the script.\n\nFor example setting the tick rate to `0.5` would result in 64 ticks per second instead of 128.\n\n- It is not possible to increase the tick speed. \n\t- However, 128 ticks per second is very fast (nearly audio rate).\n- The Lua script is run once per tick. \n\t- Lowering the tick speed also means that the Lua script will be run less frequently.\n\n```lua\n-- Set the tick speed to 0.5\nspeed(0.5)\n```\n\n*Range Float: `0.0 -\u003e 1.0`*\n\n### `mem_set(value, mem_index)`\nSets a value in the memory array at the given index. The Lua state is reset each tick. This is allows for storing values that can be accessed by susequent runs of the script.\n\n- Values may only be numbers (int or float).\n- There are 16 memory locations\n    - Like all other indices, the first memory location is 1.\n- Everything is stored as a float behind the scenes. \n- Lua does not really have a concept of integer vs float types.\n    - However this distiction can be important when dealing with array (table) indices.\n- So, if you supply an integer value to `mem_set()`, the `mem_get()` function will return an integer.\n\n```lua\n-- Set the value at index 0 to 1.0\n-- This is treated as an integer since it has no fractional part\nmem_set(1.0, 1)\n```\n\n*Range Float: `-infinity -\u003e infinity`*\n\n### `mem_get(mem_index)`\nGets a value from the memory array at the given index.\n- Values are returned as floats or integers depending on how they were set.\n- See `mem_set()` for more info.\n```lua\n-- Get the value at index 1\nlocal value = mem_get(1)\n```\n\n### `bus_lowpass(cutoff, resonance)`\nSets the lowpass filter of the master bus.\n\n```lua\n-- Set the lowpass filter of the master bus\nbus_lowpass(1000, 0.5)\n```\n\n*Cutoff Range Float: `0.0 -\u003e 22050.0` (half of the sample rate)*\n\n*Resonance Range Float: `0.0 -\u003e infinity`*\n\n### Examples\nSee the `scripts` directory for examples.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatdombrock%2Ftidalua","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatdombrock%2Ftidalua","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatdombrock%2Ftidalua/lists"}