Compare commits
No commits in common. "main" and "dev" have entirely different histories.
13
.github/FUNDING.yml
vendored
13
.github/FUNDING.yml
vendored
@ -1,13 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: BKLronin # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
||||||
patreon: # Replace with a single Patreon username
|
|
||||||
open_collective: # Replace with a single Open Collective username
|
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
||||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
||||||
liberapay: # Replace with a single Liberapay username
|
|
||||||
issuehunt: # Replace with a single IssueHunt username
|
|
||||||
otechie: # Replace with a single Otechie username
|
|
||||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
|
||||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
20
README.md
20
README.md
@ -5,19 +5,16 @@
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
- Exports patterns and projects individual audio tracks to seperate folders for use in your DAW.
|
- Exports patterns and projects individual audio tracks to seperate folders for use in your DAW.
|
||||||
- Python cross plattform with single file binary for x86 linux Windows and Mac.
|
- Python cross plattform with single file binary for x86 linux.
|
||||||
|
|
||||||
## Using Packaged single file Binarys _(The easy way)_
|
## Using Packaged single file Binarys _(The easy way)_
|
||||||
|
|
||||||
- Executables reside in the folder `/dist/` or in the release tab.
|
- Executables reside in the folder `/dist/`
|
||||||
- on Windows
|
- on Windows
|
||||||
``underbridge.exe``
|
`underbridge.exe`
|
||||||
- On Linux:
|
- On Linux:
|
||||||
``./underbridge``
|
``./underbridge``
|
||||||
- on Mac
|
|
||||||
Open terminal and change directory to where the underbridge_mac file is located and execute:
|
|
||||||
``chmod 755 underbridge_mac``
|
|
||||||
``./underbridge_mac`` or ``open underbridge_mac``
|
|
||||||
|
|
||||||
Underbridge_alt was packaged on a different system. Might help if you run into problems. (Outdated)
|
Underbridge_alt was packaged on a different system. Might help if you run into problems. (Outdated)
|
||||||
|
|
||||||
@ -26,13 +23,13 @@ Underbridge_alt was packaged on a different system. Might help if you run into p
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
- Install Python 3.9 if not already, 3.10 seems to cause problems.
|
- Install Python 3.9 if not already, 3.10 seems to cause problems.
|
||||||
|
- install portaudio_dev : `apt install portaudio19-dev`
|
||||||
- install mido : `pip install mido`
|
- install mido : `pip install mido`
|
||||||
- install rt-midi: `pip isntall rt-midi`
|
- install rt-midi: `pip isntall rt-midi`
|
||||||
- install pipwin: `pip install pipwin`
|
- install pipwin: `pip install pipwin`
|
||||||
- install pyaudio `pipwin install pyaudio`
|
- install pyaudio `pipwin install pyaudio`
|
||||||
|
|
||||||
**- Activate OP-Z device input in sound settings of windows and make it default (Should detect automatically just to be sure. **
|
**Activate OP-Z device input in sound settings of windows and make it default**
|
||||||
**- Close all other Applications that might use any audio source like your Browser etc **
|
|
||||||
|
|
||||||
- run `python underbridge.py`
|
- run `python underbridge.py`
|
||||||
|
|
||||||
@ -50,7 +47,7 @@ open terminal and type: `python3 underbridge.py` to start
|
|||||||
|
|
||||||
### Ubuntu 20.10 LTS
|
### Ubuntu 20.10 LTS
|
||||||
|
|
||||||
- `sudo apt install portaudio19-dev`
|
- `sudo apt install portaudio19-dev`
|
||||||
- `sudo apt install python3-tk`
|
- `sudo apt install python3-tk`
|
||||||
- `pip install python-rtmidi`
|
- `pip install python-rtmidi`
|
||||||
- `pip install pyaudio`
|
- `pip install pyaudio`
|
||||||
@ -88,4 +85,3 @@ open terminal and type: `python3 underbridge.py` to start
|
|||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
- When the recorded audio contains buzzing or other artifacts try disabling the USB charging with "display" and "bottom right key" to disable.
|
- When the recorded audio contains buzzing or other artifacts try disabling the USB charging with "display" and "bottom right key" to disable.
|
||||||
- If the playback of the OP-Z starts correctly but no tracks are muted check that MIDI IN in the OP-Z app or via combo is enabled.
|
|
||||||
|
Binary file not shown.
BIN
dist/underbridge
vendored
BIN
dist/underbridge
vendored
Binary file not shown.
24
dist/underbridge.app/Contents/Info.plist
vendored
24
dist/underbridge.app/Contents/Info.plist
vendored
@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>underbridge</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>underbridge</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>logo.ico</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>underbridge</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>underbridge</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>0.0.0</string>
|
|
||||||
<key>NSHighResolutionCapable</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
BIN
dist/underbridge.app/Contents/Resources/logo.ico
vendored
BIN
dist/underbridge.app/Contents/Resources/logo.ico
vendored
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
@ -1,128 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>files</key>
|
|
||||||
<dict>
|
|
||||||
<key>Resources/logo.ico</key>
|
|
||||||
<data>
|
|
||||||
mtFuKBM0y8Zhgf0zPV3iiD5US1w=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>files2</key>
|
|
||||||
<dict>
|
|
||||||
<key>Resources/logo.ico</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
QuvTuLzEUHh3cPgoVPNkcbQ5wWfEioohO8WxSTgroeM=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>rules</key>
|
|
||||||
<dict>
|
|
||||||
<key>^Resources/</key>
|
|
||||||
<true/>
|
|
||||||
<key>^Resources/.*\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>optional</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1100</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Resources/Base\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1010</real>
|
|
||||||
</dict>
|
|
||||||
<key>^version.plist$</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
<key>rules2</key>
|
|
||||||
<dict>
|
|
||||||
<key>.*\.dSYM($|/)</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>11</real>
|
|
||||||
</dict>
|
|
||||||
<key>^(.*/)?\.DS_Store$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>2000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
|
||||||
<dict>
|
|
||||||
<key>nested</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>10</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*</key>
|
|
||||||
<true/>
|
|
||||||
<key>^Info\.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^PkgInfo$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Resources/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Resources/.*\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>optional</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1100</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Resources/Base\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1010</real>
|
|
||||||
</dict>
|
|
||||||
<key>^[^/]+$</key>
|
|
||||||
<dict>
|
|
||||||
<key>nested</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>10</real>
|
|
||||||
</dict>
|
|
||||||
<key>^embedded\.provisionprofile$</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^version\.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
BIN
dist/underbridge.exe
vendored
BIN
dist/underbridge.exe
vendored
Binary file not shown.
BIN
dist/underbridge_lin
vendored
BIN
dist/underbridge_lin
vendored
Binary file not shown.
Binary file not shown.
@ -66,9 +66,9 @@ class Midirecorder:
|
|||||||
Pattern = Radiobutton(lowerframe, text= 'Pattern', value = 3 , variable = self.mode_select, width = self.buttonsize_x, height = self.buttonsize_y, indicatoron = 0,bg= '#1b7d24' )
|
Pattern = Radiobutton(lowerframe, text= 'Pattern', value = 3 , variable = self.mode_select, width = self.buttonsize_x, height = self.buttonsize_y, indicatoron = 0,bg= '#1b7d24' )
|
||||||
Pattern.select()
|
Pattern.select()
|
||||||
|
|
||||||
self.bar_input = Scale(upperframe, from_ = 1, to = 9, orient = HORIZONTAL, label="Nr. Bars", sliderlength= 10, length= 75, fg = 'white')
|
self.bar_input = Scale(upperframe, from_ = 1, to = 4, orient = HORIZONTAL, label="Nr. Bars", sliderlength= 10, length= 75, fg = 'white')
|
||||||
self.patterns_input = Scale(upperframe, from_ = 1, to = 16, orient = HORIZONTAL, label="Patterns",sliderlength= 10, length= 75, fg = 'white')
|
self.patterns_input = Scale(upperframe, from_ = 1, to = 10, orient = HORIZONTAL, label="Patterns",sliderlength= 10, length= 75, fg = 'white')
|
||||||
self.patterns_input.set(value=16)
|
self.patterns_input.set(value=10)
|
||||||
self.bpm_input = Entry(upperframe, width =10, text="BPM",bg= 'lightgrey', relief= FLAT)
|
self.bpm_input = Entry(upperframe, width =10, text="BPM",bg= 'lightgrey', relief= FLAT)
|
||||||
self.bpm_input.insert(0, "BPM")
|
self.bpm_input.insert(0, "BPM")
|
||||||
self.add_sec = Scale(upperframe, from_ = 0, to = 10, orient = HORIZONTAL, label="extra Sec", sliderlength= 10, length= 75, fg = 'white')
|
self.add_sec = Scale(upperframe, from_ = 0, to = 10, orient = HORIZONTAL, label="extra Sec", sliderlength= 10, length= 75, fg = 'white')
|
||||||
@ -133,7 +133,7 @@ class Midirecorder:
|
|||||||
try:
|
try:
|
||||||
self.op_device = list(filter(lambda x: 'OP-Z' in x, device_list))
|
self.op_device = list(filter(lambda x: 'OP-Z' in x, device_list))
|
||||||
self.op_device = self.op_device[0]
|
self.op_device = self.op_device[0]
|
||||||
#print (self.op_device)
|
print (self.op_device)
|
||||||
self.displaymsg.set("OP-Z found")
|
self.displaymsg.set("OP-Z found")
|
||||||
except:
|
except:
|
||||||
self.displaymsg.set("Can´t find OP-Z : MIDI Error.")
|
self.displaymsg.set("Can´t find OP-Z : MIDI Error.")
|
||||||
@ -196,7 +196,7 @@ class Midirecorder:
|
|||||||
#global op_device
|
#global op_device
|
||||||
self.outport= mido.open_output(self.op_device)
|
self.outport= mido.open_output(self.op_device)
|
||||||
#displaymsg.set("OP-Z MIDI not connected :(")
|
#displaymsg.set("OP-Z MIDI not connected :(")
|
||||||
#print(self.outport)
|
print(self.outport)
|
||||||
|
|
||||||
def setProject(self,projnr):
|
def setProject(self,projnr):
|
||||||
msg= mido.Message('program_change',song= self.projnr, program = 1)
|
msg= mido.Message('program_change',song= self.projnr, program = 1)
|
||||||
@ -204,19 +204,19 @@ class Midirecorder:
|
|||||||
|
|
||||||
def muteAll(self):
|
def muteAll(self):
|
||||||
checkbutton_name = 0
|
checkbutton_name = 0
|
||||||
#print(self.mute_list)
|
print(self.mute_list)
|
||||||
|
|
||||||
for j in range (0,8):
|
for j in range (0,7):
|
||||||
self.mute_list[j] = 1
|
self.mute_list[j] = 1
|
||||||
|
|
||||||
for i in range (1,7):
|
for i in range (1,6):
|
||||||
checkbutton_name = 'self.modifier{}_value'.format(i) #checkbutton 1- 6
|
checkbutton_name = 'self.modifier{}_value'.format(i) #checkbutton 1- 6
|
||||||
self.mute_list[i+7] = eval(checkbutton_name).get() #9th position in mute list
|
self.mute_list[i+7] = eval(checkbutton_name).get() #9th position in mute list
|
||||||
|
|
||||||
for k in range (0,14):
|
for k in range (0,13):
|
||||||
msg = mido.Message('control_change',control= 53, channel= k, value= self.mute_list[k])
|
msg = mido.Message('control_change',control= 53, channel= k, value= self.mute_list[k])
|
||||||
self.outport.send(msg)
|
self.outport.send(msg)
|
||||||
#print("Muted Channels",self.mute_list)
|
print("Muted Channels",self.mute_list)
|
||||||
|
|
||||||
def setSolo(self,chn):
|
def setSolo(self,chn):
|
||||||
msg = mido.Message('control_change',control= 53, channel= chn, value=0)
|
msg = mido.Message('control_change',control= 53, channel= chn, value=0)
|
||||||
@ -226,7 +226,7 @@ class Midirecorder:
|
|||||||
msg = mido.Message('start')
|
msg = mido.Message('start')
|
||||||
self.outport.send(msg)
|
self.outport.send(msg)
|
||||||
self.displaymsg.set("Playback started")
|
self.displaymsg.set("Playback started")
|
||||||
#print("midi")
|
print("midi")
|
||||||
|
|
||||||
def stop_MIDI(self):
|
def stop_MIDI(self):
|
||||||
msg = mido.Message('stop')
|
msg = mido.Message('stop')
|
||||||
@ -278,16 +278,16 @@ class Midirecorder:
|
|||||||
#print(projectpath)
|
#print(projectpath)
|
||||||
|
|
||||||
def start_Rec(self):
|
def start_Rec(self):
|
||||||
#print("record")
|
print("record")
|
||||||
self.displaymsg.set("Recording...")
|
self.displaymsg.set("Recording...")
|
||||||
CHUNK = 128
|
CHUNK = 128
|
||||||
FORMAT = pyaudio.paInt16
|
FORMAT = pyaudio.paInt16
|
||||||
CHANNELS = 2
|
CHANNELS = 2
|
||||||
|
|
||||||
RECORD_SECONDS= self.loop_time
|
RECORD_SECONDS= self.loop_time
|
||||||
#print("record")
|
print("record")
|
||||||
WAVE_OUTPUT_FILENAME = self.name_input.get() + "_" + "track" + str(self.j+1) + ".wav"
|
WAVE_OUTPUT_FILENAME = self.name_input.get() + "_" + "track" + str(self.j+1) + ".wav"
|
||||||
#print(WAVE_OUTPUT_FILENAME)
|
print(WAVE_OUTPUT_FILENAME)
|
||||||
p = pyaudio.PyAudio()
|
p = pyaudio.PyAudio()
|
||||||
stream = p.open(format=FORMAT,
|
stream = p.open(format=FORMAT,
|
||||||
channels=CHANNELS,
|
channels=CHANNELS,
|
||||||
@ -297,7 +297,7 @@ class Midirecorder:
|
|||||||
frames_per_buffer=CHUNK
|
frames_per_buffer=CHUNK
|
||||||
)
|
)
|
||||||
|
|
||||||
#print("* recording")
|
print("* recording")
|
||||||
|
|
||||||
frames = []
|
frames = []
|
||||||
self.start_MIDI()
|
self.start_MIDI()
|
||||||
@ -338,10 +338,11 @@ class Midirecorder:
|
|||||||
|
|
||||||
for i in range (0,8):
|
for i in range (0,8):
|
||||||
pattern_limit = self.patterns_input.get()
|
pattern_limit = self.patterns_input.get()
|
||||||
if self.cancel == 1 or self.pattern_nr == pattern_limit:
|
if self.cancel == 1 or self.pattern_nr == pattern_limit:
|
||||||
break
|
break
|
||||||
#print("sequence started",i)
|
#print("sequence started",i)
|
||||||
self.muteAll()
|
self.muteAll()
|
||||||
|
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
self.setSolo(i)
|
self.setSolo(i)
|
||||||
#starting Midi during wave record for timing
|
#starting Midi during wave record for timing
|
||||||
@ -349,7 +350,6 @@ class Midirecorder:
|
|||||||
self.stop_MIDI()
|
self.stop_MIDI()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.unmuteAll()
|
self.unmuteAll()
|
||||||
time.sleep(1)
|
|
||||||
mode = self.mode_select.get()
|
mode = self.mode_select.get()
|
||||||
|
|
||||||
if i == 7 and mode == 2:
|
if i == 7 and mode == 2:
|
||||||
@ -357,7 +357,7 @@ class Midirecorder:
|
|||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
self.nextPattern()
|
self.nextPattern()
|
||||||
self.pattern_nr += 1
|
self.pattern_nr += 1
|
||||||
if self.pattern_nr == 15 :
|
if self.pattern_nr == 9 :
|
||||||
self.pattern_nr = 0
|
self.pattern_nr = 0
|
||||||
self.sequenceMaster()
|
self.sequenceMaster()
|
||||||
except:
|
except:
|
||||||
|
Loading…
Reference in New Issue
Block a user