Sunday, March 30, 2025

you don't need a fancy sampler

in fl studio i would use fruity soundfont player for multi sampled insturnents and drum kits. Sometimes i create layers, set and split children to play them from 1 midi lane (newer fl finally got around to letting you include samplers in patcher so you can use vfx splitter or set up key zone splits).

  • in settings set omnipreview to 1

this lets you play everything in tbe channel rack at once!

Saturday, March 29, 2025

mid side

mid is the sum divided by 2
side is the difference divided by 2

mid = (left + right) / 2
side = (left - right) / 2

today I learned you can create envelopes by dragging audio files from the browser or from edison.
intermodulation distortion
clicking on automation clips (not in the old fl) you can import audio and use the peaks to create automation clips
my old way was using the fruity peak controller
you can also drag audio into fruity love filter and the envelope controller.
I've been into using ctrl t (typing keys), ctrl e (step edit mode) to enter in triads.
then using what I learned about the harmonic series to create spread voicings
was watching a flux pavillion against the clock where he was using just a saw wave in massive but it was the way he arranged it that made it sound huge.
being infront of a piano its easy to reach for those spread voicings but clicking it is quite a hassle untill I learned this way.
ctrl up down, to octave shift
shift up down, for semitones
right click edit events
alt o creates an lfo do this for each time selection
you can set the rate synced to the tempo and have it interpolate between 2 ranges
like 16th note slowing down to eighth and ramping down the intensity
then you can export the events data to an automation clip

Friday, March 28, 2025

g melodic minor might make more sense than c major (harmonic series)

Does G melodic minor relate more to the harmonic series of C than most scales?

The harmonic series of C refers to the overtones generated when you play a fundamental C. These overtones are naturally occurring and help define what we perceive as consonance. The harmonic series of C includes notes like:

C  (1st harmonic, fundamental)
C  (2nd harmonic, octave)
G  (3rd harmonic, perfect fifth)
C  (4th harmonic)
E  (5th harmonic, major third)
G  (6th harmonic)
Bb (7th harmonic, but it’s flatter than equal temperament)
C  (8th harmonic)
D  (9th harmonic)
E  (10th harmonic)
F# (11th harmonic, sharper than in equal temperament)
G  (12th harmonic)
A  (13th harmonic)
Bb (14th harmonic, again a bit flat)
B  (15th harmonic)
C  (16th harmonic)

Now, the G melodic minor scale is:

G - A - Bb - C - D - E - F#

Compare this to the harmonic series of C:

It shares G, C, E, A, Bb, F#, and even D appears early in the series.

The G melodic minor scale includes several of the prominent early overtones from the harmonic series of C, particularly:

G   (3rd, 6th, 12th harmonics)
E   (5th, 10th)
Bb  (7th and 14th, though slightly off)
C   (1st, 2nd, 4th, 8th, 16th)
D   (9th)
F#  (11th harmonic-ish — although not exact in equal temperament)

Conclusion

Yes, G melodic minor does align more closely with the harmonic series of C than many other scales — especially because it includes many partials (or close approximations of them), including the somewhat oddballs like F# (11th) and Bb (7th/14th), which are rare in most diatonic scales.

So in a way, G melodic minor “echoes” the color of the C harmonic series more than, say, a C major scale does. It's an excellent observation if you're exploring spectral relationships or tuning theory.

Monday, March 24, 2025

Tutorial: Tempo Math in Reaper

Let's say you have a song that is originally 124 BPM (beats per minute), and you drag it into Reaper, which has the default project tempo set to 120 BPM. You then change the project rate to 200 BPM. Now, the question is: What is the new tempo of the song in this new project rate?

Step 1: Calculate the percentage change between the original project tempo (120 BPM) and the new project tempo (200 BPM).

When you change the project tempo, you're effectively stretching or compressing the song to match the new tempo. To understand how much this changes the song’s tempo, you first need to find the percentage change between the project tempos.

The formula for calculating the percentage change is:

Percentage change = ((New Tempo - Original Tempo) / Original Tempo) * 100

Using the values provided:

Percentage change = ((200 - 120) / 120) * 100
= (80 / 120) * 100
= 66.67%

So, the project tempo has increased by 66.67% when the rate changes from 120 BPM to 200 BPM.

Step 2: Apply the percentage change to the original song tempo.

Now that we know the project rate increased by 66.67%, we can use this same percentage to adjust the original song tempo. The formula to apply the percentage increase to the original tempo is:

New Song Tempo = Original Song Tempo * (1 + (Percentage Change / 100))

Substituting the values:

New Song Tempo = 124 * (1 + (66.67 / 100))
= 124 * 1.6667
= 206.67 BPM

So, after adjusting the project rate to 200 BPM, the new tempo of the song is approximately 206.67 BPM.

Conclusion

By understanding how the project rate affects the tempo, you can calculate how much the song’s speed will change when you adjust the project tempo in Reaper. In this case, with a project rate change from 120 BPM to 200 BPM, the original song tempo of 124 BPM increases to approximately 206.67 BPM.

Friday, March 14, 2025

getting a-shell mini setup again

pkg install nnn (file browser)
mkdir -p ~/Documents/.vim/pack/bweew/start
lg2 clone nerdtree, vimwiki gruvbox, vim-orgmode

  • use the pickFolder command to set bookmarks outside of the sandbox
  • z command jumps to those bookmarks
let g:vimwiki_list = [{'path' : '~/Documents/vimwiki/'}]

add that to your .vimrc so vimwiki can work properly

fix linux mint keybindings clashing with everything

window manager tweaks, key used to grab windows ALT set it to none
in settings under keyboard:
alt super s = orca (most annoying thing ever its the first thing im going to remove I don't need to. it doesn't clash with anything I can think of but i remember it being really annoying and wasted a bunch of my time trying to figure out how to turn it off last time
xfce-app finder = alt f3
xfce-app fiinder collapsed = alt f2
xfce-popup-applicationsmenu = alt f1
xfce4-popup-whiskermenu = super L
xfdesktop--menu = ctrl esc
under window manager:
window operations menu = alt space
cycle windows alt tab / shift alt tab
close window = alt f4
toggle above = alt f12
toggle fulscreen = alt f11
workspaces = ctrl alt up/down/left/right
switch workspaces ctrl + f# ctrl f3 = space 3 etc..

Thursday, March 13, 2025

bunch of old vsts as dlls

was looking for a plugin called mda detune that was simple and sounded great found it on archive.org no installers needed from archive

Wednesday, March 12, 2025

saturating highs before lows

cool mixing trick from sage audio.

  • use a shelf eq to tilt down the low end before running it through distortion then reverse it after.
  • this preserves the bass from getting blown out

It's similar to how compressors that have a high-pass filter built into the detection circuit before the threshold to prevent pumping.

tal use (ultra simple eq) is one option its a free tilt eq

Friday, March 7, 2025

clean amps

softamp fm25 - axp
softamp gt

these delays by arc dev noise industries are nice

dropbox link

the guy who made that plugin makes folk dub shoegaze as terminal sound system

a beautiful machine
antisound.net
terminal soundsystems website

My top picks lately
cyclotron, et-301, dubb box, quilcom bfp, madshifta by tobybear, synthscience freezechamber, the oli larkin ones like gatecomb, the demo of endless series

tbt sample reducer- I like this one

Thursday, March 6, 2025

wohlstand opl3 bank editor

opl3 bank editor
vinyl goddess
I want the bass patch from lvl 1 crush. cant do anything with vgm files.(plogue portasound could but hasn't been ported to linux yet) disco dsp opl loads sbi files. i think i could use opl3 bank editor to convert .snd files to work and even use it in adlib tracker.

flangers, binaural, ringmod, saturation, compressors

lisp de-esser - sleepy time dsp
et-200 bbd delay
wah bundle
decimator - toby bear
formant filter - oli larkin
se64
auto talent
stepcomb
gatecomb
falseFI
faranear
rp-pan - panner doppler
spatializer - hrtf binaural by blue lab audio
stereo width - blue lab audio
stc-3 raz audio(looks like blue lab one above)
multiband stereo faker - klanglabs
anaglyph 3d binaural spatializer
sjoe dualband stereo enhancer - terrywest
binaural sim - gregjazz
ms - terry west
rs rotothree leslie rotary
brandulator modulated comb filters
dd flanger
syncersoft flanger(bass landscapes)
IO ring mod - b serrano
madring ring mod - novaflash
nasty DLA - vos
timewarp vibrato
adam monroe tremolo
flanger box - synthscience
bfp barberpole flanger - quilcom
gt ringmod - glitchtek
cab enhancer - acme bargig
ts-1 - samsara cycle audio vinylizer
devicer
echomachine - plektron
vocalizer formant filter - aquest
vowel filter - tobybear
trileveler 2 sonic anomaly
sn01-G vca bus compressor - senderspike
sl63x - smacklabs
reacomp
modern deathcore distressor clone - antress
devils compressor
dynamic freq lim - sir sicksik (mb transient shaping/ dyn eq)

Sunday, March 2, 2025

FL Maximus compression envelopes

this really helps you understand how this plugin works.

Wednesday, February 26, 2025

sending midi cc 64 on press and cc 65 when held for 1 second - piano sustain pedal midi scripting

For use in Reapers super 8 looper. Experimented with using on release instead of on press (like in loopy pro) but the travel distance of this piano sustain pedal is too large to be accurate so I had to remove my double and triple tap functions, still awesome being able to double your midi inputs for 0$ was hoping to get all the functions mapped though.. looking at the m vave chocolate foot switch though looks pretty cool for 50$


import time
import rtmidi
from rtmidi.midiconstants import CONTROL_CHANGE

# Configuration - Customized for single pedal operation
SUSTAIN_CC = 64          # Default sustain pedal CC - Used for both functions
RECORD_TOGGLE_CC = 64    # Record/Play/Overdub (same as sustain)
CLEAR_LOOP_CC = 65       # Clear loop CC to be triggered by holding sustain

MIDI_CHANNEL = 0         # MIDI channel (0-15)
HOLD_THRESHOLD = 1.0     # Time in seconds required to hold sustain to clear loop

class LooperPedalController:
    def __init__(self):
        # Set up MIDI input/output
        self.midi_in = rtmidi.MidiIn()
        self.midi_out = rtmidi.MidiOut()
        
        # State variables
        self.is_recording = False
        self.is_playing = False
        self.pedal_down = False
        self.press_start_time = 0
        self.action_triggered = False
        
        self.setup_midi()
        
    def setup_midi(self):
        # List available ports
        in_ports = self.midi_in.get_ports()
        out_ports = self.midi_out.get_ports()
        
        print("Available MIDI input ports:")
        for i, port in enumerate(in_ports):
            print(f"  {i}: {port}")
            
        print("Available MIDI output ports:")
        for i, port in enumerate(out_ports):
            print(f"  {i}: {port}")
        
        # Let user select ports
        in_port = int(input("Select MIDI input port number: "))
        out_port = int(input("Select MIDI output port number: "))
        
        # Open ports
        self.midi_in.open_port(in_port)
        self.midi_out.open_port(out_port)
        
        # Set callback
        self.midi_in.set_callback(self.midi_callback)
        
    def midi_callback(self, event, data=None):
        message, delta_time = event
        
        # Process Control Change messages for the sustain pedal
        if len(message) == 3 and message[0] == CONTROL_CHANGE | MIDI_CHANNEL and message[1] == SUSTAIN_CC:
            value = message[2]
            current_time = time.time()
            
            if value >= 64:  # Pedal down
                self.handle_pedal_down(current_time)
            else:  # Pedal up
                self.handle_pedal_up(current_time)
    
    def handle_pedal_down(self, current_time):
        # Record when the pedal was pressed
        self.press_start_time = current_time
        self.pedal_down = True
        self.action_triggered = False
        
    def handle_pedal_up(self, current_time):
        duration = current_time - self.press_start_time
        self.pedal_down = False
        
        # If action was already triggered (by hold), do nothing more
        if self.action_triggered:
            return
            
        # If pedal was pressed briefly (not held), trigger record/play/overdub
        if duration < HOLD_THRESHOLD:
            self.handle_record_toggle()
    
    def handle_record_toggle(self):
        # Toggle between record, play, and overdub
        print("Quick press - Record/Play/Overdub toggle")
        self.send_cc(RECORD_TOGGLE_CC, 127)
        time.sleep(0.05)
        self.send_cc(RECORD_TOGGLE_CC, 0)
        
        # Update internal state (for display purposes)
        if not self.is_recording and not self.is_playing:
            self.is_recording = True
            print("State: Recording")
        elif self.is_recording:
            self.is_recording = False
            self.is_playing = True
            print("State: Playing")
        else:
            self.is_recording = True
            print("State: Overdubbing")
    
    def handle_clear_loop(self):
        print("Hold detected - Clearing loop (sending CC 65)")
        self.send_cc(CLEAR_LOOP_CC, 127)
        time.sleep(0.05)
        self.send_cc(CLEAR_LOOP_CC, 0)
        
        # Update internal state
        self.is_recording = False
        self.is_playing = False
        print("State: Cleared")
        self.action_triggered = True
        
    def send_cc(self, cc_number, value):
        message = [CONTROL_CHANGE | MIDI_CHANNEL, cc_number, value]
        self.midi_out.send_message(message)
    
    def run(self):
        print("\n=== Single Pedal Looper Controller ===")
        print(f"- Quick press CC {SUSTAIN_CC}: Record/Play/Overdub")
        print(f"- Hold CC {SUSTAIN_CC} for {HOLD_THRESHOLD}+ sec: Clear loop (sends CC {CLEAR_LOOP_CC})")
        print("=====================================\n")
        print("Current state: Stopped")
        
        try:
            # Keep the script running
            while True:
                time.sleep(0.05)  # Check frequently for responsive hold detection
                
                # Check for hold while pedal is down
                if self.pedal_down and not self.action_triggered:
                    current_time = time.time()
                    if current_time - self.press_start_time >= HOLD_THRESHOLD:
                        self.handle_clear_loop()
                        
        except KeyboardInterrupt:
            print("Exiting...")

if __name__ == "__main__":
    controller = LooperPedalController()
    controller.run()

Tuesday, February 25, 2025

fix i3 window focus

this has been bugging me forever. When I would try to play synths using the computers built in keyboard in renoise the window focus would steal keyboard input. add this to your i3 config to disable.


focus_follows_mouse yes|no

Saturday, February 22, 2025

4op to dx7 conversion project

I was looking for 2 op fm patches similar to the adlib soundblaster or my pss170 and trying to see if anybody converted the sysex to dx7 format and came across this project. 4op2dx7
super stoked they have the fb01!!! no longer need to use deflemasks fb01 patches. I wanted to like it. Any tracker that doesn't have a hot key to jump to next note/ cyclic shift and play from line is too tedious. I used to have to do a work around where I would route midi from fl and use pulse audios loopback to re sample it in audacity.

Friday, February 21, 2025

python to send midi ccs using usb snes gampad

super 8 preset and logitech f310 to cc mapping

instead of starting on cc 64 I started mapping from cc65 so I could use my piano sustain pedal to trigger loops and use the dpad to select the loops.
x doubles, a halves the length.
the middle guide (logitech) button dumps the loops to the timeline (add to project)
L button kills all the loops

Originally I did it with this 2$ ali express gamepad, later I wanted to get it working with this logitech ps1 style controller that has more buttons (more possibilities).

dropbox link to snes-midicc.py

Using It within Super 8

my super 8 cc mapping

import pygame
import rtmidi
import time
import sys

def initialize_midi():
    midi_out = rtmidi.MidiOut()
    available_ports = midi_out.get_ports()
    
    if not available_ports:
        print("No MIDI output ports found. Creating virtual port 'Gamepad MIDI'...")
        midi_out.open_virtual_port("Gamepad MIDI")
    else:
        print("Available MIDI ports:", available_ports)
        midi_out.open_port(0)
        print(f"Connected to: {available_ports[0]}")
    
    return midi_out

def initialize_joystick():
    pygame.init()
    pygame.joystick.init()
    
    if pygame.joystick.get_count() == 0:
        print("No gamepad detected!")
        sys.exit(1)
    
    joystick = pygame.joystick.Joystick(0)
    joystick.init()
    print(f"Detected gamepad: {joystick.get_name()}")
    return joystick

def main():
    midi_out = initialize_midi()
    joystick = initialize_joystick()
    
    button_states = {
        'left': False,
        'right': False,
        'up': False,
        'down': False
    }
    
    prev_buttons = [False] * joystick.get_numbuttons()
    
    print("Gamepad to MIDI mapper running. Press Ctrl+C to exit.")
    
    try:
        while True:
            for event in pygame.event.get():
                if event.type == pygame.JOYAXISMOTION:
                    if event.axis == 0:  # Left/Right
                        if event.value < -0.5 and not button_states['left']:
                            midi_out.send_message([0xB0, 64, 127])
                            button_states['left'] = True
                        elif event.value > -0.5 and button_states['left']:
                            midi_out.send_message([0xB0, 64, 0])
                            button_states['left'] = False
                            
                        if event.value > 0.5 and not button_states['right']:
                            midi_out.send_message([0xB0, 66, 127])
                            button_states['right'] = True
                        elif event.value < 0.5 and button_states['right']:
                            midi_out.send_message([0xB0, 66, 0])
                            button_states['right'] = False
                            
                    elif event.axis == 1:  # Up/Down
                        if event.value < -0.5 and not button_states['up']:
                            midi_out.send_message([0xB0, 65, 127])
                            button_states['up'] = True
                        elif event.value > -0.5 and button_states['up']:
                            midi_out.send_message([0xB0, 65, 0])
                            button_states['up'] = False
                            
                        if event.value > 0.5 and not button_states['down']:
                            midi_out.send_message([0xB0, 67, 127])
                            button_states['down'] = True
                        elif event.value < 0.5 and button_states['down']:
                            midi_out.send_message([0xB0, 67, 0])
                            button_states['down'] = False
                
                elif event.type == pygame.JOYBUTTONDOWN:
                    button_num = event.button
                    cc_number = 68 + button_num
                    midi_out.send_message([0xB0, cc_number, 127])
                    prev_buttons[button_num] = True
                    
                elif event.type == pygame.JOYBUTTONUP:
                    button_num = event.button
                    cc_number = 68 + button_num
                    midi_out.send_message([0xB0, cc_number, 0])
                    prev_buttons[button_num] = False
                    
            time.sleep(0.001)
            
    except KeyboardInterrupt:
        print("\nExiting...")
    finally:
        midi_out.close_port()
        pygame.quit()

if __name__ == "__main__":
    main()

original attempt

starts from cc64 and up
blue X = cc69
red A = cc70
yellow b = cc71
green y = cc72
select = cc77
start = cc78
Lt = cc73
Rt = cc74
up/down = 0/ 126
left/right = 0/126
I want to fix this so each direction sends on its own cc as momentary but this is fine for now


import pygame
import mido

MIDI_CC_START = 64

# Initialize MIDI output
midi_out = mido.open_output(mido.get_output_names()[0])

def send_midi_cc(cc, value):
    msg = mido.Message('control_change', control=cc, value=value)
    midi_out.send(msg)

def main():
    pygame.init()
    pygame.joystick.init()
    
    if pygame.joystick.get_count() == 0:
        print("No gamepad detected.")
        return

    joystick = pygame.joystick.Joystick(0)
    joystick.init()
    
    print(f"Gamepad detected: {joystick.get_name()}")
    print("Press Ctrl+C to exit.")
    
    prev_axes = [0] * joystick.get_numaxes()
    prev_buttons = [0] * joystick.get_numbuttons()
    prev_hats = [(0, 0)] * joystick.get_numhats()
    
    try:
        while True:
            pygame.event.pump()
            
            # Read axis values
            axes = [joystick.get_axis(i) for i in range(joystick.get_numaxes())]
            for i, value in enumerate(axes):
                if abs(value) > 0.1 and abs(value - prev_axes[i]) > 0.01:
                    send_midi_cc(MIDI_CC_START + i, int((value + 1) / 2 * 127))  # Normalize to 0-127
                prev_axes[i] = value
            
            # Read button states
            buttons = [joystick.get_button(i) for i in range(joystick.get_numbuttons())]
            for i, pressed in enumerate(buttons):
                cc_number = MIDI_CC_START + 5 + i  # Buttons start after D-pad CCs
                if pressed and not prev_buttons[i]:
                    send_midi_cc(cc_number, 127)
                elif not pressed and prev_buttons[i]:
                    send_midi_cc(cc_number, 0)
                prev_buttons[i] = pressed
            
            # Read hat (D-pad) states (momentary, dedicated CCs)
            hats = [joystick.get_hat(i) for i in range(joystick.get_numhats())]
            for i, hat in enumerate(hats):
                left_cc = 64
                up_cc = 65
                right_cc = 66
                down_cc = 67
                
                if hat[0] == -1 and prev_hats[i][0] != -1:
                    send_midi_cc(left_cc, 127)
                elif hat[0] != -1 and prev_hats[i][0] == -1:
                    send_midi_cc(left_cc, 0)
                
                if hat[1] == 1 and prev_hats[i][1] != 1:
                    send_midi_cc(up_cc, 127)
                elif hat[1] != 1 and prev_hats[i][1] == 1:
                    send_midi_cc(up_cc, 0)
                
                if hat[0] == 1 and prev_hats[i][0] != 1:
                    send_midi_cc(right_cc, 127)
                elif hat[0] != 1 and prev_hats[i][0] == 1:
                    send_midi_cc(right_cc, 0)
                
                if hat[1] == -1 and prev_hats[i][1] != -1:
                    send_midi_cc(down_cc, 127)
                elif hat[1] != -1 and prev_hats[i][1] == -1:
                    send_midi_cc(down_cc, 0)
                
                prev_hats[i] = hat
            
            pygame.time.wait(100)  # Reduce CPU usage
    except KeyboardInterrupt:
        print("\nExiting...")
    finally:
        joystick.quit()
        pygame.quit()
        midi_out.close()

if __name__ == "__main__":
    main()

ym2612 dexed presets

sega genesis style patches for your dx7

ym2612 dexed on github

cool they work on ios in kq dixie! probably would work in fm8, and sytrus too then. I love plogues chipsynth md for ym2612 sounds. I haven't been able to run it on linux though. I heard on bluesky in q2 they ate planning on having linux betas ready by then so I'm excited. In the meantime Ive been using the rom dumped patches converted to tfi format from aly james lab's fm drive that ported the fb-01 patches to the megadrive. that 4 op sound is close to the genesis sound. I prefer that curated palate of sounds to having the millions of dx7 nameless electric piano patches. those collections are cumbersome and wading through those is exhausting.

Theres a sweet spot with having presets. too many or too few is bad. it takes alot of time to make sounds from scratch when tou already have a musical idea in your head and you want to get it out. Thats why having presets can be usefull. Too many and it feels like your drowning. spend more time comparing sound a with sound b and get nowhere.

Thursday, February 20, 2025

spectral compressor vst

its kind of ott but with wayyy more bands. can be used like soothe. the github link