{"id":18774131,"url":"https://github.com/leafac/reaper","last_synced_at":"2026-01-26T03:33:07.819Z","repository":{"id":55057085,"uuid":"299444911","full_name":"leafac/reaper","owner":"leafac","description":"Leandro Facchinetti’s REAPER effects and scripts","archived":false,"fork":false,"pushed_at":"2023-01-26T17:27:02.000Z","size":33274,"stargazers_count":113,"open_issues_count":9,"forks_count":14,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-05-21T02:46:23.337Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leafac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"patreon":"leafac","custom":["https://paypal.me/LeandroFacchinettiEU","https://btc.com/34KJBgtaFYMtDqpSgMayw9qiKWg2GQXA9M"],"github":"leafac"}},"created_at":"2020-09-28T22:21:23.000Z","updated_at":"2025-05-02T16:34:43.000Z","dependencies_parsed_at":"2023-02-08T07:01:37.441Z","dependency_job_id":null,"html_url":"https://github.com/leafac/reaper","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/leafac/reaper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafac%2Freaper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafac%2Freaper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafac%2Freaper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafac%2Freaper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leafac","download_url":"https://codeload.github.com/leafac/reaper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafac%2Freaper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28765921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T03:19:35.311Z","status":"ssl_error","status_checked_at":"2026-01-26T03:19:13.815Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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-07T19:37:25.854Z","updated_at":"2026-01-26T03:33:07.803Z","avatar_url":"https://github.com/leafac.png","language":"HTML","funding_links":["https://patreon.com/leafac","https://paypal.me/LeandroFacchinettiEU","https://btc.com/34KJBgtaFYMtDqpSgMayw9qiKWg2GQXA9M","https://github.com/sponsors/leafac"],"categories":[],"sub_categories":[],"readme":"\u003c!--\nWhen exploding tracks that make up a ‘.mkv’ file, preserve the tracks names. (https://forum.cockos.com/showthread.php?p=2598861#post2598861)\n\n\n\n\n// Tale\n\ndesc:JSFX mouse cursors\nslider1:1\u003c1,14,1{None*,Arrow,Text,Wait*,Crosshair*,Arrow Up,Size NW/SE,Size NE/SW,Size W/E,Size N/S,Size All,No,Hand,App Start*,Help*}\u003eCursor\n\n@init\n\nmem_set_values(tbl,\n  // 32511 or any other undefined resource ID.\n  32511, // None*\n\n  32512, // Arrow\n  32513, // Text\n  32514, // Wait*\n  32515, // Crosshair*\n  32516, // Arrow Up\n\n  32642, // Size NW/SE\n  32643, // Size NE/SW\n  32644, // Size W/E\n  32645, // Size N/S\n  32646, // Size All\n\n  32648, // No\n  32649, // Hand\n  32650, // App Start*\n  32651  // Help*\n);\n\n// * Not available on macOS.\n\n@gfx\n\ngfx_setcursor(tbl[slider1]);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nBug in Scripts/leafac_Explode multistream (multitrack) media file to new one-stream (one-track) media files.lua:\nStreams may be something other than video or audio. They may also be subtitles, attachments (data), and so forth. Right now, the script will try to treat them as audio and crash. These other streams should probably be ignored. (Report back to Ockenden)\n\n\n\n\n\nImage to MIDI conversion\n\n\nMaybe multichannel is bad because it affects Sidechains for later plugins\nTest what denormalization is doing: adding noise (like dither) or a fixed small value (like ReEQ)\nOn rms, don’t compute the root and convert to db directly\nGenerate pink noise with stochastic model: inverse fft of magnitude with 3db slope and random phase\nWaveform visualizer for any plug-in (just sandwich)\nYin\nPlugin doctor\nIdea of how to make circular buffers faster: have a notion of item size, so that you can store structs directly and cut one memory dereference\nIdea pf optmization for rms: dont store the size, store its reciprocal, so that a division turns into a multiplication \njust call getchar so that mouse modifiers work\nDigital hardware (like lexicon) has adc and dac. So if you have several in the chain, doesn’t it mean a lot of latency? What about modular synths?\n\n\nDraw a piano keyboard \nFrequency to midi note and back\nWhat does spectral reversal sound like (not applied to a filter kernel, but to a signal)\nCorrelation meter\n\n\nPing pong ball drop https://www.youtube.com/watch?app=desktop\u0026v=ZGcpOFo_HDA\n\n\nUse “play or stop” on MIDI editor\n\n\nADD TO REAPACK\n\nleafac_Unselect (clear selection of) all tracks, items, envelope points, time selection, and loop points\n\n\nMAP\n\nesc: leafac_Unselect (clear selection of) all tracks, items, envelope points, time selection, and loop points\n\n\n\n\n\nPrepare project for video/audio editing: Set BPM to 240 so 1 measure is one second. (See comment on https://reaperblog.net/2017/02/custom-grid-size-toolbar/)\n\n\nLeslie https://www.youtube.com/watch?v=vUaScoPXW28\n\n\n\nControlling REAPER with AutoHotkey\n\n- [ ] https://www.youtube.com/watch?v=ipL7H02G8bs\u0026lc=UgzfLHisYi3GLBVVCUl4AaABAg\n\n\n- [ ] OBS ↔ REAPER\n    - [ ] Abort recording \u0026 pre-roll \u0026 stuff: https://forum.cockos.com/showthread.php?p=2455092#post2455092\n\n\nREAPER ↔ OBS\n\n- [ ] Abort recording: https://forum.cockos.com/showpost.php?p=2430380\u0026postcount=29\n- [ ] Don’t show user-generated values in GetUserInputs, use ShowConsoleMsg instead\n    - [ ] You would need to add a short reference to the console-window in the title of GetUserInputs, so blind people know, there's a second window to look for additional information.\n- [ ] Use Mespotine’s scripts\n- [ ] LTC\n    - [ ] https://www.youtube.com/watch?v=E4R4wlfKdcw\u0026lc=UgxRZeB539r1oGd__lt4AaABAg\n- [ ] Add better error messages:\n    - [ ] When OBS isn’t running\n    - [ ] When you’re already recording and try to start\n    - [ ] When you’re not recording and try to stop\n    - [ ] https://www.youtube.com/watch?v=dxfM4ftB1hM\u0026lc=UgyzzfiAV-l2CMDhUF14AaABAg\n- [ ] Pre-roll/count-in/loop recording: https://forum.cockos.com/showpost.php?p=2421273\u0026postcount=27\n- [ ] Don’t change the recording path in OBS https://forum.cockos.com/showpost.php?p=2476104\u0026postcount=8\n- [ ] Add as a new take, not new track (Adding the video as a new take to an item if there is already a video recorded there.) https://forum.cockos.com/showpost.php?p=2476736\u0026postcount=44 / stefhambrook@gmail.com\n- [ ] Cancel recording (and discard audio and video files into the trash)  triode\n- [ ] Multicam OBS with multiple OBS instances https://www.youtube.com/watch?v=E4R4wlfKdcw\u0026lc=UgyS-NHJoZkEdwLFj3N4AaABAg\n\n- [ ] Add YouTube links to ReaScripts\n\n\nJSFX\n\n- [ ] Ping-pong delay\n- [ ] Detect chords\n- [ ] Blow air into mic game\n- [ ] Flappy bird game (Flappy Square)\n- [ ] Airwindows: Convert to JSFX: Spiral or Mojo\n- Focus, an all-in-one distortion suite that includes, among others, the Spiral and Mojo algorithms (you may also try Distortion, which is pretty similar except without the frequency selection)\n- PurestGain, as JSFX's ability to type exact values would work wonders on this\n- Preponderant, a plugin that does the opposite of popular resonance-removing plugins like Soothe, TEOTE and the freeware Vastaus (we need to implement an \"Inverse\" function in the Dry/Wet just like in other Airwindows plugins, so it does actually function as a Soothe-like plugin)\n- DeBess, as it is an excellent de-esser but its structure may not be easy to understand for beginners (same with Pressure4)\n- Infinity2 (so you can kill the feedback with a button instead of dragging the Feedback fader to the left)\n- CStrip may be good for JSFX, and I'd like to try its TimeLag function with exact values\nFotis Ky \u003cseethisworld@gmail.com\u003e\n\n\n- [ ] Control dry/wet depending on gain (think about how reverb works in a hall: louder means more reverb)\n- [ ] Fernando Imperator (https://twitter.com/imperat) Feature idea: If you ever develop a version that instead of rendering the multicam video, just creates an XML to import to Adobe Premiere or DaVinci, it'd be awesome.\n\n- [ ] Run Doom in JSFX\n\nScripts\n\n- [ ] That ADR item naming thing\n\nA VST that connects to WebRTC\n\n- [ ] https://forum.cockos.com/private.php?do=showpm\u0026pmid=205857\n- [ ] Re: Build a jsfx plugin question\n- [ ] https://forum.cockos.com/showthread.php?t=249449\n- [ ] https://sonobus.net\n- [ ] https://audiomovers.com/wp/\n- [ ] https://www.landr.com/en/sessions\n\n\n- [ ] Use reaper.GetCursorContext() to create ReaScript that consolidates Item: Duplicate items and Track: Duplicate tracks\n- [ ] Upload rendered video to YouTube\n- [ ] Sync footage\n- [ ] Multicam\n    - [ ] Create ReaScripts to switch items on a dedicated track: https://www.youtube.com/watch?v=1BvuRgKNnqc\u0026lc=UgxKIx95LJ9-nLCd-5d4AaABAg\n    - [ ] ReaScript to set up tracks \u0026 dedicated video processor item\n    - [ ] Add support for clicking on thumbnails in preview to switch to another scene\n    - [ ] When switching with ReaScript if you didn’t select items, look for an item under the cursor (and maybe even if you did select items, really)\n\n\n- [ ] Structured data\n    - [ ] Structures\n        - [ ] Arrays\n        - [ ] Objects\n        - [ ] Multi-dimensional arrays\n            - [ ] For example, lists of one buffer per channel\n        - [ ] Circular buffers\n            - [ ] One field for current position, another for buffer itself\n    - [ ] Uses\n    - [ ] Applications\n        - [ ] Automixer\n        - [ ] Oscilloscope\n    - [ ] Implementation techniques\n        - [ ] Pseudo-objects\n            - [ ] Good because it puts together things that belong together\n            - [ ] Bad because it doesn’t work with dynamically allocated structures (for example, one circular buffer per channel)\n        - [ ] Arrays with fixed positions (for example, my_object[field_index], my_multi_dimensional_array[index_x][index_y])\n        - [ ] Functions that calculate indexes (for example, my_multi_dimensional_array[my_multi_dimensional_array_index(x, y, width, height)]\n            - [ ] Good because multiplication is faster than multiple memory lookups of the technique above\n            - [ ] Bad because it’s more cumbersome to use (you have to keep repeating the width and height, but it may be a good thing to avoid out-of-bounds errors)\nfunction begin_memory_allocation() global(next_available_memory_address) (\n  next_available_memory_address = 0;\n);\nfunction array(size) local(address) global(next_available_memory_address) (\n  address = next_available_memory_address;\n  next_available_memory_address += size;\n  address;\n);\nfunction end_memory_allocation() global(next_available_memory_address) (\n  freembuf(next_available_memory_address + 1);\n);\n\nbegin_memory_allocation();\nbuffer1 = array(100);\nbuffer1[20] = array(20);\nbuffer2 = array(200);\nend_memory_allocation();\n- [ ] Better tooling\n    - [ ] Formatter\n    - [ ] Visual Studio Code support\n        - [ ] Syntax highlighter\n        - [ ] Refactoring tools\n    - [ ] Unit tests\n        - [ ] Null tests\n\nAutomixer\n\n- https://forums.prosoundweb.com/index.php/topic,158018.0.html\n- https://forum.audulus.com/t/gain-sharing-auto-mixer/1744\n- [ ] Plugin Delay Compensation should be 0 samples when there’s no lookahead (hard-code a special case)\n- [ ] max(gain reduction with lookahead, gain reduction without lookahead) https://www.youtube.com/watch?v=p7Ol5FPvHfs\n- [ ] Draw dB scale on meters\n- [ ] Envelope (Attack, Hold, Release)\n- [ ] More appealing visuals\n    - [ ] Background\n    - [ ] Title\n\n- [ ] Tone generator: Part 3\n    - [ ] Invert square wave\n    - [ ] Refactor the thing that draws on Y axis\n    - [ ] LFO controls\n        - [ ] Test with enveloper\n    - [ ] Mention frequency bound problem\n- [ ] Hull Moving Average as a low-pass filter\n- [ ] Hilbert curve\n- [ ] Flappy Bird controlled by voice!\n- [ ] Shepard’s tone generator\n- [ ] NES emulation\n    - [ ] Load ROM as audio!\n- [ ] A Vocal Rider clone\n- [ ] Sound visualizations\n- [ ] DC offset fixer\n- [ ] LV2 effect: https://news.ycombinator.com/item?id=25046869\n- [ ] Oscilloscope\n    - [ ] Plot channels as a stack of oscilloscopes (that’s what the main REAPER interface does)\n    - [ ] Draw scale\n- [ ] GUI knob: https://forum.cockos.com/showpost.php?p=2357022\u0026postcount=3\n- [ ] Delay\n    - [ ] Ping-pong\n- [ ] Subsampler (a digital distortion effect that consists of reducing the number of samples per second)\n    - [ ] Use it for aliasing distortion: https://www.youtube.com/watch?v=74GzXK1MngI\n- [ ] Volume meter\n- [ ] Tuner\n- [ ] Metronome\n- [ ] Pitch shifter\n- [ ] Vectorscope (ginioscope)\n- [ ] Phase shifte\n- [ ] Tone Generator\n    - [ ] Noise\n        - [ ] White\n        - [ ] Pink\n            - [ ] https://www.firstpr.com.au/dsp/pink-noise/\n            - [ ] https://dsp.stackexchange.com/questions/62342/understanding-voss-mccartney-pink-noise-generation-algorithm\n            - [ ] \n        - [ ] Brown\n        - [ ] Gray\n    - [ ] Sample and hold\n    - [ ] Truncate the shapes above\n    - [ ] ASDR (use trigger)\n    - [ ] User-drawn shapes\n    - [ ] LFO mode\n- [ ] White noise, when speed up, doesn’t sound a different pitch and tamber (it’s a fucking fractal!)\n    - [ ] Generate white and brown music with MIDI\n    - [ ] Stochastic method\n    - [ ] Build arpeggiators with these\n    - [ ] Pink noise: levels of river!\n    - [ ] White: sum 10 dice / brown: up on even, down on odd / pink: three dice rolled on log_2\n    - [ ] How do different colors of sound feel with hands on the speakers\n- [ ] Subtractive synth\n    - [ ] ADSR\n    - [ ] MIDI\n- [ ] Granular synth\n- [ ] Meters\n    - [ ] Peak\n    - [ ] RMS\n    - [ ] LUFS\n        - [ ] Seems to be a combination of RMS + gating + a-weighting\n        - [ ] Check EBU manuals to learn more about it\n    - [ ] PSR and PLR\n        - [ ] http://www.meterplugs.com/blog/2017/05/18/crest-factor-psr-and-plr.html\n        - [ ] http://www.meterplugs.com/blog/2016/11/18/why-loudness-doesnt-matter.html\n        - [ ] Dear Leandro\n- [ ] Levels over time\n    - [ ] Peak\n    - [ ] RMS\n    - [ ] LUFS\n- [ ] Pitch shifter\n- [ ] EQ\n    - [ ] A low-pass filter is like lowering the sample rate 🤯\n    - [ ] What are poles and zeroes?\n- [ ] Compressor\n- [ ] Limiter\n    - [ ] Soft clipper\n    - [ ] Peak limiter\n- [ ] Telephoner: a one knob FX that’s a bit crusher followed by a filter\n- [ ] Tremolo\n    - [ ] Combination of an LFO with an Enveloper\n- [ ] Reverb\n    - [ ] Algorithmic\n    - [ ] Convolution\n- [ ] Spectogram\n- [ ] Spectrograph\n- [ ] De-click\n- [ ] De-plosive\n- [ ] Crazy ideas:\n    - [ ] Multichannel mid-side\n    - [ ] Generate noises (white, pink, and so forth) by inverse FFT of random frequencies with right slope\n    - [ ] Generate pink noise with a variation of the standard algorithm: Generate the random number that you need to update every sample anyway; now if it’s between 0 and 0.5, update octave 1; if it’s between 0.5 and 0.75 update octave 2, and so forth (this may be stochastic method)\n- [ ] Other topics to cover:\n    - [ ] Even when you’re clipping in the middle of a FX chain, or in a channel, there’s a chance that you won’t clip in the end, of somewhere in the pipeline there’s another thing that brings the gain down\n        - [ ] That works because internally REAPER (and many other DAWs) use 64 bits per sample, as opposed to the 16/24/32 that you’d find in other places\n        - [ ] But it’s generally a bad idea to rely on this, because some effects don’t work as well when the input is clipping\n        - [ ] When writing JSFX, this means that sometimes your samples won’t be in the –1 - 1 range\n    - [ ] The notions of dB in different scales\n        - [ ] dBFS (Full scale)\n            - [ ] –∞ - 0\n            - [ ] DAWs\n        - [ ] dBSPL (Sound pressure levels)\n            - [ ] 0 - ∞\n        - [ ] VU\n            - [ ] Old hardware\n            - [ ] 0 is optimal operation level, which corresponds to around –18dBFS\n    - [ ] Planning laws\n\n\nMid panner https://youtu.be/upG1KaKExMY\n\n\n\n The first idea is a script that would open a dialog box in REAPER. In the dialogue box, you can enter a shortcut or simply paste a command ID, and in the first case, it would look for the command ID with that shortcut assigned to it, and in the second case it would just use the ID to generate a smart marker at edit cursor position. Currently there is an outboarder script that allows making a custom name and color marker, but all the modifications needs to be done by duplicating the script and editing values in the IDE, so I thought It'd be cool if there was a way of to have a dialog box basically kinda fill in those strings. That way it could be a hotkey or toolbar icon and it would quickly generate a bunch of action markers even by hotkey inputs.\n\n  It would be nice if there was a script in REAPER that would generate an ADR script from a list of item names. The studio I used to work in had a similar setup for Pro Tools, where you would make clip regions, and then export a text file from Pro Tools. It would have the start timecode and the name of the clip region, which you would then paste into an excel sheet, and it would generate a script based on that. I'll have to dig it up but basically let me know if any of this sounds like something you'd be interested in and we can keep communicating from there!\n\n\n   Basically it would be an action to write the volume/pan/pitch envelope of a track onto the items that are on the track. It's really useful in films cuz the sound editor usually doesn't do automation and the mixer does, so with this script, the sound designer can mix their own reaper project, and then in the end just write all of the automation to the items, and they can then just clear all the track envelopes and the project is ready to mix. \n\n It'll be useful for other people too cuz track envelopes have a lot more features overall, like latch preview (items have them but they're a pain and again, way fewer actions to toggle them etc.) and also track envelopes are more straightforward to assign to midi controllers than items (speaking of which, action to assign midi cc to \"selected items volume\" is useful too and I think that one doesn't exist either) but then writing all that to the item frees up the envelope lanes once again, and also items can then be freely position across tracks.\n\n\n Scripts/leafac_Explode multistream (multitrack) media file to new one-stream (one-track) media files.lua: copy name from original takes, just like we already copy the name from original tracks: Fotis Ky\n\n\n\n\n A delay plugin in which you can route anything into the feedback chain by using a non-causal loop in a sandwich of effects.\n\n\n\n\n\n\n\n\n\n-- Preferences for LeaFac's-OBS \u003c-\u003e Reaper integration\n-- Version 1.0 written by Meo-Ada Mespotine 17th of February 2021 - licensed under MIT-license\n\n\n-- TODO:\n--  Retina-Support missing\n--  Check settings-button is not functional yet(please include the code into CheckSettings() )\n--  Check tooltips if they are correct and have no typos.\n\n\n-- [[ Some Custom Settings ]]\n\n-- Default Window position and size:\n--    X and Y will be used the first time the preferences are opened\n--    when closing the prefs, the prefs remember the position of the window for next time\nWindowX     = 30 -- x-position\nWindowY     = 30 -- y-position\nWindowWidth = 400 -- width of the window\nWindowHeight= 339 -- height of the window\n\nToolTipWaitTime=30 -- the waittime-until tooltips are shown when hovering above them; 30~1 second\n\nYDefault=0          -- The Y-position of the first GUI-Element. So if you want to move all of them lower, raise this value\nXOffset=43          -- X-offset of the second element in the gui(usually text inputfields), so you can move the inputfields to the right together\n                    -- if an explanation-text becomes too long to be drawn\n\n\n-- [[ The following functions can be customized by you ]]\n\nfunction main()\n  -- This function manages all the drawing and positioning of the gui-elements.\n  -- If you need more gui-elements, simply add them into here.\n  -- All Gui-element-functions like DrawText(), InputText(), ManageCheckBox(), ManageButton() have\n  -- a description of their parameters included. Just go to the function-definitions and read their comments.\n  \n  -- Now, let's add the individual UI-elements\n  -- Header\n  Y=Y+10 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText(10, Y, \"LeaFac OBS - Preferences\", 85, \"\", 20) \n  \n  -- Address - text and inputbox\n  --  the length is linked to gfx.w, so it always uses the whole window for display\n  Y=Y+30 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Address:\", 0, \"The address to OBS-websocket.\\nMust be the same, as set in OBS -\u003e Tools -\u003e Websockets-serversettings.\\n\\nDefault is: localhost:4444\")\n  InputText(100+XOffset, Y, gfx.w-110-XOffset, \"LeaFac_OBS\", \"Address\", \"localhost:4444\", \"Enter Address to OBS\", \"Address\")\n    \n  -- Password - text and inputbox\n  --  the length is linked to gfx.w, so it always uses the whole window for display\n  Y=Y+21 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Password:\", 0, \"The password for your OBS-websocket connection.\\nMust be the same, as set in OBS -\u003e Tools -\u003e Websockets-serversettings.\\n\\nDefault is no password.\")\n  InputText(100+XOffset, Y, gfx.w-110-XOffset, \"LeaFac_OBS\", \"Password\", \"\", \"Enter Password\", \"Password\")\n  \n  -- Extension - text and inputbox\n  Y=Y+21 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Extension:\", 0, \"The extension of the recorded video, as set in OBS.\\n\\nDefault is: mkv.\")\n  InputText(100+XOffset, Y, 50, \"LeaFac_OBS\", \"Extension\", \"mkv\", \"Enter extension\", \"Extension\")\n  \n  -- Subfolder - text and inputbox\n  --  the length is linked to gfx.w, so it always uses the whole window for display\n  Y=Y+21 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Subfolder:\", 0, \"The subfolder within your project, in which the video-file shall be.\\n\\nDefault is none.\")\n  InputText(100+XOffset, Y, gfx.w-110-XOffset, \"LeaFac_OBS\", \"Subfolder\", \"\", \"Enter subfolder\", \"Subfolder\")\n  \n  -- Latency - text and inputbox\n  Y=Y+30 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Latency:\", 0, \"If you notice an offset between audio and video after the video got imported into Reaper, you can set the offset to compensate the latency here in ms.\\n\\nDefault is 0.\")\n  InputText(100+XOffset, Y, 50, \"LeaFac_OBS\", \"Latency\", \"0\", \"Enter latency\", \"Latency\", true)\n  \n  -- Execute Timeout - text and inputbox\n  Y=Y+21 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Execute Timeout:\", 0, \"The time to wait for a response of OBS, before an error-message will be shown.\\n\\nDefault is 5000 ms.\")\n  InputText(100+XOffset, Y, 50, \"LeaFac_OBS\", \"EXECUTE_TIMEOUT\", \"5000\", \"Enter extension\", \"Extension\", true)\n    \n  -- OBS Stop Recording Timeout - text and inputbox\n  Y=Y+21 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"Stop Rec Timeout:\", 0, \"\\n\\nDefault is 10.\")\n  InputText(100+XOffset, Y, 50, \"LeaFac_OBS\", \"OBS_STOP_RECORDING_TIMEOUT\", \"10\", \"Enter recording timeout\", \"Recording Timeout\", true)\n    \n  -- TrackName - text and inputbox\n  --  the length is linked to gfx.w, so it always uses the whole window for display\n  Y=Y+35 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  DrawText (10,  Y, \"TrackName:\", 0, \"The name of a track, into which the video is imported to.\\n\\nDefault is OBS.\")\n  InputText(100+XOffset, Y, gfx.w-110-XOffset, \"LeaFac_OBS\", \"TRACK_NAME\", \"OBS\", \"Enter Trackname\", \"Trackname\")\n  \n  -- alway create new track-text and checkbox\n  Y=Y+24 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  ManageCheckBox(100+XOffset-1, Y,   \"LeaFac_OBS\",              \"ALWAYS_CREATE_NEW_TRACK\", false)\n  DrawText      (125+XOffset,   Y+2, \"Always create new track\", 0, \"When checked, this will always create a new track when starting recording, so multiple files are always placed into new tracks. When unchecked, all files will be added to the same track.\\n\\nDefault is unchecked.\")\n    \n  \n  -- Check Settings and Done-buttons\n  --  these are linked to gfx.w(right side of the window) so they are always aligned to the right-side of the window\n  Y=Y+43 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  ManageButton(gfx.w-260, Y, \"Default Settings\", ResetSettings)\n  ManageButton(gfx.w-132, Y, \"Check Settings\",   CheckSettings)\n  Y=Y+29 -- This holds the position of the next ui-element. I simply add a value, so it stays relative to the one above it.\n  ManageButton(gfx.w-68, Y, \"Done\", QuitMe)\n  \n  \n  \n  -- make some mouse-management, run refresh the window again, until the window is closed, otherwise end script\n  -- leave it untouched\n  if Key~=-1 then OldCap2=gfx.mouse_cap\u00261 reaper.defer(RefreshWindow) end\nend\n\n\n\n-- [[ Custom Button functions ]]\n--\n-- here are some custom-functions used by the buttons.\n-- If you want to add additional buttons, add their accompanying functions in this section\n\nfunction CheckSettings()\n  -- Please put it in here the checking-mechanism for checking validity of connection.\n  -- use reaper.MB to output an error-message\n  reaper.MB(\"You need to add the check-settings-code into the function \\\"CheckSettings\\\" for this button to work, as you probably know better, how this works.\",\"Not yet implemented.\",0)\nend\n\nfunction ResetSettings()\n  -- This function resets all the settings to their defaults.\n  -- The settings are deleted, so the start/stop-recording-scripts need to check, if the setting exists, via GetExtState.\n  -- If GetExtState returns \"\", then use the default-value instead of the stored one.\n  if reaper.MB(\"Do you really want to reset your settings to the factory default-settings?\", \"Reset to defaults?\", 4)==6 then\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"Address\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"Password\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"Extension\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"Latency\", true) \n    reaper.DeleteExtState(\"LeaFac_OBS\", \"TRACK_NAME\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"ALWAYS_CREATE_NEW_TRACK\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"Subfolder\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"EXECUTE_TIMEOUT\", true)\n    reaper.DeleteExtState(\"LeaFac_OBS\", \"OBS_STOP_RECORDING_TIMEOUT\", true)\n  end\nend\n\nfunction QuitMe() \n  -- this function quits the script\n  dockstate, x,y,w,h=gfx.dock(-1,0,0,0,0)\n  --reaper.MB(x..\" \"..y..\"\\n\"..x2..\" \"..y2, \"\",0)\n  reaper.SetExtState(\"LeaFac_OBS\", \"prefs_x\", x, true)\n  reaper.SetExtState(\"LeaFac_OBS\", \"prefs_y\", y, true)\n  \n  gfx.quit()\nend\n\n\n\n-- [[ GUI-element-functions ]]\n\n-- here come the GUI-element functions. If you want to add another GUI-element into the preferences, just use one of these\n-- functions to do it.\n-- For those elements who can store stuff, you can set a section and key, into which the settings will be stored.\n-- They are then stored as ExtStates using SetExtState. To retrieve these settings, use GetExtState in your script.\n-- As \"section\" I used \"LeaFac_OBS\", and as key the name of the setting.\n-- Set some of the values and have a look into reaper-extstate.ini to see, how this looks like. You quickly get the idea.\n--\n-- Important: it will NOT store them, when nothing has been clicked. So you need to have default-values in your\n--            script, in case the user hasn't set any settings yet(in that case, GetExtState returns \"\"\n--            The values returned by GetExtState are always strings, so integers and such must be converted\n--            using integervalue=tonumber(value)\n\n-- Now, all functions and an explanation, what they do, how and where they store the settings.\n-- Also an explanation of the parameters.\n\nfunction ManageCheckBox(x, y, section, key, default)\n  -- This adds a checkbox. If that checkbox is clicked it will store a 1 into the extstate.\n  -- Parameters:\n  --            integer x - the x-position in pixels\n  --            integer y - the x-position in pixels\n  --            string section - the section, in which it's statechanges shall be stored(for instance LeaFac_OBS)\n  --            string key - an explanatory name for the key, in which the value will be stored.\n  --            boolean default - if no value is set until now, you can set this to a default in the checkbox to true(checked) or false(unchecked)\n  \n  local value=tonumber(reaper.GetExtState(section, key))\n  if clickstate==true and \n    gfx.mouse_x\u003e=x and gfx.mouse_x\u003c=x+20 and \n    gfx.mouse_y\u003e=y and gfx.mouse_y\u003c=y+20\n    then\n    if value==1 then\n      reaper.SetExtState(section, key, 0, true)\n      value=0\n    else\n      reaper.SetExtState(section, key, 1, true)\n      value=1\n    end\n  end\n  if default==false then default=0 else default=1 end\n  if value==nil then value=tonumber(default)  end\n  \n  gfx.set(0.8)\n  gfx.rect(x,y,20,20,0)\n  gfx.set(1,1,0)\n  if value==1 then gfx.rect(x+5, y+5, 10, 10, 1) end\nend\n\n\n\nfunction DrawText(x, y, text, mode, tooltip, size)\n  -- This displays a text and optionally allows showing a tooltip\n  -- Parameters:\n  --            integer x - the x-position in pixels\n  --            integer y - the x-position in pixels\n  --            string text - the text, that shall be shown\n  --            integer mode - refer gfx.mode for this value\n  --            string tooltip - when mouse hovers over text, show this as a tooltip\n  --            integer size - the font-size of the text; omit it to use the default one\n  --                         - remember, that fontsize on Mac is not the same on Windows.\n  --                         - which means, these must be set for both systems individually.\n if size==nil then \n  size=17\n  if not string.match( reaper.GetOS(), \"Win\") then\n     size = math.floor(size * 0.8)\n   end\n end\n if mode==nil then mode=0 end\n  gfx.set(0.8)\n  gfx.x=x\n  gfx.y=y\n  gfx.setfont(1, \"Arial\", size, mode)\n  gfx.drawstr(text)\n  gfx.setfont(1, \"Arial\", size, 0)\n  \n  if tooltip~=nil and ShowToolTip==true and ToolTipShown==false and \n    gfx.mouse_x\u003e=x and gfx.mouse_x\u003c=x+gfx.measurestr(text) and\n    gfx.mouse_y\u003e=y and gfx.mouse_y\u003c=y+gfx.texth then\n    ALLAAAA=os.date()\n    local X,Y=reaper.GetMousePosition()\n    reaper.TrackCtl_SetToolTip(tooltip, X+15, Y, true) \n    ToolTipShown=true\n  end\n  mode=oldmode\nend\n\nfunction InputText(x, y, width, section, key, default, InputTitle, InputText, onlynumbers)\n  -- This adds a textbox, which, when clicked, opens an input-dialog, into which one can enter the new value.\n  -- This value will then be stored as extstate.\n  -- If the text exceeds the size of the inputbox, it will be truncated visually. To show the entire text,\n  -- just hover above the inputbox and it will show it via tooltip.\n  \n  -- Parameters:\n  --            integer x - the x-position in pixels\n  --            integer y - the x-position in pixels\n  --            integer width - the shown width of the text-box; shown text might be t\n  --            string section - the section, in which it's statechanges shall be stored(for instance LeaFac_OBS)\n  --            string key - an explanatory name for the key, in which the value will be stored.\n  --            string default - if no value is set until now, you can set this to a default in the inputfield\n  --            string InputTitle - this will influence the title of the input-dialog\n  --            string InputText - this will influence the text, next to the input-box in the input-dialog\n  --            boolean onlynumbers - true, allows only entering numbers; false or nil, any text can be entered\n\n  local value=reaper.GetExtState(section, key)\n  if value==\"\" then value=default end\n  if gfx.mouse_x\u003e=x and gfx.mouse_x\u003c=gfx.w-10 and \n     gfx.mouse_y\u003e=y and gfx.mouse_y\u003c=y+20\n    then\n    if clickstate==true then\n      retval, enteredtext = reaper.GetUserInputs(InputTitle, 1, InputText..\",extrawidth=150\", value)\n      if retval==true then\n        if onlynumbers==true and tonumber(enteredtext)==nil then\n          reaper.MB(\"Only numbers can be entered in this field!\", \"Only numbers\", 0)\n          enteredtext=value\n        else\n          reaper.SetExtState(section, key, enteredtext, true)\n        end\n        value=enteredtext\n      end\n    else\n      if ShowToolTip==true and ToolTipShown==false then\n        local X,Y = reaper.GetMousePosition()\n        reaper.TrackCtl_SetToolTip(value, X+10, Y, true)\n        ToolTipShown=true\n      end\n    end\n  end\n  gfx.x=x+2\n  gfx.y=y+1\n  gfx.set(0.17)\n  gfx.rect(x-2,y,width,gfx.texth+1,1)\n  gfx.set(0.3)\n  gfx.rect(x,y+2,width,gfx.texth+1,0)\n  gfx.set(0.8)\n  gfx.rect(x-1,y+1,width,gfx.texth+1,0)\n  gfx.drawstr(value, 0, width+x, y+gfx.texth+1)\nend\n\nfunction ManageButton(x, y, buttontext, functioncall)\n  -- This adds a button, which can be clicked on.\n  -- As you might want to have additional functionality associated with that button,\n  -- you can write a function that does, what you want. Then pass the name of the function\n  -- as parameter functioncall and this function will run it, everytime the button was clicked\n  \n  -- Parameters:\n  --            integer x - the x-position in pixels\n  --            integer y - the x-position in pixels\n  --            string buttontext - the text of the button\n  --            function functioncall - the name of the function that shall be called. Just as it is, NOT as string!\n  local clickoffset=0\n  local width=gfx.measurestr(buttontext)+20\n  if gfx.mouse_cap\u00261==1 and gfx.mouse_x\u003e=x and gfx.mouse_x\u003c=x+width and \n     gfx.mouse_y\u003e=y and gfx.mouse_y\u003c=y+20\n    then\n    clickoffset=2\n  end\n\n  gfx.set(0.8)\n  \n  local h=gfx.texth+4\n  local r=2\n  -- draw roundrectangle(code taken from Lokasenna's Gui Lib, inspired by mwe's EEL-sample\n  gfx.set(0)\n  x=x+clickoffset\n  y=y+clickoffset\n  -- Corners\n  gfx.circle(x + r,         y + r    , r, 1, aa)      -- top-left\n  gfx.circle(x + width - r, y + r    , r, 1, aa)      -- top-right\n  gfx.circle(x + width - r, y + h - r, r, 1, aa)      -- bottom-right\n  gfx.circle(x + r,         y + h - r, r, 1, aa)      -- bottom-left\n  -- Ends\n  gfx.rect(x, y + r, r, h - r * 2)\n  gfx.rect(x + width - r, y + r, r + 1, h - r * 2)\n  -- Body + sides\n  gfx.rect(x + r, y, width - r * 2, h + 1)\n  \n  gfx.set(0.3)\n  x=x+1\n  y=y+1\n  -- Corners\n  gfx.circle(x + r,         y + r    , r, 1, aa)      -- top-left\n  gfx.circle(x + width - r, y + r    , r, 1, aa)      -- top-right\n  gfx.circle(x + width - r, y + h - r, r, 1, aa)      -- bottom-right\n  gfx.circle(x + r,         y + h - r, r, 1, aa)      -- bottom-left\n  -- Ends\n  gfx.rect(x, y + r, r, h - r * 2)\n  gfx.rect(x + width - r, y + r, r + 1, h - r * 2)\n  -- Body + sides\n  gfx.rect(x + r, y, width - r * 2, h + 1)\n\n  gfx.set(0.3)\n  x=x-clickoffset-1\n  y=y-clickoffset-1\n  \n  gfx.x=x+clickoffset*2\n  gfx.y=y+clickoffset+2\n  gfx.set(0)\n  gfx.drawstr(buttontext, 1, width+x+2, y+gfx.texth+4)\n  gfx.x=x+clickoffset*2\n  gfx.y=y+clickoffset+3\n  gfx.set(0.8)\n  gfx.drawstr(buttontext, 1, width+x+3, y+gfx.texth+6)\n\n  if gfx.mouse_cap\u00261==0 and OldCap2==1 and \n     gfx.mouse_x\u003e=x and gfx.mouse_x\u003c=x+width and \n     gfx.mouse_y\u003e=y and gfx.mouse_y\u003c=y+20 then\n     functioncall()\n  end\nend  \n\n\n-- [[ Initialization of the GUI-Window and some management functions]]\n-- You can mostly ignore the following functions, as they do some management here and there.\n-- So best is to leave them untouched.\n\n-- Initialize window and some global variables; leave them untouched\nVal=tonumber(reaper.GetExtState(\"LeaFac_OBS\", \"prefs_x\")) if Val~=nil then WindowX=Val end\nVal=tonumber(reaper.GetExtState(\"LeaFac_OBS\", \"prefs_y\")) if Val~=nil then WindowY=Val end\n\ngfx.init(\"LeaFac-OBS - Preferences\", WindowWidth, WindowHeight, 0, WindowX, WindowY)\nOldCap=0\nOldCap2=0\nsize=17\nif not string.match( reaper.GetOS(), \"Win\") then\n   -- font-size-management on non-Windows-systems, so the font is properly scaled\n   size = math.floor(size * 0.8)\nend\ngfx.setfont(1, \"Arial\", size, 0)\nToolTipCount=0\n\nfunction GetMouseState()\n  -- This does some mouse-stuff checking and the measuring ot the waittime, until tooltips are shown.\n  -- Just leave it as it is.\n  if OldMouseX==gfx.mouse_x and OldMouseY==gfx.mouse_y then \n    ToolTipCount=ToolTipCount+1\n    if ToolTipCount\u003eToolTipWaitTime then\n      ShowToolTip=true\n    else\n      ShowToolTip=false\n      ToolTipShown=false\n    end\n  else\n    ToolTipCount=0\n    reaper.TrackCtl_SetToolTip(\"\", 1, 1, true) \n  end\n  OldMouseX=gfx.mouse_x\n  OldMouseY=gfx.mouse_y\n\n  -- this returns, if the left-mousebutton has been clicked.\n  -- this is used in the main-function. Just leave it there and use its returnvalue, where needed.\n  if gfx.mouse_cap\u00261==1 and OldCap==0 then OldCap=1 return true end\n  if gfx.mouse_cap\u00261==0 and OldCap==1 then OldCap=0 end\n\n  return false\nend\n\nfunction RefreshWindow()\n  -- In here, I reset the window for further drawing operations, as well as checking, whether the user hit\n  -- enter or esc to close the window.\n  -- Just leave it as it is.\n  Y=YDefault\n  gfx.set(0.1)\n  gfx.rect(0,0, gfx.w, gfx.h)\n  clickstate=GetMouseState() -- get the clickstate, as needed by several functions\n  Key=gfx.getchar()\n  if Key==13 or Key==27 then QuitMe() end\n  main()\nend\n\nRefreshWindow() -- start the magic\n\n--\u003e\n\n\u003ch1 align=\"center\"\u003eLeandro Facchinetti’s REAPER Effects and Scripts\u003c/h1\u003e\n\n## How to Install\n\nAdd the following repository to [ReaPack](https://reapack.com):\n\n```\nhttps://github.com/leafac/reaper/raw/main/index.xml\n```\n\nIf you’re new to this, check [this video](https://youtu.be/gVbMbqGSB7E) (in particular, 11:26).\n\n## Multicam Editing\n\n\u003ch3 align=\"center\"\u003e\u003ca href=\"https://youtu.be/1BvuRgKNnqc\"\u003eWatch the video with a demonstration and instructions!\u003c/a\u003e\u003c/h3\u003e\n\nInstall the FX Chains:\n\n- [`FXChains/leafac_Video processor - Multicam - Preview.RfxChain`](FXChains/leafac_Video%20processor%20-%20Multicam%20-%20Preview.RfxChain)\n- [`FXChains/leafac_Video processor - Multicam - Selector.RfxChain`](FXChains/leafac_Video%20processor%20-%20Multicam%20-%20Selector.RfxChain)\n\n## Automixer\n\n\u003ch3 align=\"center\"\u003eWatch the videos with demonstrations and instructions!\u003c/h3\u003e\n\n- [Quick start](https://youtu.be/hSnk6ueU3hQ).\n- [Main features](https://youtu.be/qi1jQcIaOxo).\n- [Automixer video editor](https://youtu.be/aEvO3ufOqvY).\n\nSee also:\n\n- [Code review](https://youtu.be/7V2dGYGtV-8).\n- [Example projects](https://archive.org/download/leafac/leafac_Automixer%20Examples.zip).\n- [Automixer video editor FX Chain](FXChains/leafac_Video%20processor%20-%20Automixer.RfxChain).\n\nEven more information:\n\n- Alternatives:\n  - [The original REAPER JSFX extension on which this is based](https://forum.cockos.com/showthread.php?t=173289). It doesn’t have as many features (for example, track priorities), and is more prone to bugs because it relies on inter-plugin communication. But it’s easier to setup for simple cases and it supports projects with massive numbers of tracks, while this modification is limited by the 64 channels per track that REAPER offers.\n  - [TBProAudio’s AMM Automatic Microphone Mixer](https://www.tb-software.com/TBProAudio/amm.html). It’s limited to 16 stereo tracks and requires a setup with transmitters and receiver plugin instances, which limits the possibility of having independent groups of automixed tracks.\n  - [WTAUTOMIXER](https://www.wtautomixer.com).\n  - [Waves Dan Dugan Automixer Plugin](https://www.waves.com/plugins/dugan-automixer). This only works on Waves MultiRack system, not as a regular audio plugin.\n- Papers on Automixers:\n  - [Real-Time Multi-Track Mixing For Live Performance](https://zenodo.org/record/2550903#.X43irC9h01I).\n  - [Automatic Microphone Mixer White Paper](https://jp.yamaha.com/files/download/other_assets/7/329527/Automixer_WhitePaper_en.pdf).\n  - [The original patent](https://worldwide.espacenet.com/publicationDetails/originalDocument?CC=US\u0026NR=3992584A\u0026KC=A\u0026FT=D\u0026ND=\u0026date=19761116\u0026DB=\u0026locale=en_EP). This patent has expired, and since then the Automixer is also known as a **gain sharing algorithm**.\n  - [An article explaining how to Automixer works on a high level](http://www.protechaudio.com/products/PDFFiles/DuganMixing.pdf).\n- How I learned about Automixing:\n  - [Podigy’s Complete Guide to Podcast Editing](https://podigy.co/podcast-editing-guide/). This where I first read about Automixing and became obsessed with the topic.\n  - [An interview on the Podcast Engineering School with Dan Dugan, the inventor of the Automixer](https://podcastengineeringschool.com/dan-dugan-inventor-of-the-automatic-microphone-mixer-pes-101/).\n\n## Third-Party ReaPack Redistribution\n\n| Extension                                                                                               | Author                                                                        | Repository Index URL                                                          |\n| ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |\n| **All**                                                                                                 |                                                                               | `https://github.com/leafac/reaper/raw/main/ThirdParty/index.xml`            |\n| [SWS](http://sws-extension.org)                                                                         | [The SWS Contributors](https://github.com/reaper-oss/sws/graphs/contributors) | `https://github.com/leafac/reaper/raw/main/ThirdParty/SWS/index.xml`        |\n| [ReEQ and ReSpectrum](https://forum.cockos.com/showthread.php?t=213501)                                 | [nitsuj](https://forum.cockos.com/member.php?u=121300)                        | `https://github.com/leafac/reaper/raw/main/ThirdParty/ReEQ/index.xml`       |\n| [ABLevelMatching, AutoGainStaging, and EBUR128LM](https://www.tb-software.com/TBProAudio/download.html) | [TBProAudio](https://www.tb-software.com/TBProAudio/index.html)               | `https://github.com/leafac/reaper/raw/main/ThirdParty/TBProAudio/index.xml` |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafac%2Freaper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleafac%2Freaper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafac%2Freaper/lists"}