2022-03-28 17:37:27 +02:00
# Underbridge OP-Z multichannel exporter
# Copyright 2022 Thomas Herrmann Email: herrmann@raise-uav.com
2022-03-28 13:02:05 +02:00
import mido
import pyaudio
import wave
from tkinter import *
from tkinter import filedialog as fd
import time
import threading
import os
loop_time = 0
inport = 0
outport = 0
path = 0
folder = 0
2022-03-28 15:01:27 +02:00
pattern_nr = 0
2022-03-28 13:02:05 +02:00
j = 0
mode_select = 0
addsec = 0
2022-03-28 15:01:27 +02:00
projectpath = 0
2022-03-28 17:37:27 +02:00
cancel = 0
2022-03-28 15:01:27 +02:00
2022-03-28 13:02:05 +02:00
2022-03-28 17:37:27 +02:00
def getMIDIDevice ( ) :
2022-03-28 13:02:05 +02:00
pass
def getBPM ( ) :
inport = mido . open_input ( ' OP-Z:OP-Z MIDI 1 20:0 ' )
msg = inport . poll ( )
2022-03-28 17:37:27 +02:00
#print(msg)
2022-03-28 13:02:05 +02:00
def setLoop ( ) :
global loop_time
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! " )
return time
def setParam ( ) :
setLoop ( )
2022-03-28 15:01:27 +02:00
#mode = mode_select.get()
#if mode == 2:
# projnr = project_input.get()
# setProject(projnr)
2022-03-28 13:02:05 +02:00
def openMidi ( ) :
global outport
outport = mido . open_output ( ' OP-Z:OP-Z MIDI 1 20:0 ' )
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 " )
2022-03-28 15:01:27 +02:00
def unmuteAll ( ) :
global outport
for i in range ( 0 , 15 ) :
msg = mido . Message ( ' control_change ' , control = 53 , channel = i , value = 0 )
2022-03-28 17:37:27 +02:00
outport . send ( msg )
2022-03-28 15:01:27 +02:00
2022-03-28 13:02:05 +02:00
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 ( ) :
pass
def setPath ( ) :
global path
folder = name_input . get ( )
path = fd . askdirectory ( )
displaymsg . set ( " Directory set " )
makeDir ( )
def makeDir ( ) :
global folder
2022-03-28 15:01:27 +02:00
global projectpath
2022-03-28 13:02:05 +02:00
folder = name_input . get ( )
2022-03-28 15:01:27 +02:00
projectpath = path + ' / ' + folder
2022-03-28 17:37:27 +02:00
try :
os . mkdir ( projectpath )
except :
displaymsg . set ( " Directory Error " )
2022-03-28 15:01:27 +02:00
def makeDirNr ( pattern_nr ) :
global projectpath
2022-03-28 15:41:09 +02:00
#Pfad wird addiert deswegen zusätzliche verzeichnisse
#projectpath = projectpath + '/' + str(pattern_nr)
2022-03-28 17:37:27 +02:00
try :
os . mkdir ( projectpath + ' / ' + str ( pattern_nr ) )
except :
displaymsg . set ( " Directory Error " )
#print(projectpath)
2022-03-28 13:02:05 +02:00
def start_Rec ( ) :
displaymsg . set ( " Recording... " )
global path
global time
global j
2022-03-28 15:01:27 +02:00
global pro
2022-03-28 15:41:09 +02:00
global pattern_nr
2022-03-28 13:02:05 +02:00
CHUNK = 1024
FORMAT = pyaudio . paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = loop_time
WAVE_OUTPUT_FILENAME = name_input . get ( ) + " _ " + " track " + str ( j + 1 ) + " .wav "
p = pyaudio . PyAudio ( )
2022-03-28 17:37:27 +02:00
start_MIDI ( )
2022-03-28 13:02:05 +02:00
stream = p . open ( format = FORMAT ,
channels = CHANNELS ,
rate = RATE ,
input = True ,
frames_per_buffer = CHUNK
)
2022-03-28 17:37:27 +02:00
#print("* recording")
2022-03-28 13:02:05 +02:00
frames = [ ]
for i in range ( 0 , int ( RATE / CHUNK * RECORD_SECONDS ) ) :
data = stream . read ( CHUNK )
frames . append ( data )
2022-03-28 17:37:27 +02:00
#print("Done recording")
2022-03-28 13:02:05 +02:00
stream . stop_stream ( )
stream . close ( )
p . terminate ( )
2022-03-28 15:41:09 +02:00
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 ' )
2022-03-28 13:02:05 +02:00
wf . setnchannels ( CHANNELS )
wf . setsampwidth ( p . get_sample_size ( FORMAT ) )
wf . setframerate ( RATE )
wf . writeframes ( b ' ' . join ( frames ) )
wf . close ( )
j = j + 1
2022-03-28 15:41:09 +02:00
if j == 8 :
j = 0
2022-03-28 13:02:05 +02:00
displaymsg . set ( " End of Recording " )
def sequenceMaster ( ) :
2022-03-28 17:37:27 +02:00
global cancel
2022-03-28 15:01:27 +02:00
global pattern_nr
2022-03-28 17:37:27 +02:00
cancel = 0
2022-03-28 18:03:23 +02:00
#print("test")
displaymsg . set ( " Sequence started " )
openMidi ( )
2022-03-28 15:01:27 +02:00
if mode_select . get ( ) == 2 :
makeDirNr ( pattern_nr )
2022-03-28 13:02:05 +02:00
2022-03-28 18:03:23 +02:00
for i in range ( 0 , 8 ) : #
pattern_limit = patterns_input . get ( )
if cancel == 1 or pattern_nr == pattern_limit :
break
#print("sequence started",i)
2022-03-28 13:02:05 +02:00
muteAll ( )
setSolo ( i )
#starting Midi during wave record for timing
2022-03-28 17:37:27 +02:00
start_Rec ( )
2022-03-28 13:02:05 +02:00
#print(i)
stop_MIDI ( )
2022-03-28 17:37:27 +02:00
unmuteAll ( )
2022-03-28 18:03:23 +02:00
mode = mode_select . get ( )
2022-03-28 13:02:05 +02:00
if i == 7 and mode == 2 :
2022-03-28 17:37:27 +02:00
#print(mode_select)
2022-03-28 13:02:05 +02:00
time . sleep ( 5 )
nextPattern ( )
2022-03-28 15:01:27 +02:00
pattern_nr + = 1
2022-03-28 17:37:27 +02:00
if pattern_nr == 9 :
2022-03-28 15:01:27 +02:00
pattern_nr = 0
2022-03-28 17:37:27 +02:00
sequenceMaster ( )
2022-03-28 18:03:23 +02:00
2022-03-28 17:37:27 +02:00
def cancelRec ( ) :
global cancel
global j
j = 0
cancel = 1
2022-03-28 13:02:05 +02:00
#GUI Main
buttonsize_x = 8
buttonsize_y = 2
mode_select = 0
root = Tk ( )
root . title ( ' underbridge for OP-Z ' )
root . resizable ( width = False , height = False ) #565A5E
root . tk_setPalette ( background = ' #565A5E ' , foreground = ' black ' , activeBackground = ' #283867 ' , activeForeground = ' black ' )
upperframe = LabelFrame ( root , text = " Parameter " , padx = 10 , pady = 10 , fg = ' white ' )
upperframe . grid ( row = 0 , column = 0 , padx = 2 , pady = 2 , columnspan = 7 )
2022-03-28 18:22:47 +02:00
lowerframe = Frame ( root , padx = 10 , pady = 10 )
2022-03-28 13:02:05 +02:00
lowerframe . grid ( row = 1 , column = 0 , padx = 2 , pady = 2 , columnspan = 7 )
2022-03-28 17:37:27 +02:00
footer = Frame ( root , padx = 15 , pady = 10 )
footer . grid ( row = 2 , column = 0 , padx = 2 , pady = 2 , columnspan = 7 )
2022-03-28 13:02:05 +02:00
mode_select = IntVar ( )
displaymsg = StringVar ( )
#root.geometry('550x150+0+0')
Get_BPM = Button ( upperframe , text = " Get BPM " , width = buttonsize_x , height = buttonsize_y , fg = ' white ' , command = lambda : getBPM ( ) )
#ALL = Radiobutton(lowerframe, text= 'ALL', value = 1 , variable = mode_select, width = buttonsize_x, height = buttonsize_y , indicatoron = 0, bg= '#1b7d24' )
Song = Radiobutton ( lowerframe , text = ' Project ' , value = 2 , variable = mode_select , width = buttonsize_x , height = buttonsize_y , indicatoron = 0 , bg = ' #1b7d24 ' )
Pattern = Radiobutton ( lowerframe , text = ' Pattern ' , value = 3 , variable = mode_select , width = buttonsize_x , height = buttonsize_y , indicatoron = 0 , bg = ' #1b7d24 ' )
Pattern . select ( )
bar_input = Scale ( upperframe , from_ = 1 , to = 4 , orient = HORIZONTAL , label = " Nr. Bars " , sliderlength = 10 , length = 75 , fg = ' white ' )
#bar_text = Label(upperframe,text="Nr. of Bars", width = 8, height = 1)
patterns_input = Scale ( upperframe , from_ = 1 , to = 10 , orient = HORIZONTAL , label = " Patterns " , sliderlength = 10 , length = 75 , fg = ' white ' )
2022-03-28 18:03:23 +02:00
patterns_input . set ( value = 10 )
2022-03-28 13:02:05 +02:00
bpm_input = Entry ( upperframe , width = 10 , text = " BPM " , bg = ' white ' )
#bpm_text = Label(upperframe,text="BPM", width = 8, height = 1)
bpm_input . insert ( 0 , " BPM " )
#project_input = Entry(upperframe, width =10, text="Project",bg= 'white')
#bpm_text = Label(upperframe,text="BPM", width = 8, height = 1)
#project_input.insert(0, "Project Nr.")
add_sec = Scale ( upperframe , from_ = 0 , to = 10 , orient = HORIZONTAL , label = " extra Sec " , sliderlength = 10 , length = 75 , fg = ' white ' )
#add_text = Label(upperframe,text="Sec offset", width = 8, height = 1)
name_input = Entry ( upperframe , width = 10 , text = " Name " , bg = ' white ' )
name_input . insert ( 0 , " Name " )
#name_text = Label(upperframe,text="Prj Name", width = 8, height = 1)
2022-03-28 18:03:23 +02:00
set_param = Button ( lowerframe , text = " set Param " , width = buttonsize_x , height = buttonsize_y , fg = ' white ' , bg = ' #0095FF ' , command = lambda : setParam ( ) )
set_path = Button ( lowerframe , text = " Directory " , width = buttonsize_x , height = buttonsize_y , fg = ' white ' , bg = ' #0095FF ' , command = lambda : setPath ( ) )
start_recording = Button ( lowerframe , text = " RECORD " , width = buttonsize_x , height = buttonsize_y , fg = ' white ' , bg = ' #FF2200 ' , command = lambda : threading . Thread ( target = sequenceMaster ) . start ( ) )
2022-03-28 17:37:27 +02:00
2022-03-28 18:22:47 +02:00
tutorial = Label ( footer , text = " Enter Parameter, then press set Param, choose directory and start recording " , width = 70 , height = 2 , bg = ' grey ' , fg = ' white ' , relief = SUNKEN )
2022-03-28 17:37:27 +02:00
display = Label ( footer , textvariable = displaymsg , width = 15 , height = 2 , bg = ' white ' , relief = SUNKEN )
2022-03-28 18:03:23 +02:00
cancel = Button ( lowerframe , text = " CANCEL " , width = buttonsize_x , height = buttonsize_y , bg = ' #FFCC00 ' , fg = ' white ' , command = lambda : cancelRec ( ) )
2022-03-28 17:37:27 +02:00
cancel . grid ( row = 1 , column = 6 , padx = 2 , pady = 2 )
2022-03-28 13:02:05 +02:00
2022-03-28 17:37:27 +02:00
donate = Label ( footer , text = " donate <3 @ https://link.raise-uav.com " , width = 40 , height = 1 )
donate . grid ( row = 3 , column = 5 , padx = 2 , pady = 2 , columnspan = 2 )
2022-03-28 13:02:05 +02:00
#Get_BPM.grid(row = 1, column = 0, padx =2, pady =2)
2022-03-28 17:37:27 +02:00
#ALL.grid()
2022-03-28 13:02:05 +02:00
Song . grid ( row = 1 , column = 1 , padx = 5 , pady = 2 )
Pattern . grid ( row = 1 , column = 2 , padx = 5 , pady = 2 )
name_input . grid ( row = 0 , column = 0 , padx = 5 , pady = 0 )
#name_text.grid(row = 1, column = 2, padx =0, pady =0)
bpm_input . grid ( row = 0 , column = 1 , padx = 5 , pady = 0 )
#bpm_text.grid(row = 0, column = 0, padx =0, pady =0)
#project_input.grid(row = 0, column = 2, padx =5, pady =0)
bar_input . grid ( row = 0 , column = 3 , padx = 5 , pady = 2 )
#bar_text.grid(row = 1, column = 2, padx =0, pady =0)
patterns_input . grid ( row = 0 , column = 4 , padx = 5 , pady = 2 )
add_sec . grid ( row = 0 , column = 5 , padx = 5 , pady = 2 )
#add_text.grid(row = 1, column = 0, padx =0, pady =0)
2022-03-28 18:22:47 +02:00
set_param . grid ( row = 1 , column = 3 , padx = 5 , pady = 5 )
set_path . grid ( row = 1 , column = 4 , padx = 5 , pady = 5 )
start_recording . grid ( row = 1 , column = 5 , padx = 5 , pady = 5 )
2022-03-28 13:02:05 +02:00
2022-03-28 18:22:47 +02:00
tutorial . grid ( row = 2 , column = 0 , padx = 2 , pady = 5 , columnspan = 6 )
2022-03-28 17:37:27 +02:00
display . grid ( row = 3 , column = 0 , padx = 2 , pady = 5 )
2022-03-28 13:02:05 +02:00
root . mainloop ( )