Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
97043ad530 | ||
|
4dd36626a3 | ||
|
bf7ec5aca6 | ||
|
9d8d251cc8 | ||
|
5ae8fd499b | ||
|
9c96d5a1d5 | ||
|
13bca03f78 | ||
|
0e5c609d03 | ||
|
7fe2d4c3eb | ||
|
2489f99b90 | ||
|
e96b01e772 | ||
|
8319f87ec5 | ||
|
5794cc9a21 | ||
|
a4e87e4bbf | ||
|
a162d06a62 | ||
|
5141d3e324 | ||
|
f0c438d7fa | ||
|
815354f4e6 | ||
|
27718f3e29 | ||
|
85c7df594b | ||
|
ebc097d901 | ||
|
28f4ef3334 | ||
|
0207f61739 | ||
|
a312e0540c | ||
|
728158ce09 | ||
|
d4c397e373 | ||
|
f90daecfaa | ||
|
5e23f8846f | ||
|
8721fa190f | ||
|
d0d7ded22f | ||
|
3c7149f741 | ||
|
47092eed60 | ||
|
56586e1ac8 |
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 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']
|
41
README.md
41
README.md
@ -5,17 +5,21 @@
|
|||||||
## 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.
|
- Python cross plattform with single file binary for x86 linux Windows and Mac.
|
||||||
|
|
||||||
## Using Packaged single file Binarys _(The easy way)_
|
## Using Packaged single file Binarys _(The easy way)_
|
||||||
|
|
||||||
- Executables reside in the folder `/dist/`
|
- Executables reside in the folder `/dist/` or in the release tab.
|
||||||
- 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.
|
Underbridge_alt was packaged on a different system. Might help if you run into problems. (Outdated)
|
||||||
|
|
||||||
## Installation _(Less easy way)_
|
## Installation _(Less easy way)_
|
||||||
|
|
||||||
@ -27,16 +31,29 @@ Underbridge_alt was packaged on a different system. Might help if you run into p
|
|||||||
- 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**
|
**- Activate OP-Z device input in sound settings of windows and make it default (Should detect automatically just to be sure. **
|
||||||
|
**- Close all other Applications that might use any audio source like your Browser etc **
|
||||||
|
|
||||||
- run `python underbridge.py`
|
- 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
|
### 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`
|
||||||
|
|
||||||
`python3 underbridge.py` to start
|
`python3 underbridge.py` to start
|
||||||
|
|
||||||
@ -68,3 +85,7 @@ Underbridge_alt was packaged on a different system. Might help if you run into p
|
|||||||
- Select project mode
|
- Select project mode
|
||||||
- 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.
|
||||||
|
- 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
Normal file
24
dist/underbridge.app/Contents/Info.plist
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?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>
|
Binary file not shown.
BIN
dist/underbridge.app/Contents/Resources/logo.ico
vendored
Normal file
BIN
dist/underbridge.app/Contents/Resources/logo.ico
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
128
dist/underbridge.app/Contents/_CodeSignature/CodeResources
vendored
Normal file
128
dist/underbridge.app/Contents/_CodeSignature/CodeResources
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?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
Executable file
BIN
dist/underbridge_lin
vendored
Executable file
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
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'))
|
|
718
underbridge.py
718
underbridge.py
@ -6,367 +6,367 @@ import pyaudio
|
|||||||
import wave
|
import wave
|
||||||
from tkinter import *
|
from tkinter import *
|
||||||
from tkinter import filedialog as fd
|
from tkinter import filedialog as fd
|
||||||
|
from tkinter import ttk
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import os
|
import os
|
||||||
|
|
||||||
device_list = []
|
|
||||||
op_device = []
|
|
||||||
audio_device = []
|
|
||||||
loop_time = 0
|
|
||||||
inport = 0
|
|
||||||
outport = 0
|
|
||||||
path = 0
|
|
||||||
folder = 0
|
|
||||||
pattern_nr = 0
|
|
||||||
j = 0
|
|
||||||
mode_select=0
|
|
||||||
addsec = 0
|
|
||||||
projectpath = 0
|
|
||||||
cancel = 0
|
|
||||||
|
|
||||||
|
|
||||||
def getMIDIDevice():
|
|
||||||
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():
|
|
||||||
global op_device
|
|
||||||
inport= mido.open_input(op_device)
|
|
||||||
msg = inport.poll()
|
|
||||||
#print(msg)
|
|
||||||
|
|
||||||
def setLoop():
|
|
||||||
global loop_time
|
|
||||||
try:
|
|
||||||
bpm = bpm_input.get()
|
|
||||||
bar = bar_input.get()
|
|
||||||
addsec = add_sec.get()
|
|
||||||
loop_time = (240 / int(bpm) * int(bar)) + int(addsec)
|
|
||||||
print("Loop time set!")
|
|
||||||
displaymsg.set("BPM Set!")
|
|
||||||
except:
|
|
||||||
displaymsg.set("Please enter accurate BPM.")
|
|
||||||
return time
|
|
||||||
|
|
||||||
def setParam():
|
|
||||||
setLoop()
|
|
||||||
#mode = mode_select.get()
|
|
||||||
#if mode == 2:
|
|
||||||
# projnr = project_input.get()
|
|
||||||
# setProject(projnr)
|
|
||||||
|
|
||||||
def openMidi():
|
|
||||||
global outport
|
|
||||||
global op_device
|
|
||||||
outport= mido.open_output(op_device)
|
|
||||||
#displaymsg.set("OP-Z MIDI not connected :(")
|
|
||||||
print(outport)
|
|
||||||
|
|
||||||
def setProject(projnr):
|
|
||||||
global outport
|
|
||||||
msg= mido.Message('program_change',song= projnr, program = 1)
|
|
||||||
outport.send(msg)
|
|
||||||
|
|
||||||
def muteAll():
|
|
||||||
global outport
|
|
||||||
for i in range (0,15):
|
|
||||||
msg = mido.Message('control_change',control= 53, channel= i, value=1)
|
|
||||||
outport.send(msg)
|
|
||||||
|
|
||||||
def setSolo(chn):
|
|
||||||
global outport
|
|
||||||
msg = mido.Message('control_change',control= 53, channel= chn, value=0)
|
|
||||||
outport.send(msg)
|
|
||||||
|
|
||||||
def start_MIDI():
|
|
||||||
global outport
|
|
||||||
msg = mido.Message('start')
|
|
||||||
outport.send(msg)
|
|
||||||
displaymsg.set("Playback started")
|
|
||||||
|
|
||||||
def stop_MIDI():
|
|
||||||
global outport
|
|
||||||
msg = mido.Message('stop')
|
|
||||||
outport.send(msg)
|
|
||||||
displaymsg.set("Playback stopped")
|
|
||||||
|
|
||||||
def unmuteAll():
|
|
||||||
global outport
|
|
||||||
for i in range (0,15):
|
|
||||||
msg = mido.Message('control_change',control= 53, channel= i, value=0)
|
|
||||||
outport.send(msg)
|
|
||||||
|
|
||||||
def nextPattern():
|
|
||||||
global outport
|
|
||||||
msg = mido.Message('control_change', control = 103, value = 16)
|
|
||||||
outport.send(msg)
|
|
||||||
displaymsg.set("Next Pattern")
|
|
||||||
|
|
||||||
def nextSong():
|
|
||||||
pass
|
|
||||||
|
|
||||||
def closeMidi():
|
|
||||||
global outport
|
|
||||||
outport.close()
|
|
||||||
displaymsg.set("MIDI closed")
|
|
||||||
|
|
||||||
def setPath():
|
|
||||||
global path
|
|
||||||
folder = name_input.get()
|
|
||||||
path = fd.askdirectory()
|
|
||||||
displaymsg.set("Directory set!")
|
|
||||||
makeDir()
|
|
||||||
|
|
||||||
def makeDir():
|
|
||||||
global folder
|
|
||||||
global projectpath
|
|
||||||
folder = name_input.get()
|
|
||||||
projectpath = path + '/' + folder
|
|
||||||
try:
|
|
||||||
os.mkdir(projectpath)
|
|
||||||
except:
|
|
||||||
displaymsg.set("Directory Error. Please enter different Name.")
|
|
||||||
|
|
||||||
def makeDirNr(pattern_nr):
|
|
||||||
global projectpath
|
|
||||||
#Pfad wird addiert deswegen zusätzliche verzeichnisse
|
|
||||||
#projectpath = projectpath + '/' + str(pattern_nr)
|
|
||||||
try:
|
|
||||||
os.mkdir(projectpath + '/' + str(pattern_nr))
|
|
||||||
except:
|
|
||||||
displaymsg.set("Directory Error")
|
|
||||||
#print(projectpath)
|
|
||||||
|
|
||||||
def start_Rec():
|
|
||||||
displaymsg.set("Recording...")
|
|
||||||
global path
|
|
||||||
global time
|
|
||||||
global j
|
|
||||||
global pro
|
|
||||||
global pattern_nr
|
|
||||||
global audio_device
|
|
||||||
|
|
||||||
CHUNK = 128
|
|
||||||
FORMAT = pyaudio.paInt16
|
|
||||||
CHANNELS = 2
|
|
||||||
RATE = 48000
|
|
||||||
RECORD_SECONDS = loop_time
|
|
||||||
WAVE_OUTPUT_FILENAME = name_input.get()+ "_" + "track" + str(j+1) + ".wav"
|
|
||||||
|
|
||||||
p = pyaudio.PyAudio()
|
|
||||||
stream = p.open(format=FORMAT,
|
|
||||||
channels=CHANNELS,
|
|
||||||
rate=RATE,
|
|
||||||
input=True,
|
|
||||||
input_device_index= audio_device,
|
|
||||||
frames_per_buffer=CHUNK
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
#print("* recording")
|
|
||||||
|
|
||||||
frames = []
|
|
||||||
start_MIDI()
|
|
||||||
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
|
|
||||||
data = stream.read(CHUNK)
|
|
||||||
frames.append(data)
|
|
||||||
|
|
||||||
#print("Done recording")
|
|
||||||
|
|
||||||
stream.stop_stream()
|
|
||||||
stream.close()
|
|
||||||
p.terminate()
|
|
||||||
if mode_select.get() == 2:
|
|
||||||
wf = wave.open(projectpath + '/' + str(pattern_nr) + '/' + WAVE_OUTPUT_FILENAME, 'wb')
|
|
||||||
else:
|
|
||||||
wf = wave.open(projectpath + '/' + WAVE_OUTPUT_FILENAME, 'wb')
|
|
||||||
|
|
||||||
wf.setnchannels(CHANNELS)
|
|
||||||
wf.setsampwidth(p.get_sample_size(FORMAT))
|
|
||||||
wf.setframerate(RATE)
|
|
||||||
wf.writeframes(b''.join(frames))
|
|
||||||
wf.close()
|
|
||||||
j = j + 1
|
|
||||||
if j == 8:
|
|
||||||
j= 0
|
|
||||||
displaymsg.set("End of Recording")
|
|
||||||
|
|
||||||
def sequenceMaster():
|
|
||||||
|
|
||||||
global cancel
|
|
||||||
global pattern_nr
|
|
||||||
cancel = 0
|
|
||||||
#print("test")
|
|
||||||
|
|
||||||
getMIDIDevice()
|
|
||||||
time.sleep(1)
|
|
||||||
getAudioDevice()
|
|
||||||
|
|
||||||
displaymsg.set("Sequence started")
|
|
||||||
|
|
||||||
try:
|
|
||||||
openMidi()
|
|
||||||
|
|
||||||
if mode_select.get() == 2:
|
|
||||||
makeDirNr(pattern_nr)
|
|
||||||
|
|
||||||
for i in range (0,8): #
|
|
||||||
pattern_limit = patterns_input.get()
|
|
||||||
if cancel == 1 or pattern_nr == pattern_limit:
|
|
||||||
break
|
|
||||||
#print("sequence started",i)
|
|
||||||
muteAll()
|
|
||||||
time.sleep(0.1)
|
|
||||||
setSolo(i)
|
|
||||||
#starting Midi during wave record for timing
|
|
||||||
start_Rec()
|
|
||||||
#print(i)
|
|
||||||
stop_MIDI()
|
|
||||||
time.sleep(1)
|
|
||||||
unmuteAll()
|
|
||||||
mode = mode_select.get()
|
|
||||||
|
|
||||||
if i == 7 and mode == 2:
|
|
||||||
#print(mode_select)
|
|
||||||
time.sleep(5)
|
|
||||||
nextPattern()
|
|
||||||
pattern_nr += 1
|
|
||||||
if pattern_nr == 9 :
|
|
||||||
pattern_nr = 0
|
|
||||||
sequenceMaster()
|
|
||||||
except:
|
|
||||||
displaymsg.set("OP-Z Sequence error try restarting the OP-Z or press CANCEL Button")
|
|
||||||
|
|
||||||
def cancelRec():
|
|
||||||
global cancel
|
|
||||||
global outport
|
|
||||||
global j
|
|
||||||
j = 0
|
|
||||||
cancel = 1
|
|
||||||
closeMidi()
|
|
||||||
|
|
||||||
#GUI Main
|
class Midirecorder:
|
||||||
buttonsize_x = 7
|
def __init__(self):
|
||||||
buttonsize_y = 2
|
|
||||||
mode_select = 0
|
self.window = Tk()
|
||||||
|
self.window.title('underbridge')
|
||||||
root = Tk()
|
self.window.resizable(width=False, height=False) #565A5E
|
||||||
root.title('underbridge for OP-Z')
|
self.window.tk_setPalette(background='#565A5E', foreground='black',activeBackground='#283867', activeForeground='black' )
|
||||||
root.resizable(width=False, height=False) #565A5E
|
#device_list = []
|
||||||
root.tk_setPalette(background='#565A5E', foreground='black',activeBackground='#283867', activeForeground='black' )
|
self.op_device = []
|
||||||
|
self.audio_device = []
|
||||||
upperframe= LabelFrame(root, text= "Parameter",padx= 10, pady =2, fg = 'white')
|
self.loop_time = 0
|
||||||
upperframe.grid(row = 0, column = 0, padx =2, pady =2,)
|
self.inport = 0
|
||||||
|
self.outport = 0
|
||||||
lowerframe= Frame(root,padx= 10, pady =5)
|
self.path = 0
|
||||||
lowerframe.grid(row = 1, column = 0, padx =2, pady =2)
|
self.folder = 0
|
||||||
|
self.pattern_nr = 0
|
||||||
footer= Frame(root,padx= 15, pady =2)
|
self.j = 0
|
||||||
footer. grid(row = 2, column = 0, padx =2, pady =2)
|
self.addsec = 0
|
||||||
|
self.projectpath = 0
|
||||||
mode_select = IntVar()
|
self.cancel = 0
|
||||||
displaymsg = StringVar()
|
self.RATE = 0
|
||||||
#root.geometry('550x150+0+0')
|
self.mute_list =[0] * 14 #Midi mute selection of all 14 necessary channels
|
||||||
|
#modifier_dict = {"mod1": modifier1_va}
|
||||||
Get_BPM = Button(upperframe, text="Get BPM",width = buttonsize_x, height = buttonsize_y, fg = 'lightgrey', command = lambda:getBPM())
|
|
||||||
|
#GUI Main
|
||||||
#ALL = Radiobutton(lowerframe, text= 'ALL', value = 1 , variable = mode_select, width = buttonsize_x, height = buttonsize_y , indicatoron = 0, bg= '#1b7d24' )
|
self.buttonsize_x = 7
|
||||||
Song = Radiobutton(lowerframe, text= 'Project', value = 2 , variable = mode_select, width = buttonsize_x, height = buttonsize_y , indicatoron = 0, bg= '#1b7d24' )
|
self.buttonsize_y = 2
|
||||||
Pattern = Radiobutton(lowerframe, text= 'Pattern', value = 3 , variable = mode_select, width = buttonsize_x, height = buttonsize_y, indicatoron = 0,bg= '#1b7d24' )
|
|
||||||
Pattern.select()
|
self.mode_select = IntVar()
|
||||||
|
self.displaymsg = StringVar()
|
||||||
bar_input = Scale(upperframe, from_ = 1, to = 4, orient = HORIZONTAL, label="Nr. Bars", sliderlength= 10, length= 75, fg = 'white')
|
self.modifier1_value = IntVar()
|
||||||
#bar_text = Label(upperframe,text="Nr. of Bars", width = 8, height = 1)
|
self.modifier2_value = IntVar()
|
||||||
|
self.modifier3_value = IntVar()
|
||||||
patterns_input = Scale(upperframe, from_ = 1, to = 10, orient = HORIZONTAL, label="Patterns",sliderlength= 10, length= 75, fg = 'white')
|
self.modifier4_value = IntVar()
|
||||||
patterns_input.set(value=10)
|
self.modifier5_value = IntVar()
|
||||||
|
self.modifier6_value = IntVar()
|
||||||
bpm_input = Entry(upperframe, width =10, text="BPM",bg= 'lightgrey', relief= FLAT)
|
|
||||||
#bpm_text = Label(upperframe,text="BPM", width = 8, height = 1)
|
upperframe= LabelFrame(self.window, text= "Parameter",padx= 10, pady =2, fg = 'white')
|
||||||
bpm_input.insert(0, "BPM")
|
upperframe.grid(row = 0, column = 0, padx =2, pady =2,)
|
||||||
|
|
||||||
#project_input = Entry(upperframe, width =10, text="Project",bg= 'white')
|
lowerframe= Frame(self.window,padx= 10, pady =5)
|
||||||
#bpm_text = Label(upperframe,text="BPM", width = 8, height = 1)
|
lowerframe.grid(row = 2, column = 0, padx =2, pady =2)
|
||||||
#project_input.insert(0, "Project Nr.")
|
|
||||||
|
modifiers = LabelFrame(self.window, text= "Exclude Modifiers",padx= 10, pady =2, fg = 'white')
|
||||||
add_sec = Scale(upperframe, from_ = 0, to = 10, orient = HORIZONTAL, label="extra Sec", sliderlength= 10, length= 75, fg = 'white')
|
modifiers.grid(row = 1, column = 0, padx =2, pady =2)
|
||||||
#add_text = Label(upperframe,text="Sec offset", width = 8, height = 1)
|
|
||||||
|
footer= Frame(self.window,padx= 15, pady =2)
|
||||||
name_input = Entry(upperframe, width =10, text="Name",bg = 'lightgrey', relief= FLAT)
|
footer. grid(row = 3, column = 0, padx =2, pady =2)
|
||||||
name_input.insert(0, "Name")
|
|
||||||
#name_text = Label(upperframe,text="Prj Name", width = 8, height = 1)
|
#Get_BPM = Button(upperframe, text="Get BPM",width = self.buttonsize_x, height = self.buttonsize_y, fg = 'lightgrey', command = getBPM)
|
||||||
|
Song = Radiobutton(lowerframe, text= 'Project', value = 2 , variable = self.mode_select, width = self.buttonsize_x, height = self.buttonsize_y , indicatoron = 0, bg= '#1b7d24' )
|
||||||
set_param = Button(lowerframe, text="Set Prmtr",width = buttonsize_x, height = buttonsize_y, fg = 'white',bg= '#0095FF', command = lambda:setParam())
|
Pattern = Radiobutton(lowerframe, text= 'Pattern', value = 3 , variable = self.mode_select, width = self.buttonsize_x, height = self.buttonsize_y, indicatoron = 0,bg= '#1b7d24' )
|
||||||
set_path = Button(lowerframe, text="Directory",width = buttonsize_x, height = buttonsize_y,fg = 'white',bg= '#0095FF', command = lambda:setPath())
|
Pattern.select()
|
||||||
start_recording = Button(lowerframe, text="RECORD",width = buttonsize_x, height = buttonsize_y,fg = 'white', bg = '#FF2200', command = lambda:threading.Thread(target = sequenceMaster).start())
|
|
||||||
|
self.bar_input = Scale(upperframe, from_ = 1, to = 9, orient = HORIZONTAL, label="Nr. Bars", sliderlength= 10, length= 75, fg = 'white')
|
||||||
tutorial = Label(footer,text="Enter Parameter, then press set Param, choose directory and start recording", height = 2, bg ='grey',fg= 'white', relief = FLAT)
|
self.patterns_input = Scale(upperframe, from_ = 1, to = 16, orient = HORIZONTAL, label="Patterns",sliderlength= 10, length= 75, fg = 'white')
|
||||||
display = Label(lowerframe,textvariable= displaymsg,width = 60, height = buttonsize_y -1, bg ='lightgrey', relief = FLAT)
|
self.patterns_input.set(value=16)
|
||||||
|
self.bpm_input = Entry(upperframe, width =10, text="BPM",bg= 'lightgrey', relief= FLAT)
|
||||||
cancel = Button(lowerframe,text = "CANCEL" , width = buttonsize_x, height = buttonsize_y, bg ='#FFCC00', fg= 'white', command = lambda: cancelRec())
|
self.bpm_input.insert(0, "BPM")
|
||||||
cancel.grid(row = 0, column = 6, padx =2, pady =2)
|
self.add_sec = Scale(upperframe, from_ = 0, to = 10, orient = HORIZONTAL, label="extra Sec", sliderlength= 10, length= 75, fg = 'white')
|
||||||
|
|
||||||
donate = Label(footer, text= "donate <3 @ https://link.raise-uav.com", height = 1)
|
self.name_input = Entry(upperframe, width =10, text="Name",bg = 'lightgrey', relief= FLAT)
|
||||||
donate.grid(row = 3, column = 4, padx =2, pady =10, columnspan=2)
|
self.name_input.insert(0, "Name")
|
||||||
|
|
||||||
|
modifier1 = Checkbutton(modifiers, text="Send 1", variable=self.modifier1_value)
|
||||||
#Get_BPM.grid(row = 1, column = 0, padx =2, pady =2)
|
modifier1.grid(row = 0, column = 0, padx =5, pady =2)
|
||||||
|
|
||||||
#ALL.grid()
|
modifier2 = Checkbutton(modifiers,text="Send 2", variable=self.modifier2_value)
|
||||||
Song.grid(row = 0, column = 1, padx =5, pady =2)
|
modifier2.grid(row = 0, column = 1, padx =5, pady =2)
|
||||||
Pattern.grid(row = 0, column = 2, padx =5, pady =2)
|
|
||||||
|
modifier3 = Checkbutton(modifiers,text="Tape",variable=self.modifier3_value )
|
||||||
name_input.grid(row = 0, column = 0, padx =5, pady =0)
|
modifier3.grid(row = 0, column = 2, padx =5, pady =2)
|
||||||
#name_text.grid(row = 1, column = 2, padx =0, pady =0)
|
|
||||||
|
modifier4 = Checkbutton(modifiers,text="Master", variable= self.modifier4_value)
|
||||||
bpm_input.grid(row = 0, column = 1, padx =5, pady =0)
|
modifier4.grid(row = 0, column = 3, padx =5, pady =2)
|
||||||
#bpm_text.grid(row = 0, column = 0, padx =0, pady =0)
|
|
||||||
|
modifier5 = Checkbutton(modifiers,text="Perform", variable= self.modifier5_value)
|
||||||
#project_input.grid(row = 0, column = 2, padx =5, pady =0)
|
modifier5.grid(row = 0, column = 4, padx =5, pady =2)
|
||||||
|
|
||||||
bar_input.grid(row = 0, column = 3, padx =5, pady =2)
|
modifier6 = Checkbutton(modifiers,text="Module", variable=self.modifier6_value)
|
||||||
#bar_text.grid(row = 1, column = 2, padx =0, pady =0)
|
modifier6.grid(row = 0, column = 5, padx =5, pady =2)
|
||||||
|
|
||||||
patterns_input.grid(row = 0, column = 4, padx =5, pady =2)
|
set_param = Button(lowerframe, text="Set Prmtr",width = self.buttonsize_x, height = self.buttonsize_y, fg = 'white',bg= '#0095FF', command = self.setParam)
|
||||||
|
set_path = Button(lowerframe, text="Directory",width = self.buttonsize_x, height = self.buttonsize_y,fg = 'white',bg= '#0095FF', command = self.setPath)
|
||||||
add_sec.grid(row = 0, column = 5, padx =5, pady =2)
|
start_recording = Button(lowerframe, text="RECORD",width = self.buttonsize_x, height = self.buttonsize_y,fg = 'white', bg = '#FF2200', command = lambda:threading.Thread(target = self.sequenceMaster).start())
|
||||||
#add_text.grid(row = 1, column = 0, padx =0, pady =0)
|
|
||||||
|
tutorial = Label(footer,text="Enter Parameter, then press set Param, choose directory and start recording", height = 2, bg ='grey',fg= 'white', relief = FLAT)
|
||||||
set_param.grid(row = 0, column = 3, padx =5, pady =2)
|
display = Label(lowerframe,textvariable= self.displaymsg,width = 60, height = self.buttonsize_y -1, bg ='lightgrey', relief = FLAT)
|
||||||
set_path.grid(row = 0, column = 4, padx =5, pady =2)
|
|
||||||
start_recording.grid(row = 0, column = 5, padx =5, pady =2)
|
cancel = Button(lowerframe,text = "CANCEL" , width = self.buttonsize_x, height = self.buttonsize_y, bg ='#FFCC00', fg= 'white', command =self.cancelRec)
|
||||||
|
cancel.grid(row = 0, column = 6, padx =2, pady =2)
|
||||||
tutorial.grid(row = 1, column = 0, padx =5, pady =5, columnspan=5)
|
|
||||||
display.grid(row = 1, column = 0, padx =2, pady =10, columnspan= 7)
|
donate = Label(footer, text= "donate <3 @ https://link.raise-uav.com", height = 1)
|
||||||
|
donate.grid(row = 3, column = 4, padx =2, pady =10, columnspan=2)
|
||||||
|
|
||||||
|
Song.grid(row = 0, column = 1, padx =5, pady =2)
|
||||||
root.mainloop()
|
Pattern.grid(row = 0, column = 2, padx =5, pady =2)
|
||||||
|
|
||||||
|
self.name_input.grid(row = 0, column = 0, padx =5, pady =0)
|
||||||
|
self.bpm_input.grid(row = 0, column = 1, padx =5, pady =0)
|
||||||
|
self.bar_input.grid(row = 0, column = 3, padx =5, pady =2)
|
||||||
|
self.patterns_input.grid(row = 0, column = 4, padx =5, pady =2)
|
||||||
|
self.add_sec.grid(row = 0, column = 5, padx =5, pady =2)
|
||||||
|
|
||||||
|
set_param.grid(row = 0, column = 3, padx =5, pady =2)
|
||||||
|
set_path.grid(row = 0, column = 4, padx =5, pady =2)
|
||||||
|
start_recording.grid(row = 0, column = 5, padx =5, pady =2)
|
||||||
|
|
||||||
|
tutorial.grid(row = 1, column = 0, padx =5, pady =5, columnspan=5)
|
||||||
|
display.grid(row = 1, column = 0, padx =2, pady =10, columnspan= 7)
|
||||||
|
|
||||||
|
self.window.mainloop()
|
||||||
|
|
||||||
|
def getMIDIDevice(self):
|
||||||
|
#global device_list
|
||||||
|
#global op_device
|
||||||
|
device_list = mido.get_output_names()
|
||||||
|
print (device_list)
|
||||||
|
try:
|
||||||
|
self.op_device = list(filter(lambda x: 'OP-Z' in x, device_list))
|
||||||
|
self.op_device = self.op_device[0]
|
||||||
|
#print (self.op_device)
|
||||||
|
self.displaymsg.set("OP-Z found")
|
||||||
|
except:
|
||||||
|
self.displaymsg.set("Can´t find OP-Z : MIDI Error.")
|
||||||
|
|
||||||
|
def getAudioDevice(self):
|
||||||
|
#global audio_device
|
||||||
|
#global RATE
|
||||||
|
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:
|
||||||
|
self.audio_device = i
|
||||||
|
#audio_device = 4
|
||||||
|
print ("Detected OP-Z audio at Index:",self.audio_device, p.get_device_info_by_host_api_device_index(0, self.audio_device).get('name'))
|
||||||
|
except:
|
||||||
|
self.displaymsg.set("OP-Z Audio Device not found.")
|
||||||
|
|
||||||
|
#devinfo = p.get_device_info_by_index(self.audio_device)
|
||||||
|
try:
|
||||||
|
devinfo = p.get_device_info_by_index(self.audio_device)
|
||||||
|
test = p.is_format_supported(48000, input_device=devinfo['index'], input_channels=devinfo['maxInputChannels'],input_format=pyaudio.paInt16)
|
||||||
|
self.RATE = 48000
|
||||||
|
print("48kHz")
|
||||||
|
except:
|
||||||
|
self.RATE = 44100
|
||||||
|
print("44100kHz compatibility mode")
|
||||||
|
|
||||||
|
def getBPM(self):
|
||||||
|
inport= mido.open_input(self.op_device)
|
||||||
|
msg = inport.poll(self)
|
||||||
|
#print(msg)
|
||||||
|
|
||||||
|
def setLoop(self):
|
||||||
|
try:
|
||||||
|
bpm = self.bpm_input.get()
|
||||||
|
bar = self.bar_input.get()
|
||||||
|
addsec = self.add_sec.get()
|
||||||
|
self.loop_time = (240 / int(bpm) * int(bar)) + int(addsec)
|
||||||
|
print("Loop time set!", self.loop_time)
|
||||||
|
self.displaymsg.set("BPM Set!")
|
||||||
|
except:
|
||||||
|
self.displaymsg.set("Please enter accurate BPM.")
|
||||||
|
#return self.loop_time
|
||||||
|
|
||||||
|
def setParam(self):
|
||||||
|
self.setLoop()
|
||||||
|
#mode = mode_select.get()
|
||||||
|
#if mode == 2:
|
||||||
|
# projnr = project_input.get()
|
||||||
|
# setProject(projnr)
|
||||||
|
|
||||||
|
def openMidi(self):
|
||||||
|
#global outport
|
||||||
|
#global op_device
|
||||||
|
self.outport= mido.open_output(self.op_device)
|
||||||
|
#displaymsg.set("OP-Z MIDI not connected :(")
|
||||||
|
#print(self.outport)
|
||||||
|
|
||||||
|
def setProject(self,projnr):
|
||||||
|
msg= mido.Message('program_change',song= self.projnr, program = 1)
|
||||||
|
self.outport.send(msg)
|
||||||
|
|
||||||
|
def muteAll(self):
|
||||||
|
checkbutton_name = 0
|
||||||
|
#print(self.mute_list)
|
||||||
|
|
||||||
|
for j in range (0,8):
|
||||||
|
self.mute_list[j] = 1
|
||||||
|
|
||||||
|
for i in range (1,7):
|
||||||
|
checkbutton_name = 'self.modifier{}_value'.format(i) #checkbutton 1- 6
|
||||||
|
self.mute_list[i+7] = eval(checkbutton_name).get() #9th position in mute list
|
||||||
|
|
||||||
|
for k in range (0,14):
|
||||||
|
msg = mido.Message('control_change',control= 53, channel= k, value= self.mute_list[k])
|
||||||
|
self.outport.send(msg)
|
||||||
|
#print("Muted Channels",self.mute_list)
|
||||||
|
|
||||||
|
def setSolo(self,chn):
|
||||||
|
msg = mido.Message('control_change',control= 53, channel= chn, value=0)
|
||||||
|
self.outport.send(msg)
|
||||||
|
|
||||||
|
def start_MIDI(self):
|
||||||
|
msg = mido.Message('start')
|
||||||
|
self.outport.send(msg)
|
||||||
|
self.displaymsg.set("Playback started")
|
||||||
|
#print("midi")
|
||||||
|
|
||||||
|
def stop_MIDI(self):
|
||||||
|
msg = mido.Message('stop')
|
||||||
|
self.outport.send(msg)
|
||||||
|
self.displaymsg.set("Playback stopped")
|
||||||
|
|
||||||
|
def unmuteAll(self):
|
||||||
|
for i in range (0,15):
|
||||||
|
msg = mido.Message('control_change',control= 53, channel= i, value=0)
|
||||||
|
self.outport.send(msg)
|
||||||
|
|
||||||
|
def nextPattern(self):
|
||||||
|
msg = mido.Message('control_change', control = 103, value = 16)
|
||||||
|
self.outport.send(msg)
|
||||||
|
self.displaymsg.set("Next Pattern")
|
||||||
|
|
||||||
|
def nextSong(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def closeMidi(self):
|
||||||
|
self.outport.close()
|
||||||
|
self.displaymsg.set("MIDI closed")
|
||||||
|
|
||||||
|
def setPath(self):
|
||||||
|
#global path
|
||||||
|
folder = self.name_input.get()
|
||||||
|
path = fd.askdirectory()
|
||||||
|
self.displaymsg.set("Directory set!")
|
||||||
|
self.makeDir(path,folder)
|
||||||
|
|
||||||
|
def makeDir(self,path,folder):
|
||||||
|
#global folder
|
||||||
|
#global projectpath
|
||||||
|
#folder = name_input.get()
|
||||||
|
self.projectpath = path + '/' + folder
|
||||||
|
try:
|
||||||
|
os.mkdir(self.projectpath)
|
||||||
|
except:
|
||||||
|
self.displaymsg.set("Directory Error. Please enter different Name.")
|
||||||
|
|
||||||
|
def makeDirNr(self, pattern_nr):
|
||||||
|
#global projectpath
|
||||||
|
#Pfad wird addiert deswegen zusätzliche verzeichnisse
|
||||||
|
#projectpath = projectpath + '/' + str(pattern_nr)
|
||||||
|
try:
|
||||||
|
os.mkdir(self.projectpath + '/' + str(pattern_nr))
|
||||||
|
except:
|
||||||
|
self.displaymsg.set("Directory Error")
|
||||||
|
#print(projectpath)
|
||||||
|
|
||||||
|
def start_Rec(self):
|
||||||
|
#print("record")
|
||||||
|
self.displaymsg.set("Recording...")
|
||||||
|
CHUNK = 128
|
||||||
|
FORMAT = pyaudio.paInt16
|
||||||
|
CHANNELS = 2
|
||||||
|
|
||||||
|
RECORD_SECONDS= self.loop_time
|
||||||
|
#print("record")
|
||||||
|
WAVE_OUTPUT_FILENAME = self.name_input.get() + "_" + "track" + str(self.j+1) + ".wav"
|
||||||
|
#print(WAVE_OUTPUT_FILENAME)
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
stream = p.open(format=FORMAT,
|
||||||
|
channels=CHANNELS,
|
||||||
|
rate=self.RATE,
|
||||||
|
input=True,
|
||||||
|
input_device_index= self.audio_device,
|
||||||
|
frames_per_buffer=CHUNK
|
||||||
|
)
|
||||||
|
|
||||||
|
#print("* recording")
|
||||||
|
|
||||||
|
frames = []
|
||||||
|
self.start_MIDI()
|
||||||
|
for i in range(0, int(self.RATE / CHUNK * RECORD_SECONDS)):
|
||||||
|
data = stream.read(CHUNK)
|
||||||
|
frames.append(data)
|
||||||
|
|
||||||
|
#print("Done recording")
|
||||||
|
|
||||||
|
stream.stop_stream()
|
||||||
|
stream.close()
|
||||||
|
p.terminate()
|
||||||
|
if self.mode_select.get() == 2:
|
||||||
|
wf = wave.open(self.projectpath + '/' + str(self.pattern_nr) + '/' + WAVE_OUTPUT_FILENAME, 'wb')
|
||||||
|
else:
|
||||||
|
wf = wave.open(self.projectpath + '/' + WAVE_OUTPUT_FILENAME, 'wb')
|
||||||
|
|
||||||
|
wf.setnchannels(CHANNELS)
|
||||||
|
wf.setsampwidth(p.get_sample_size(FORMAT))
|
||||||
|
wf.setframerate(self.RATE)
|
||||||
|
wf.writeframes(b''.join(frames))
|
||||||
|
wf.close()
|
||||||
|
self.j = self.j + 1
|
||||||
|
if self.j == 8:
|
||||||
|
self.j= 0
|
||||||
|
self.displaymsg.set("End of Recording")
|
||||||
|
|
||||||
|
def sequenceMaster(self):
|
||||||
|
self.cancel = 0
|
||||||
|
self.getMIDIDevice()
|
||||||
|
time.sleep(1)
|
||||||
|
self.getAudioDevice()
|
||||||
|
self.displaymsg.set("Sequence started")
|
||||||
|
try:
|
||||||
|
self.openMidi()
|
||||||
|
if self.mode_select.get() == 2:
|
||||||
|
self.makeDirNr(self.pattern_nr)
|
||||||
|
|
||||||
|
for i in range (0,8):
|
||||||
|
pattern_limit = self.patterns_input.get()
|
||||||
|
if self.cancel == 1 or self.pattern_nr == pattern_limit:
|
||||||
|
break
|
||||||
|
#print("sequence started",i)
|
||||||
|
self.muteAll()
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.setSolo(i)
|
||||||
|
#starting Midi during wave record for timing
|
||||||
|
self.start_Rec()
|
||||||
|
self.stop_MIDI()
|
||||||
|
time.sleep(1)
|
||||||
|
self.unmuteAll()
|
||||||
|
time.sleep(1)
|
||||||
|
mode = self.mode_select.get()
|
||||||
|
|
||||||
|
if i == 7 and mode == 2:
|
||||||
|
#print(mode_select)
|
||||||
|
time.sleep(5)
|
||||||
|
self.nextPattern()
|
||||||
|
self.pattern_nr += 1
|
||||||
|
if self.pattern_nr == 15 :
|
||||||
|
self.pattern_nr = 0
|
||||||
|
self.sequenceMaster()
|
||||||
|
except:
|
||||||
|
self.displaymsg.set("OP-Z Sequence error try restarting the OP-Z or press CANCEL Button")
|
||||||
|
|
||||||
|
def cancelRec(self):
|
||||||
|
self.j = 0
|
||||||
|
self.cancel = 1
|
||||||
|
self.closeMidi()
|
||||||
|
|
||||||
|
|
||||||
|
underbridge = Midirecorder()
|
BIN
underbridge_mac.png
Normal file
BIN
underbridge_mac.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
Loading…
Reference in New Issue
Block a user