Python to .repatch (Mutator)

This forum is for developers of Rack Extensions to discuss the RE SDK, share code, and offer tips to other developers.
Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 15 Sep 2023

Ok so i've been busy creating a few python scripts that produce midi files and i would really love a simple way to process / convert them into pattern mutator repatch files so i thought i would reach out to any devs that might be able to assist or already have a script?

any help would be appreciated.

at the moment i'm guessing that the pattern_data_1 is a hex string but i could be well off, and would much rather not reinvent a wheel that might already be in someone's toolbox ;)

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 16 Sep 2023

so this is what am currently doing

Code: Select all

c:\Billy>python random_rhythm_generator.py --help
usage: random_rhythm_generator.py [-h] [--charset CHARSET] [--rotate-left] [--rotate-right]

optional arguments:
  -h, --help         show this help message and exit
  --charset CHARSET  character set to use for generating random rhythm
  --rotate-left      rotate the string to the left
  --rotate-right     rotate the string to the right


c:\Billy>python random_rhythm_generator.py
Todays Random Rhythm is : rsrhhhhmsssshrhh


c:\Billy>python musicrhythm.py --help
usage: musicrhythm.py [-h] [--bpm BPM] [--output OUTPUT] [--human] N

Generate a MIDI file from a list of notes with volume and rest.

positional arguments:
  N                a string of notes and reset (h=Hard, m=Medium, s=Soft r=Rest)

optional arguments:
  -h, --help       show this help message and exit
  --bpm BPM        the tempo in beats per minute (default: 120)
  --output OUTPUT  the name of the output MIDI file (default: output.mid)
  --human          adds slight random volume to the notes.


c:\Billy>python musicrhythm.py --bpm 90 --human rsrhhhhmsssshrhh
Sequence of notes:
Note 1: r, Onset: 0.3333333333333333, Duration: 0.3333333333333333
Note 2: s, Volume: 55, Onset: 0.6666666666666666, Duration: 0.3333333333333333
Note 3: r, Onset: 1.0, Duration: 0.3333333333333333
Note 4: h, Volume: 93, Onset: 1.3333333333333333, Duration: 0.3333333333333333
Note 5: h, Volume: 102, Onset: 1.6666666666666665, Duration: 0.3333333333333333
Note 6: h, Volume: 101, Onset: 1.9999999999999998, Duration: 0.3333333333333333
Note 7: h, Volume: 95, Onset: 2.333333333333333, Duration: 0.3333333333333333
Note 8: m, Volume: 78, Onset: 2.6666666666666665, Duration: 0.3333333333333333
Note 9: s, Volume: 49, Onset: 3.0, Duration: 0.3333333333333333
Note 10: s, Volume: 47, Onset: 3.3333333333333335, Duration: 0.3333333333333333
Note 11: s, Volume: 46, Onset: 3.666666666666667, Duration: 0.3333333333333333
Note 12: s, Volume: 53, Onset: 4.0, Duration: 0.3333333333333333
Note 13: h, Volume: 94, Onset: 4.333333333333333, Duration: 0.3333333333333333
Note 14: r, Onset: 4.666666666666666, Duration: 0.3333333333333333
Note 15: h, Volume: 94, Onset: 4.999999999999999, Duration: 0.3333333333333333
Note 16: h, Volume: 97, Onset: 5.333333333333332, Duration: 0.3333333333333333

midi files saved as : output.mid


c:\Billy>python random_rhythm_generator.py --rotate-left
Todays Random Rhythm is : rsmrmrsrrsrrshss
Rotation 1: smrmrsrrsrrshssr
Rotation 2: mrmrsrrsrrshssrs
Rotation 3: rmrsrrsrrshssrsm
Rotation 4: mrsrrsrrshssrsmr
Rotation 5: rsrrsrrshssrsmrm
Rotation 6: srrsrrshssrsmrmr
Rotation 7: rrsrrshssrsmrmrs
Rotation 8: rsrrshssrsmrmrsr
Rotation 9: srrshssrsmrmrsrr
Rotation 10: rrshssrsmrmrsrrs
Rotation 11: rshssrsmrmrsrrsr
Rotation 12: shssrsmrmrsrrsrr
Rotation 13: hssrsmrmrsrrsrrs
Rotation 14: ssrsmrmrsrrsrrsh
Rotation 15: srsmrmrsrrsrrshs

all I'm missing is a midi2repatch script...

if anyone is interested in the scripts let me know, and if anyone can provide some info on the next phase (midi2repatch.py) that would be great.

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 18 Sep 2023

ok so i've made some progress today but there are a few values i'm still not sure of and i know the props programmer love to have some fun so i'm wondering if maybe this value is just for giggles?
The 8380 twin flame symbolism is the act of satisfaction after you have met all your goals and dreams.

Code: Select all

            <Value property="pattern_data_1"  type="string" >
                020110013D67028380023D5E028380033D63028380043D35028380053D6A028380063D54028380073D36028380083D69028380093D300283800A3D2E0283800B3D610283800C3D320283800D3D670283800E3D340283800F3D43028380
            </Value>

Code: Select all

[Version?]0201 10 [16]=Steps 

position   | pitch+1     | velocity+1   | giggles
[1]	01     3D          [103] 67 	02 8380 
[2]	02     3D          [ 94] 5E  	02 8380 
[3]	03     3D          [ 99] 63  	02 8380 
[4]	04     3D          [ 53] 35  	02 8380 
[5]	05     3D          [106] 6A 	02 8380 
[6]	06     3D          [ 84] 54  	02 8380 
[7]	07     3D          [ 54] 36  	02 8380 
[8]	08     3D          [105] 69 	02 8380 
[9]	09     3D          [ 48] 30  	02 8380 
[10]	0A     3D          [ 46] 2E  	02 8380 
[11]	0B     3D          [ 97] 61  	02 8380 
[12]	0C     3D          [ 50] 32  	02 8380 
[13]	0D     3D          [103] 67 	02 8380 
[14]	0E     3D          [ 52] 34  	02 8380 
[15]	0F     3D          [ 67] 43  	02 8380



Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 18 Sep 2023

so i'm not 100% happy with the script but it can take a midi file and generate the string needed to make a PM.repatch file ;)
repatchfaker.png
it defo needs some more work, but I can basically generate files from my daily random rhythm generator :lol:
You do not have the required permissions to view the files attached to this post.

WaxTrax
Posts: 146
Joined: 16 Feb 2021

Post 18 Sep 2023

Very cool! :-)

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 21 Sep 2023

took a bit more time on this today and i'm getting closer ;)
repatchfaker2.png
I'm sure there's a simple solution but I've only just started with python - guess those that real know don't want to share so i will just keep plodding along
You do not have the required permissions to view the files attached to this post.

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 21 Sep 2023

so I finally got round to generating some more data for giggles - and it's no joke.....

Bar-1/128th.mid
Note 1 bar, time: 2.0
Note 1/2, time: 1.0
Note 1/4, time: 0.5
Note 1/8, time: 0.25
Note 1/16, time: 0.125
Note 1/32, time: 0.0625
Note 1/64, time: 0.03125
Note 1/128, time: 0.015625

decided this was enough data to play with for now - and time is an issue for me "would defo like some help"......

thankfully I'm only working in 16th so my scripts works, but it would be nice to extend / enhance this to work with other midi files.....

User avatar
Enlightenspeed
RE Developer
Posts: 1063
Joined: 03 Jan 2019

Post 22 Sep 2023

Billy+ wrote:
21 Sep 2023
guess those that real know don't want to share so i will just keep plodding along
As a first step, you should ask RS to give you the schema for the data strings, and permission to discuss the schema publicly.

Without that, it's difficult for other devs to participate; any of us could do it easily enough, but it involves a level of reverse engineering, which is legally dubious - not that it would be any real threat of course, this stuff is far too basic.

The moral issue is still there, however, so if you can get RS to publicly agree to this first, then other RE devs can help.

avasopht
Competition Winner
Posts: 3741
Joined: 16 Jan 2015

Post 22 Sep 2023

And I'll just add that they're all a lot more open than you might think!

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 22 Sep 2023

Enlightenspeed wrote:
22 Sep 2023
Billy+ wrote:
21 Sep 2023
guess those that real know don't want to share so i will just keep plodding along
As a first step, you should ask RS to give you the schema for the data strings, and permission to discuss the schema publicly.

Without that, it's difficult for other devs to participate; any of us could do it easily enough, but it involves a level of reverse engineering, which is legally dubious - not that it would be any real threat of course, this stuff is far too basic.

The moral issue is still there, however, so if you can get RS to publicly agree to this first, then other RE devs can help.
ah!

hadn't really considered that......

Sorry Reason Studios, if you see this thread would you possibly chip in and advise on any concerns :thumbup:
if you would rather the info be removed please say so.
if however you're cool with it please give the go ahead ;)

again sorry, and if mods want to remove images / code please feel free to :thumbs_up:

User avatar
DaveyG
Posts: 2227
Joined: 03 May 2020

Post 22 Sep 2023

:roll:

User avatar
Enlightenspeed
RE Developer
Posts: 1063
Joined: 03 Jan 2019

Post 22 Sep 2023

Billy+ wrote:
22 Sep 2023

ah!

hadn't really considered that......

Sorry Reason Studios, if you see this thread would you possibly chip in and advise on any concerns :thumbup:
if you would rather the info be removed please say so.
if however you're cool with it please give the go ahead ;)

again sorry, and if mods want to remove images / code please feel free to :thumbs_up:
I’d be surprised if they aren’t cool with it, but as a rule ask first. The patches are in plain text, not encrypted, so it’s easy to do this kind of thing, and this is probably intended by RS.

In the spirit of sharing, if they make the schema available, I’ll write the script for you, and make it public 😊

Cheers,
Brian

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 22 Sep 2023

Enlightenspeed wrote:
22 Sep 2023
Billy+ wrote:
22 Sep 2023

ah!

hadn't really considered that......

Sorry Reason Studios, if you see this thread would you possibly chip in and advise on any concerns :thumbup:
if you would rather the info be removed please say so.
if however you're cool with it please give the go ahead ;)

again sorry, and if mods want to remove images / code please feel free to :thumbs_up:
I’d be surprised if they aren’t cool with it, but as a rule ask first. The patches are in plain text, not encrypted, so it’s easy to do this kind of thing, and this is probably intended by RS.

In the spirit of sharing, if they make the schema available, I’ll write the script for you, and make it public 😊

Cheers,
Brian
thanks man :oops:

and seriously i didn't even think about the protentional issue, i guess i just got a bit of tunnel vision - i've been hitting a bit of a brick wall for a few months musically speaking and started out with thinking maybe some random rhythms might inspire something and it spiraled.

if i could remove the current insight i would but i can't

thanks for the intervention :thumbup:

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 22 Sep 2023

i have updated the initial script (random_rhythm_generator.py) and im happy to share it...

example usage :-

Code: Select all

c:\Billy>python random_rhythm_generator.py --help
usage: random_rhythm_generator.py [-h] [--charset CHARSET] [--rotate-left] [--rotate-right] [--limiting-factor LIMITING_FACTOR] [--max-repeating MAX_REPEATING]

optional arguments:
  -h, --help            show this help message and exit
  --charset CHARSET     character set to use for generating random rhythm
  --rotate-left         rotate the string to the left
  --rotate-right        rotate the string to the right
  --limiting-factor LIMITING_FACTOR
                        specify an individual character as a parameter to be the limiting factor
  --max-repeating MAX_REPEATING
                        specify the maximum number of times a character can be repeated

c:\Billy>python random_rhythm_generator.py
Todays Random Rhythm is : smsshmmrrmmshsrh

c:\Billy>python random_rhythm_generator.py --rotate-right --limiting-factor h3 --max-repeating 2
Todays Random Rhythm is : shmhsmrhmrmmsrss
Rotation 01: sshmhsmrhmrmmsrs
Rotation 02: ssshmhsmrhmrmmsr
Rotation 03: rssshmhsmrhmrmms
Rotation 04: srssshmhsmrhmrmm
Rotation 05: msrssshmhsmrhmrm
Rotation 06: mmsrssshmhsmrhmr
Rotation 07: rmmsrssshmhsmrhm
Rotation 08: mrmmsrssshmhsmrh
Rotation 09: hmrmmsrssshmhsmr
Rotation 10: rhmrmmsrssshmhsm
Rotation 11: mrhmrmmsrssshmhs
Rotation 12: smrhmrmmsrssshmh
Rotation 13: hsmrhmrmmsrssshm
Rotation 14: mhsmrhmrmmsrsssh
Rotation 15: hmhsmrhmrmmsrsss

this is the actual code below for anyone interested :- save as: random_rhythm_generator.py

Code: Select all

import argparse
import random
import string

def rotate_string(string, rotation):
    return string[rotation:] + string[:rotation]

def modify_string(string, limiting_factor, max_repeating):
    limiting_character, limiting_count = limiting_factor[0], int(limiting_factor[1:])
    limiting_factor_count = string.count(limiting_character)
    if limiting_factor_count > limiting_count:
        new_random_string = string.replace(limiting_character, limiting_character * limiting_count)
    else:
        new_random_string = string
    if max_repeating is not None:
        new_random_string = enforce_max_repeating(new_random_string, max_repeating)
    return new_random_string

def enforce_max_repeating(string, max_repeating):
    for char in set(string):
        if string.count(char) > max_repeating:
            string = string.replace(char * max_repeating, char * max_repeating + char)
    return string

def generate_random_string(charset, length):
    return ''.join(random.choices(charset, k=length))

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--charset', type=str, default='hmsr', help='character set to use for generating random rhythm')
    parser.add_argument('--rotate-left', action='store_true', help='rotate the string to the left')
    parser.add_argument('--rotate-right', action='store_true', help='rotate the string to the right')
    parser.add_argument('--limiting-factor', type=str, default=None, help='specify an individual character as a parameter to be the limiting factor')
    parser.add_argument('--max-repeating', type=int, default=None, help='specify the maximum number of times a character can be repeated')
    args = parser.parse_args()

    random_string = generate_random_string(args.charset, 16)

    if args.rotate_left:
        for i in range(len(random_string)):
            rotated_string = rotate_string(random_string, i)
            if i == 0:
                print(f"Todays Random Rhythm is : {random_string} ")
            elif i > 0:
                print(f"Rotation {i:02}: {rotated_string}")

    elif args.rotate_right:
        for i in range(len(random_string)):
            rotated_string = rotate_string(random_string, -i)
            if i == 0:
                print(f"Todays Random Rhythm is : {random_string} ")
            elif i > 0:
                print(f"Rotation {i:02}: {rotated_string}")

    elif args.limiting_factor is not None:
        new_random_string = modify_string(random_string, args.limiting_factor, args.max_repeating)
        print(f"Todays Random Rhythm is : {new_random_string} ")

    else:
        print(f"Todays Random Rhythm is : {random_string} ")

if __name__ == "__main__":
    main()


avasopht
Competition Winner
Posts: 3741
Joined: 16 Jan 2015

Post 23 Sep 2023

Billy+ wrote:
22 Sep 2023
i've been hitting a bit of a brick wall for a few months musically speaking and started out with thinking maybe some random rhythms might inspire something and it spiraled.

if i could remove the current insight i would but i can't

thanks for the intervention :thumbup:
Funnily enough, a few months ago I'd made this track using instruments (as I normally do). But I had a drum kit loaded with a good 64+ chord and note stabs.

I was surprised by how much they added to my track.

I think you might be onto something.

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 23 Sep 2023

avasopht wrote:
23 Sep 2023
Billy+ wrote:
22 Sep 2023
i've been hitting a bit of a brick wall for a few months musically speaking and started out with thinking maybe some random rhythms might inspire something and it spiraled.

if i could remove the current insight i would but i can't

thanks for the intervention :thumbup:
Funnily enough, a few months ago I'd made this track using instruments (as I normally do). But I had a drum kit loaded with a good 64+ chord and note stabs.

I was surprised by how much they added to my track.

I think you might be onto something.
yeah its funny how just getting something you wouldn't normally do can inspire.
I also have / had a brute force dictionary of numbers that I randomly grab a line from and use them to create chords etc.

this project just created a rhythm that I wouldn't normally create, I stuck with 16th that are either Rest Hard Medium or Soft hits.

oh I just realized that the script it's the best version :lol:
it's got bugs
, I was trying to extend it but failed..

Billy+
Posts: 4134
Joined: 09 Dec 2016

Post 23 Sep 2023

I also made another script that walks through a folder and subfolder playing wav mid files and listing patches etc, so I don't get distracted by shinny things and instead just listen to what's available..... that way I just sit back listen and wait for something to jump out at me ;)

this is basically its output on the console, and anything that can play gets played :lol:

c:\Billy>python playkit.py c:\DeepHouseCollection\Club_Essential_Series_-_Deep_House_Kits_Vol4_product_pack
FOLDER : EAM_Club_Series_Deep_House_Kits_Vol_4 [FILES 2]
FOLDER : KIT 01 126 A# [FILES 1]
* Playing FULL KIT 01 126 A#.wav
FOLDER : LOOPS [FILES 8]
* Playing BASS.wav
* Playing CLAP.wav
* Playing KICK.wav
* Playing PERC LOOP.wav
* Playing SHAKER LOOP 2.wav
* Playing SHAKER LOOP.wav
* Playing TRUMPET.wav
* Playing VOCAL.wav
FOLDER : MIDI [FILES 2]
* Playing BASS.mid
* Playing TRUMPET.mid
FOLDER : ONE SHOTS [FILES 10]
* Playing BASS SHOT A#.wav
* Playing CLAP.wav
* Playing CRASH.wav
* Playing KICK.wav
* Playing PERC 01.wav
* Playing SHAKER 01.wav
* Playing SHAKER 02.wav
* Playing TRUMPET C#.wav
* Playing VOCAL SHOT.wav
* Playing VOX.wav
FOLDER : PRESETS [FILES 1]
BASS - SPIRE.spf is a Spire Patch File.
FOLDER : STEMS [FILES 10]
* Playing BASS.wav
* Playing CLAP.wav
* Playing CRASH.wav
* Playing KICK.wav
* Playing PERC LOOP.wav
* Playing SHAKER LOOP 01.wav
* Playing SHAKER LOOP 20.wav
* Playing TRUMPET.wav
* Playing VOCAL SHOT.wav
* Playing VOX.wav
FOLDER : KIT 02 126 G [FILES 1]
* Playing FULL KIT G 126.wav

  • Information
  • Who is online

    Users browsing this forum: No registered users and 0 guests