Differences

This shows you the differences between two versions of the page.

Link to this comparison view

test-and-measurement:analog-discovery-pro-3x50:midi [2022/04/04 10:52] – [User Interface Design] Álmos Veres-Vitályostest-and-measurement:analog-discovery-pro-3x50:midi [2022/10/04 11:38] (current) – external edit 127.0.0.1
Line 259: Line 259:
 ---- ----
 ==== Configuring the FPGA ==== ==== Configuring the FPGA ====
-<WRAP group><WRAP half column>+<WRAP group>
 To configure the FPGA board connected to the ADP3450, with the bit file created with Multisim, the [[https://mautic.digilentinc.com/adept-utilities-download|Adept Utilities]] must be installed on your device. To install the software, follow the [[test-and-measurement:analog-discovery-pro-3x50:programming-an-fpga|]] guide. To configure the FPGA board connected to the ADP3450, with the bit file created with Multisim, the [[https://mautic.digilentinc.com/adept-utilities-download|Adept Utilities]] must be installed on your device. To install the software, follow the [[test-and-measurement:analog-discovery-pro-3x50:programming-an-fpga|]] guide.
  
Line 266: Line 266:
 and and
 <code>djtgcfg prog -d ArtyS7 -i 0 -f ./FPGA/midi_driver_ArtyS7.bit</code> <code>djtgcfg prog -d ArtyS7 -i 0 -f ./FPGA/midi_driver_ArtyS7.bit</code>
 +
 **Note: **//Don't forget to change the device name and the name of the bit file to match to your preferences.// **Note: **//Don't forget to change the device name and the name of the bit file to match to your preferences.//
-</WRAP><WRAP half column><code python> 
-""" This module realizes communication with the FPGA board """ 
- 
-from subprocess import Popen, PIPE 
- 
-"""-------------------------------------------------------------------""" 
-""" UPLOADING THE BIT FILE """ 
-"""-------------------------------------------------------------------""" 
- 
- 
-def configure(description_file="./FPGA/MIDI_UI_Arty_S7.bit", device_name="ArtyS7", chip_index="0"): 
-    """ 
-        configures the connected FPGA board 
- 
-        parameters: - bit file 
-                    - device name 
-                    - chip index 
- 
-        returns:    - True on success, False on error 
-    """ 
-    # initialize the FPGA board 
-    process = Popen(["djtgcfg", "init", "-d", device_name], 
-                     stdout=PIPE, stderr=PIPE) 
-    stdout, stderr = process.communicate() 
-    stdout = stdout.decode("UTF-8") 
-    stderr = stderr.decode("UTF-8") 
- 
-    # check response 
-    if stderr != "" or not ("Found Device ID" in stdout): 
-        return False 
- 
-    # upload the bit file 
-    process = Popen(["djtgcfg", "prog", "-d", device_name, 
-                     "-i", chip_index, "-f", description_file], 
-                     stdout=PIPE, stderr=PIPE) 
-    stdout, stderr = process.communicate() 
-    stdout = stdout.decode("UTF-8") 
-    stderr = stderr.decode("UTF-8") 
- 
-    # check response 
-    if stderr != "" or not ("Programming succeeded" in stdout): 
-        return False 
- 
-    return True 
- 
- 
-"""-------------------------------------------------------------------""" 
  
-</code></WRAP></WRAP>+<WRAP center round tip 80%> 
 +In your script, check for the responses of the commands to determine if the operation was successful, or not. You can try the commands first in a terminal to check possible responses. 
 +</WRAP></WRAP>
 ---- ----
  
 ==== MIDI ==== ==== MIDI ====
-<WRAP group><WRAP half column>+<WRAP group>
 Start raveloxmidi in the background as a subprocess, to be able to communicate using RTPMIDI. Use the following command: Start raveloxmidi in the background as a subprocess, to be able to communicate using RTPMIDI. Use the following command:
 <code>sudo raveloxmidi -c ./MIDI/address.conf</code> <code>sudo raveloxmidi -c ./MIDI/address.conf</code>
 Don't forget to change the path of the configuration file, to a file, which contains the bind address: "0.0.0.0". Don't forget to change the path of the configuration file, to a file, which contains the bind address: "0.0.0.0".
 <code>network.bind_address = 0.0.0.0</code> <code>network.bind_address = 0.0.0.0</code>
-</WRAP><WRAP half column><code python> +</WRAP>
-""" This module contains the functions needed to send MIDI messages """ +
-""" More information:  +
-            https://github.com/ravelox/pimidi/tree/master/python """+
  
-"""-------------------------------------------------------------------""" +<WRAP group>
-""" GLOBAL """ +
-"""-------------------------------------------------------------------""" +
- +
- +
-import sys  # interactions with the interpreter +
-import socket   # socket operations +
-import struct   # conversion between Python values and C type data +
-from subprocess import Popen, PIPE # system calls +
-from MIDI.message import *   # import all MIDI messages +
- +
-sock = None +
- +
-"""-------------------------------------------------------------------""" +
-""" INITIALIZATION """ +
-"""-------------------------------------------------------------------""" +
- +
- +
-def open(configuration_file="./MIDI/address.conf", localport=5006): +
-    """ +
-        start ravelomidi +
-         +
-        parameters: - configuration file path +
-                    - local port +
-    """ +
-    # start raveloxmidi in the background +
-    Popen(["sudo", "raveloxmidi", "-c", configuration_file]) +
- +
-    global sock # load variable +
- +
-    # local variables +
-    family = None +
-    connect_tuple = None +
- +
-    # defining connection parameters +
-    # code snippet from the RaveloxMIDI examples +
-    if len(sys.argv) == 1: +
-        family = socket.AF_INET +
-        connect_tuple = ("localhost", localport) +
-    else: +
-        details = socket.getaddrinfo( +
-            sys.argv[1], localport, socket.AF_UNSPEC, socket.SOCK_DGRAM) +
-        family = details[0][0] +
-        if family == socket.AF_INET6: +
-            connect_tuple = (sys.argv[1], localport, 0, 0) +
-        else: +
-            connect_tuple = (sys.argv[1], localport) +
- +
-    # connect socket +
-    sock = socket.socket(family, socket.SOCK_DGRAM) +
-    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +
-    sock.connect(connect_tuple) +
-    return +
-</code></WRAP></WRAP> +
- +
-<WRAP group><WRAP half column>+
 While the background process is running, you can send data sockets containing MIDI data. An extensive list of possible MIDI messages is available on the page [[https://wiki.cockos.com/wiki/index.php/MIDI_Specification|MIDI Specification]] and [[https://anotherproducer.com/online-tools-for-musicians/midi-cc-list/|MIDI CC List for Continuous Controllers]]. While the background process is running, you can send data sockets containing MIDI data. An extensive list of possible MIDI messages is available on the page [[https://wiki.cockos.com/wiki/index.php/MIDI_Specification|MIDI Specification]] and [[https://anotherproducer.com/online-tools-for-musicians/midi-cc-list/|MIDI CC List for Continuous Controllers]].
  
-Open the drop-downs below for the most important MIDI messages.+See the drop-downs below for the most important MIDI messages.
  
---> MIDI Message Types #+--> MIDI Message Types ^
 <WRAP group> <WRAP group>
 |<100% 10% 10% 50% 10% 10% 10%>| |<100% 10% 10% 50% 10% 10% 10%>|
Line 404: Line 302:
 <-- <--
  
---> MIDI Notes #+<WRAP group><WRAP column half> 
 +--> MIDI Notes ^
 <WRAP group> <WRAP group>
 |<100% 50% 50%>| |<100% 50% 50%>|
Line 422: Line 321:
 </WRAP> </WRAP>
 <-- <--
- +</WRAP><WRAP column half> 
---> MIDI Octaves #+--> MIDI Octaves ^
 <WRAP group> <WRAP group>
 |<100% 20% 10% 70%>| |<100% 20% 10% 70%>|
Line 440: Line 339:
 </WRAP> </WRAP>
 <-- <--
-</WRAP><WRAP half column><code python> +</WRAP></WRAP> 
-"""-------------------------------------------------------------------""" +</WRAP>
-""" SENDING """ +
-"""-------------------------------------------------------------------"""+
  
- +<WRAP group>
-def send(msg_type, channel, data): +
-    """ +
-        send a message +
-         +
-        parameters: - message type: from MIDI.message +
-                    - midi channel: 0-15 +
-                    - data: from MIDI.message +
-    """ +
-    # get data length +
-    length = len(data) +
- +
-    # get message length +
-    byte_count = "B" +
-    for _ in range(length): +
-        byte_count = byte_count + "B" +
- +
-    # construct the message +
-    # pack a binary structure with all the data words +
-    message = None +
-    if length == 1: +
-        message = struct.pack(byte_count, msg_type + channel, data[0]) +
-    elif length == 2: +
-        message = struct.pack(byte_count, msg_type + channel, data[0], data[1]) +
-    elif length == 3: +
-        message = struct.pack(byte_count, msg_type + +
-                              channel, data[0], data[1], data[2]) +
-    elif length == 4: +
-        message = struct.pack(byte_count, msg_type + channel, +
-                              data[0], data[1], data[2], data[3]) +
-    elif length == 5: +
-        message = struct.pack(byte_count, msg_type + channel, +
-                              data[0], data[1], data[2], data[3], data[4]) +
-    elif length == 6: +
-        message = struct.pack(byte_count, msg_type + channel, +
-                              data[0], data[1], data[2], data[3], data[4], data[5]) +
-    else: +
-        message = struct.pack(byte_count, msg_type + channel, +
-                              data[0], data[1], data[2], data[3], data[4], data[5], data[6]) +
- +
-    # send message +
-    sock.send(message) +
-    return +
-</code></WRAP></WRAP> +
- +
-<WRAP group><WRAP half column>+
 When you are finished, kill every process with the name "raveloxmidi" to terminate the connection. When you are finished, kill every process with the name "raveloxmidi" to terminate the connection.
-</WRAP><WRAP half column><code python> +</WRAP> 
-"""-------------------------------------------------------------------""" +----
-""" CLEANUP """ +
-"""-------------------------------------------------------------------"""+
  
 +==== MIDI Controller Script ====
 +<WRAP group>
 +In your wrapper script, define the connections between the devices and other parameters like the frequency and amplitude/offset of the output signals, then import your HAL, the previously defined MIDI commands, functions and constants and the FPGA programming function. Use these modules to upload the bit file to the FPGA, start raveloxmidi and initialize the WaveForms SDK.
  
-def close(): +Start the WaveForms instruments needed in your controller: start the power supplies, generate the necessary analog and digital signals, set static DIO pins to the desired state and initialize the oscilloscope and the logic analyzer. (Don't forget to close these instruments and disconnect from the ADP at the end of your script! Also stop raveloxmidi when the script is terminated.)
-    """ +
-        stop ravelomidi +
-    """ +
-    # close socket +
-    sock.close()+
  
-    # find remaining processes +The rest of your code should run in an infinite loop, broken only by pressing Ctrl+C. In each iteration set the address pins of the multiplexers in the driver to 0, 1, 2, or 3 (implement a 2 bit counter here), then read the current state of the multiplexer outputs. Decode these outputs according to the current address and compare the results to the previous ones. If there is no change in the state of a user interface element, no new command should be sent, but if there is a change, send the respective MIDI command with raveloxmidi.
-    process = Popen(["sudo", "ps", "u"], stdout=PIPE, stderr=PIPE) +
-    stdout, _ = process.communicate() +
-    stdout = stdout.decode("UTF-8") +
-    processes = stdout.split("root") +
-    processes.pop(0) +
-    proc_id = [] +
-    for index in range(len(processes)): +
-        processes[index] = processes[index].split() +
-        for property in processes[index]: +
-            if property == "raveloxmidi": +
-                proc_id.append(processes[index][0]) +
-                continue+
  
-    # kill the processes +You might also want to set some visual effects using the RGB LEDs. Use your creativity to modify the colors according to the received data. 
-    success_flag = True +</WRAP>
-    for pid in proc_id: +
-        try: +
-            Popen(["sudo", "kill", "-SIGKILL", pid]) +
-        except: +
-            success_flag = False +
-    return success_flag +
- +
- +
-"""-------------------------------------------------------------------""" +
- +
-</code></WRAP></WRAP> +
----- +
- +
-==== Program Body ==== +
-[[content]]+
 ---- ----
  
Line 546: Line 367:
 <code>sudo python3 midi_controller.py</code> <code>sudo python3 midi_controller.py</code>
 </WRAP><WRAP half column> </WRAP><WRAP half column>
-[[image]]+{{ :test-and-measurement:analog-discovery-pro-3x50:sftp-winscp.png?600 |}}
 </WRAP></WRAP> </WRAP></WRAP>