Merge branch 'main' of https://github.com/BKLronin/underbridge
This commit is contained in:
commit
3c7149f741
80
README.md
80
README.md
@ -2,40 +2,62 @@
|
|||||||
## Multitrack exporter
|
## Multitrack exporter
|
||||||
---
|
---
|
||||||
|
|
||||||
## Despription
|
## 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
|
- Python cross plattform with single file binary for x86 linux.
|
||||||
|
|
||||||
## Installation
|
## Using Packaged single file Binarys _(The easy way)_
|
||||||
### Ubuntu 20.10 LTS (If the binary in /dist doesn't work)
|
|
||||||
|
|
||||||
`sudo apt install portaudio19-dev`
|
|
||||||
`sudo apt install python3-tk`
|
|
||||||
`pip install python-rtmidi`
|
|
||||||
`pip install pyaudio`
|
|
||||||
|
|
||||||
### Mac Install
|
|
||||||
|
|
||||||
`brew install portaudio`
|
|
||||||
`brew install python-tk`
|
|
||||||
`pip install python-rtmidi`
|
|
||||||
`pip install pyaudio`
|
|
||||||
`pip install mido`
|
|
||||||
|
|
||||||
`python3 underbridge.py` to start
|
|
||||||
|
|
||||||
### Linux binary
|
|
||||||
|
|
||||||
|
- Executables reside in the folder `/dist/`
|
||||||
|
- on Windows
|
||||||
|
`underbridge.exe`
|
||||||
|
- On Linux:
|
||||||
``./underbridge``
|
``./underbridge``
|
||||||
|
|
||||||
Underbridge_alt was packaged on a different system. Might help if you run into problems.
|
|
||||||
|
Underbridge_alt was packaged on a different system. Might help if you run into problems. (Outdated)
|
||||||
|
|
||||||
|
## Installation _(Less easy way)_
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
- 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 rt-midi: `pip isntall rt-midi`
|
||||||
|
- install pipwin: `pip install pipwin`
|
||||||
|
- install pyaudio `pipwin install pyaudio`
|
||||||
|
|
||||||
|
**Activate OP-Z device input in sound settings of windows and make it default**
|
||||||
|
|
||||||
|
- run `python underbridge.py`
|
||||||
|
|
||||||
|
### Mac Install - ( tested on Mac OS Monterey 12.3 )
|
||||||
|
|
||||||
|
install portaudio: `brew install portaudio`
|
||||||
|
install mido: `pip install mido`
|
||||||
|
install tk: `brew install python-tk`
|
||||||
|
install rt-midi: `pip install python-rtmidi`
|
||||||
|
install pyaudio: `pip install pyaudio`
|
||||||
|
|
||||||
|
**Set OP-Z device as input in sound of system preferences**
|
||||||
|
|
||||||
|
open terminal and type: `python3 underbridge.py` to start
|
||||||
|
|
||||||
|
### Ubuntu 20.10 LTS
|
||||||
|
|
||||||
|
- `sudo apt install portaudio19-dev`
|
||||||
|
- `sudo apt install python3-tk`
|
||||||
|
- `pip install python-rtmidi`
|
||||||
|
- `pip install pyaudio`
|
||||||
|
|
||||||
|
`python3 underbridge.py` to start
|
||||||
|
|
||||||
## Steps
|
## Steps
|
||||||
|
|
||||||
- connect OP-Z via USB
|
- connect OP-Z via USB
|
||||||
- in /dist/ directory run ``./underbridge``
|
- Run underbridge
|
||||||
- Alternatively python3 underbridge.py in root directory. Make sure you have installed dependencies before..
|
|
||||||
|
|
||||||
### Single Pattern Mode
|
### Single Pattern Mode
|
||||||
|
|
||||||
@ -53,7 +75,7 @@ Underbridge_alt was packaged on a different system. Might help if you run into p
|
|||||||
- Select Porject and first Pattern you want to export on OP-Z.
|
- Select Porject and first Pattern you want to export on OP-Z.
|
||||||
- Enter name for the project. This is used for the folder structure
|
- Enter name for the project. This is used for the folder structure
|
||||||
- Get BPM from led code or Smartphone app.
|
- Get BPM from led code or Smartphone app.
|
||||||
- Enter BPM
|
- Enter BPM
|
||||||
- Enter longest Bar of you track (1-4)
|
- Enter longest Bar of you track (1-4)
|
||||||
- Enter the Nr. of Patterns your song consists of.
|
- Enter the Nr. of Patterns your song consists of.
|
||||||
- Optionally enter additional seconds at the end of the recording to capture reverb tails etc.
|
- Optionally enter additional seconds at the end of the recording to capture reverb tails etc.
|
||||||
@ -61,7 +83,5 @@ Underbridge_alt was packaged on a different system. Might help if you run into p
|
|||||||
- Select directory you want to record the waves to
|
- Select directory you want to record the waves to
|
||||||
- Click record and wait until finished.
|
- Click record and wait until finished.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
- When the recorded audio contains buzzing or other artifacts try disabling the USB charging with "display" and "bottom right key" to disable.
|
||||||
|
|
||||||
|
|
||||||
|
BIN
dist/underbridge
vendored
BIN
dist/underbridge
vendored
Binary file not shown.
BIN
dist/underbridge.exe
vendored
Normal file
BIN
dist/underbridge.exe
vendored
Normal file
Binary file not shown.
7
import pyaudio.py
Normal file
7
import pyaudio.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import pyaudio
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
info = p.get_host_api_info_by_index(0)
|
||||||
|
numdevices = info.get('deviceCount')
|
||||||
|
for i in range(0, numdevices):
|
||||||
|
if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0:
|
||||||
|
print("Input Device id ", i, " - ", p.get_device_info_by_host_api_device_index(0, i).get('name'))
|
@ -1,7 +1,6 @@
|
|||||||
# Underbridge OP-Z multichannel exporter
|
# Underbridge OP-Z multichannel exporter
|
||||||
# Copyright 2022 Thomas Herrmann Email: herrmann@raise-uav.com
|
# Copyright 2022 Thomas Herrmann Email: herrmann@raise-uav.com
|
||||||
|
|
||||||
|
|
||||||
import mido
|
import mido
|
||||||
import pyaudio
|
import pyaudio
|
||||||
import wave
|
import wave
|
||||||
@ -11,6 +10,9 @@ import time
|
|||||||
import threading
|
import threading
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
device_list = []
|
||||||
|
op_device = []
|
||||||
|
audio_device = []
|
||||||
loop_time = 0
|
loop_time = 0
|
||||||
inport = 0
|
inport = 0
|
||||||
outport = 0
|
outport = 0
|
||||||
@ -25,11 +27,39 @@ cancel = 0
|
|||||||
|
|
||||||
|
|
||||||
def getMIDIDevice():
|
def getMIDIDevice():
|
||||||
pass
|
global device_list
|
||||||
|
global op_device
|
||||||
|
device_list = mido.get_output_names()
|
||||||
|
print (device_list)
|
||||||
|
try:
|
||||||
|
op_device = list(filter(lambda x: 'OP-Z' in x, device_list))
|
||||||
|
op_device = op_device[0]
|
||||||
|
print (op_device)
|
||||||
|
displaymsg.set("OP-Z found")
|
||||||
|
except:
|
||||||
|
displaymsg.set("Can´t find OP-Z : MIDI Error.")
|
||||||
|
|
||||||
|
def getAudioDevice():
|
||||||
|
global audio_device
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
try:
|
||||||
|
info = p.get_host_api_info_by_index(0)
|
||||||
|
numdevices = info.get('deviceCount')
|
||||||
|
for i in range(0, numdevices):
|
||||||
|
if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0:
|
||||||
|
print("Input Device id ", i, " - ", p.get_device_info_by_host_api_device_index(0, i).get('name'))
|
||||||
|
for i in range(0, numdevices):
|
||||||
|
#audio_device = p.get_device_info_by_host_api_device_index(0, i).get('name')
|
||||||
|
if "OP-Z" in p.get_device_info_by_host_api_device_index(0, i).get('name') and (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0:
|
||||||
|
audio_device = i
|
||||||
|
|
||||||
|
print ("Detected OP-Z audio at Index:",audio_device, p.get_device_info_by_host_api_device_index(0, audio_device).get('name'))
|
||||||
|
except:
|
||||||
|
displaymsg.set("OP-Z Audio Device not found.")
|
||||||
|
|
||||||
def getBPM():
|
def getBPM():
|
||||||
inport= mido.open_input('OP-Z:OP-Z MIDI 1 20:0')
|
global op_device
|
||||||
|
inport= mido.open_input(op_device)
|
||||||
msg = inport.poll()
|
msg = inport.poll()
|
||||||
#print(msg)
|
#print(msg)
|
||||||
|
|
||||||
@ -55,8 +85,9 @@ def setParam():
|
|||||||
|
|
||||||
def openMidi():
|
def openMidi():
|
||||||
global outport
|
global outport
|
||||||
outport= mido.open_output('OP-Z:OP-Z MIDI 1 20:0')
|
global op_device
|
||||||
displaymsg.set("OP-Z MIDI not connected :(")
|
outport= mido.open_output(op_device)
|
||||||
|
#displaymsg.set("OP-Z MIDI not connected :(")
|
||||||
print(outport)
|
print(outport)
|
||||||
|
|
||||||
def setProject(projnr):
|
def setProject(projnr):
|
||||||
@ -102,8 +133,10 @@ def nextPattern():
|
|||||||
def nextSong():
|
def nextSong():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def closeMidi():
|
def closeMidi():
|
||||||
pass
|
global outport
|
||||||
|
outport.close()
|
||||||
|
displaymsg.set("MIDI closed")
|
||||||
|
|
||||||
def setPath():
|
def setPath():
|
||||||
global path
|
global path
|
||||||
@ -139,26 +172,29 @@ def start_Rec():
|
|||||||
global j
|
global j
|
||||||
global pro
|
global pro
|
||||||
global pattern_nr
|
global pattern_nr
|
||||||
CHUNK = 1024
|
global audio_device
|
||||||
|
|
||||||
|
CHUNK = 128
|
||||||
FORMAT = pyaudio.paInt16
|
FORMAT = pyaudio.paInt16
|
||||||
CHANNELS = 2
|
CHANNELS = 2
|
||||||
RATE = 44100
|
RATE = 48000
|
||||||
RECORD_SECONDS = loop_time
|
RECORD_SECONDS = loop_time
|
||||||
WAVE_OUTPUT_FILENAME = name_input.get()+ "_" + "track" + str(j+1) + ".wav"
|
WAVE_OUTPUT_FILENAME = name_input.get()+ "_" + "track" + str(j+1) + ".wav"
|
||||||
|
|
||||||
p = pyaudio.PyAudio()
|
p = pyaudio.PyAudio()
|
||||||
start_MIDI()
|
|
||||||
stream = p.open(format=FORMAT,
|
stream = p.open(format=FORMAT,
|
||||||
channels=CHANNELS,
|
channels=CHANNELS,
|
||||||
rate=RATE,
|
rate=RATE,
|
||||||
input=True,
|
input=True,
|
||||||
|
input_device_index= audio_device,
|
||||||
frames_per_buffer=CHUNK
|
frames_per_buffer=CHUNK
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
#print("* recording")
|
#print("* recording")
|
||||||
|
|
||||||
frames = []
|
frames = []
|
||||||
|
start_MIDI()
|
||||||
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
|
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
|
||||||
data = stream.read(CHUNK)
|
data = stream.read(CHUNK)
|
||||||
frames.append(data)
|
frames.append(data)
|
||||||
@ -184,12 +220,19 @@ def start_Rec():
|
|||||||
displaymsg.set("End of Recording")
|
displaymsg.set("End of Recording")
|
||||||
|
|
||||||
def sequenceMaster():
|
def sequenceMaster():
|
||||||
|
|
||||||
global cancel
|
global cancel
|
||||||
global pattern_nr
|
global pattern_nr
|
||||||
cancel = 0
|
cancel = 0
|
||||||
#print("test")
|
#print("test")
|
||||||
|
|
||||||
|
getMIDIDevice()
|
||||||
|
time.sleep(1)
|
||||||
|
getAudioDevice()
|
||||||
|
|
||||||
displaymsg.set("Sequence started")
|
displaymsg.set("Sequence started")
|
||||||
try:
|
|
||||||
|
try:
|
||||||
openMidi()
|
openMidi()
|
||||||
|
|
||||||
if mode_select.get() == 2:
|
if mode_select.get() == 2:
|
||||||
@ -201,11 +244,13 @@ def sequenceMaster():
|
|||||||
break
|
break
|
||||||
#print("sequence started",i)
|
#print("sequence started",i)
|
||||||
muteAll()
|
muteAll()
|
||||||
|
time.sleep(0.1)
|
||||||
setSolo(i)
|
setSolo(i)
|
||||||
#starting Midi during wave record for timing
|
#starting Midi during wave record for timing
|
||||||
start_Rec()
|
start_Rec()
|
||||||
#print(i)
|
#print(i)
|
||||||
stop_MIDI()
|
stop_MIDI()
|
||||||
|
time.sleep(1)
|
||||||
unmuteAll()
|
unmuteAll()
|
||||||
mode = mode_select.get()
|
mode = mode_select.get()
|
||||||
|
|
||||||
@ -218,13 +263,15 @@ def sequenceMaster():
|
|||||||
pattern_nr = 0
|
pattern_nr = 0
|
||||||
sequenceMaster()
|
sequenceMaster()
|
||||||
except:
|
except:
|
||||||
displaymsg.set("OP-Z connection Problem :(")
|
displaymsg.set("OP-Z Sequence error try restarting the OP-Z or press CANCEL Button")
|
||||||
|
|
||||||
def cancelRec():
|
def cancelRec():
|
||||||
global cancel
|
global cancel
|
||||||
|
global outport
|
||||||
global j
|
global j
|
||||||
j = 0
|
j = 0
|
||||||
cancel = 1
|
cancel = 1
|
||||||
|
closeMidi()
|
||||||
|
|
||||||
#GUI Main
|
#GUI Main
|
||||||
buttonsize_x = 7
|
buttonsize_x = 7
|
||||||
|
Loading…
Reference in New Issue
Block a user