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 [2021/11/23 13:24] – [Control Signals] Álmos Veres-Vitályostest-and-measurement:analog-discovery-pro-3x50:midi [2022/10/04 11:38] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Building a MIDI Controller with Analog Discovery Pro (ADP3450/3250) ====== ====== Building a MIDI Controller with Analog Discovery Pro (ADP3450/3250) ======
 ~~TechArticle~~ ~~TechArticle~~
 +
 +{{ :test-and-measurement:analog-discovery-pro-3x50:bandlab_in_use.png?600 |}}
  
 <WRAP center round todo 60%> <WRAP center round todo 60%>
Line 132: Line 134:
 The control signals can be divided in three main categories: digital signals (coming from buttons, switches and rotary encoders), slowly changing analog signals (coming from potentiometers/sliders) and fast changing analog signals (coming from pressure sensitive pads). These three categories will be discussed separately, as the methods used to register them differ. The control signals can be divided in three main categories: digital signals (coming from buttons, switches and rotary encoders), slowly changing analog signals (coming from potentiometers/sliders) and fast changing analog signals (coming from pressure sensitive pads). These three categories will be discussed separately, as the methods used to register them differ.
  
-Digital signals can be directly connected in the driver circuit. They must be debounced (the mechanical noise created by the "bouncing" of the pressed pushbuttons must be filtered out) and might be latched (momentary buttons acting like switches). If some signals have to increment/decrement certain counters, these counters can also be implemented in the driver circuit. When the input signals are conditioned, they can be demultiplexed to the digital inputs of the ADP.+Digital signals can be directly connected in the driver circuit. They must be debounced (the mechanical noise created by the "bouncing" of the pressed pushbuttons must be filtered out) and might be latched (momentary buttons acting like switches). If some signals have to increment/decrement certain counters, these counters can also be implemented in the driver circuit. When the input signals are conditioned, they can be multiplexed to the digital inputs of the ADP.
 </WRAP> </WRAP>
  
-<WRAP group><WRAP half column>+<WRAP group>
 Slowly changing analog signals can't be directly measured by the digital inputs of the ADP. While the analog inputs (oscilloscope channels) can measure them directly, they should be used to record fast changing analog signals, so another solution should be found. One method to transform the analog signals to digital ones is by using comparators: the comparators can compare the provided voltage level to a fast changing sawtooth signal, and output a PWM signal for which the duty cycle is proportional with the voltage level of the original signal. This duty cycle can be measured on a single digital pin, using the logic analyzer. The generated PWM signal comes connected to the driver circuit to be multiplexed to the digital inputs of the ADP. Slowly changing analog signals can't be directly measured by the digital inputs of the ADP. While the analog inputs (oscilloscope channels) can measure them directly, they should be used to record fast changing analog signals, so another solution should be found. One method to transform the analog signals to digital ones is by using comparators: the comparators can compare the provided voltage level to a fast changing sawtooth signal, and output a PWM signal for which the duty cycle is proportional with the voltage level of the original signal. This duty cycle can be measured on a single digital pin, using the logic analyzer. The generated PWM signal comes connected to the driver circuit to be multiplexed to the digital inputs of the ADP.
-</WRAP><WRAP half column> +</WRAP>
-<html><iframe width="600" height="350" src="https://www.multisim.com/content/BCNHr52UHjWf3piskM4oRL/analog-to-duty/open"></iframe></html> +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column>+--> Click for Model and Simulation # 
 +<WRAP group> 
 +<html><iframe width="100%" height="600" src="https://www.multisim.com/content/BCNHr52UHjWf3piskM4oRL/analog-to-duty/open"></iframe></html> 
 +</WRAP> 
 +<-- 
 + 
 +<WRAP group>
 Fast changing analog signals can be measured by the oscilloscope channels. As there will be more signal sources, then channels, these signals have to be multiplexed as well. In the case of the drum pads, the generated pulses are all positive, so the easiest way of multiplexing them is for every channel to add the output of a drum pad to the inverted output of another drum pad. This way the number of input signals will be double the number of input channels and no digital signals are required to control the "multiplexer". The negative (inverted pulses) can be easily separated from the positive pulses via software. The only downside of this method is, that two simultaneous pulses with equal amplitude can cancel each other, but the probability of this is negligible (humans can't strike two drum pads in the exact same moment). Fast changing analog signals can be measured by the oscilloscope channels. As there will be more signal sources, then channels, these signals have to be multiplexed as well. In the case of the drum pads, the generated pulses are all positive, so the easiest way of multiplexing them is for every channel to add the output of a drum pad to the inverted output of another drum pad. This way the number of input signals will be double the number of input channels and no digital signals are required to control the "multiplexer". The negative (inverted pulses) can be easily separated from the positive pulses via software. The only downside of this method is, that two simultaneous pulses with equal amplitude can cancel each other, but the probability of this is negligible (humans can't strike two drum pads in the exact same moment).
-</WRAP><WRAP half column> +</WRAP> 
-<html><iframe width="600" height="350" src="https://www.multisim.com/content/kekFtHeuH3GvY4PwjPwEeG/piezo-driver/open"></iframe></html> + 
-</WRAP></WRAP>+--> Click for Model and Simulation # 
 +<WRAP group> 
 +<html><iframe width="100%" height="600" src="https://www.multisim.com/content/kekFtHeuH3GvY4PwjPwEeG/piezo-driver/open"></iframe></html> 
 +</WRAP> 
 +<--
 ---- ----
  
Line 152: Line 162:
 Design the user interface circuit to contain the control and indicator elements you want. Keep in mind the offered possibilities and limitations of the ADP3450, and the signal conditioning methods discussed above. Design the user interface circuit to contain the control and indicator elements you want. Keep in mind the offered possibilities and limitations of the ADP3450, and the signal conditioning methods discussed above.
 </WRAP><WRAP half column> </WRAP><WRAP half column>
 +{{ :test-and-measurement:analog-discovery-pro-3x50:pcb_3d.png?600 |}}
 </WRAP></WRAP> </WRAP></WRAP>
  
 <WRAP group> <WRAP group>
-For a detailed presentation of the user interface circuitry, you can check the drop-down below, or you can design your own custom user interface.+For a detailed presentation of the user interface circuitry used in this guide, you can check the drop-down below, or you can design your own custom user interface.
  
 --> The User Interface Circuit # --> The User Interface Circuit #
 <WRAP group> <WRAP group>
-=== Main Sound Control === +<WRAP group> 
-<WRAP half column> +=== Parts of the User Interface === 
-The most important control elements are the play/pause button, the record button, the volume slider and the channel selector button. To display the selected channel, this circuit part also contains a double seven segment display. +The user interface consists of five main parts: 
- +  * The most important control elements are the play/pause button, the record button, the volume slider and the channel selector button. To display the selected channel, this circuit part also contains a [[pmod:pmodssd:start|]] connected and driven by the digital driver (implemented on the Arty-S7 FPGA board). 
-Four RGB LEDs are also added to lit up this part of the circuit. +  * To further shave the sound of the controller, the second part contains three filters (low, middle and high). The analog-to-PWM converter for the volume slider and the filters is present in this block as well. Incremental rotary encoders are used to set the modulation, the attack, or the release time of the sounds. 
-</WRAP><WRAP half column> +  * In the third block, six potentiometers (with analog-to-PWM converters) are used to control the effects set in the DAW. 
 +  * While traditional keypads have more buttons, this controller only has 12: for the notes C, C#, D, D#, E, F, F#, G, G#, A, A# and B. Two additional buttons can increment and decrement the octave. The index of the chosen octave is displayed on a seven segment display. The RGB LEDs used to implement visual effects are connected to a connector for an open-drain MOSFET driver module ([[pmod:pmodod1:start|]]). 
 +  * The actual drum pads are mechanical parts, each one a disk containing a piezo, but the driver is implemented on the PCB. The outputs of the piezos are clamped and "multiplexed" with the method presented above.
 </WRAP> </WRAP>
  
-=== Additional Sound Control === +<WRAP group> 
-<WRAP half column> +=== Connecting the User Interface === 
-To further shave the sound of the controller, three filters (low, middle and high) are added. The analog-to-PWM converter for the volume slider is present in this block. Incremental rotary encoders are used to set the modulation, the attack, or the release time of the sounds.+Connect the output signals of the user interface to the FPGA board, but keep track of the connections, as they will have to be defined in the PLD design later, in Multisim (see below).
  
-The RGB LEDs are also present here, to provide the desired visual effects. +The BNC oscilloscope connectors are connected directly to the drum pad outputs (multiplexed) and the waveform generator channels are used to generate the reference signal for the PWM generator and the -5V DC voltage reference. The USB ports on the ADP are used to power and program the FPGA, connect the Wi-Fi dongle and supply power to the displays and LEDs through a USB connector.
-</WRAP><WRAP half column> +
- +
-</WRAP> +
- +
-=== Effect Control === +
-<WRAP half column> +
-Six potentiometers (with analog-to-PWM converters) are used to control the effects set in the DAW. +
-</WRAP><WRAP half column> +
- +
-</WRAP> +
- +
-=== Keypad === +
-<WRAP half column> +
-While traditional keypads have more buttons, this controller only has 12: for the notes C, C#, D, D#, E, F, F#, G, G#, A, A# and B. Two additional buttons can increment and decrement the octave. The index of the chosen octave is displayed on a seven segment display. +
- +
-The RGB LEDs are connected to a connector for an open-drain MOSFET driver module. +
-</WRAP><WRAP half column> +
- +
-</WRAP> +
- +
-=== Drum Pad (Driver) === +
-<WRAP half column> +
-The actual drum pads are mechanical parts, each one a disk containing a piezo, but the driver is implemented on the PCB. The outputs of the piezos are clamped and "multiplexed" with the method presented above. +
-</WRAP><WRAP half column>+
  
 +The Pmod connectors are used on the Arty-S7 to connect the user interface control elements, while the Chipkit analog headers are used to connect the displays and the LEDs. The ADP3450 digital pins are connected to the outer digital Chipkit header.
 </WRAP> </WRAP>
 </WRAP> </WRAP>
 <-- <--
 </WRAP> </WRAP>
----- 
- 
-==== Connecting the User Interface ==== 
-<WRAP group><WRAP half column> 
-Connect the output signals of the user interface to the FPGA board, but keep track of the connections, as they will have to be defined in the PLD design later, in Multisim (see below). 
- 
-The Pmod connectors are used on the Arty-S7 to connect the user interface control elements, while the Chipkit analog headers are used to connect the displays and the LEDs. The ADP3450 digital pins are connected to the outer digital Chipkit header. 
- 
-The BNC oscilloscope connectors are connected directly to the drum pad outputs (multiplexed) and the waveform generator channels are used to generate the reference signal for the PWM generator and the -5V DC voltage reference. The USB ports on the ADP are used to power and program the FPGA, connect the Wi-Fi dongle and supply power to the displays and LEDs through a USB connector. 
-</WRAP><WRAP half column> 
- 
-</WRAP></WRAP> 
 ---- ----
  
Line 221: Line 197:
 As most of the control signals are digital (including the converted "slow" analog signals), the conditioning circuits for them will be also digital. To prototype a complex digital circuit, the easiest way is to use an FPGA development board. In this project the Arty-S7 FPGA board will be used, for which the design will be created in Multisim, to avoid using VHDL, or Verilog (which can be challenging, especially for new users) and to make the final circuit easier to understand by drawing a schematic of it. As most of the control signals are digital (including the converted "slow" analog signals), the conditioning circuits for them will be also digital. To prototype a complex digital circuit, the easiest way is to use an FPGA development board. In this project the Arty-S7 FPGA board will be used, for which the design will be created in Multisim, to avoid using VHDL, or Verilog (which can be challenging, especially for new users) and to make the final circuit easier to understand by drawing a schematic of it.
  
-If your chosen FPGA board isn't available in Multisim PLD design, follow the instructions in [[link_to_hackster_page|this]] guide to create the configuration files for it.+If your chosen FPGA board isn't available in Multisim PLD design, follow the instructions in the [[learn:programmable-logic:tutorials:add_fpgas_to_multisim:start|]] guide to create the configuration files for it.
  
 Start a new PLD design in Multisim, select your board and create the conditioning circuits for your signals. You should use some digital I/O pins of the ADP3450 as outputs to control the multiplexers connected to the input pins, this way you can connect much more signals to the input, then the number of input pins. Start a new PLD design in Multisim, select your board and create the conditioning circuits for your signals. You should use some digital I/O pins of the ADP3450 as outputs to control the multiplexers connected to the input pins, this way you can connect much more signals to the input, then the number of input pins.
Line 231: Line 207:
  
 <WRAP group> <WRAP group>
-For a detailed presentation of the driver circuitry, you can check the drop-down below, or you can design your own driver on an FPGA board.+For a detailed presentation of the driver circuitry used in this guide, you can check the drop-down below, or you can design your own driver on an FPGA board.
  
 --> The Driver Circuit # --> The Driver Circuit #
 +<WRAP group>
 <WRAP group> <WRAP group>
 === Hierarchical Blocks === === Hierarchical Blocks ===
 +Before creating the driver, design and test certain circuits which will be used multiple times in the driver, to make your final design easier to create and to understand. Some blocks to create:  
 +  * clock divider - several D flip-flops are used to reduce the clock frequency to the desired value. If the clock rate must be further reduced, multiple clock divider blocks can be cascaded.
 +  * debouncer - when a button is pressed, some mechanical noise appears in the signal (the bouncing of the two metal plates on each other), so if the action is taken on the edge of the signal, the circuit will be triggered multiple times. A debouncer "validates" the output signal only after a certain time, so the bouncing can come to an end before.
 +  * latch - so buttons can be used as switches (on press turns the signal high, the next one turns it low).
 +  * 1:2 demultiplexer - Multisim contains only larger circuits (1:8).
 +  * up-down counter to N (0<N<15) - this circuit will be used to change the octaves (there are only 11 valid octaves, so counting to 15 is unnecessary).
 +  * pulse counter - as the Python script will use polling to measure every signal, it might miss certain events of the rotary encoders, so they should be re-encoded as numbers. This is why a pulse counter is designed, which is an up-down counter clocked by the two waves of the rotary encoder in quadrature. The block turns the incremental rotary encoders into 4-bit absolute encoders.
 +  * 7 segment display decoder - while 4-bit binary numbers might be easy to understand for machines, on a user interface (created for humans) numbers should appear in decimal representation. This is why a decoder must be used for the dual 7 segment displays, which displays a number between 1 and 16 (received in binary) in decimal representation.
 +  * display selector - while most FPGA boards have many pins, there are some cases, when "many" is still not enough. This is why the cathodes of the two dual displays should be multiplexed (the same cathodes are used in different times). This block takes two binary numbers (and one clock) as inputs and displays the first number on the first display (decoded) and the second number on the second display.
 +</WRAP>
 +
 <WRAP group> <WRAP group>
-Before creating the driver, design and test certain circuits which will be used multiple times in the driver, to make your final design easier to create and to understand.+=== Driver === 
 +After all the blocks were designed and tested, the actual driver can be built.
  
-<WRAP group><WRAP half column> +As almost all conditioning circuits need clock signals, the derived clocks (with the desired frequency) must be obtained from the FPGA clock. Use clock dividers to reduce the frequency.
-The first hierarchical block created is the clock divider. Several D flip-flops are used to reduce the clock frequency to the desired value. If the clock rate must be further reduced, multiple clock divider blocks can be cascaded. +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:clock_divider.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +The RGB LED control signals are just passed through the FPGA, they are entirely generated by the ADP. The PWM signals coming from the potentiometer conditioning circuits are again buffered, then sent to the multiplexers.
-One of the most important building blocks is the debouncer. When a button is pressed, some mechanical noise appears in the signal (the bouncing of the two metal plates on each other), so if the action is taken on the edge of the signal, the circuit will be triggered multiple times. A debouncer "validates" the output signal only after a certain time, so the bouncing can come to an end before. +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:debouncer.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +The play/pause and record buttons are debounced and latched to act like switches. The piano keys are debounced and sent to the multiplexers.
-A simple latch should also be implemented, so buttons can be used as switches (on press turns the signal high, the next one turns it low). +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:latch.png?400 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +The button selecting the MIDI channel is debounced, then connected to an up counter. The output of the counter is connected to the multiplexers. Octaves are set by two buttons: one buttons shifts the octave up, the other one down. The N counter block is used to set the upper limit of counting to 10 (the block will count from 0 to 10 - 11 positions).
-A 1:2 demultiplexer is also implemented as Multisim contains only larger circuits (1:8). +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:dmx12.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +The pulse counter block is used to turn the incremental encoder used as modulation wheel into an absolute encoder. The same is done for the timing wheel, but the latched timing button decides, if the output is used for the attack time, or for the release time (the distinction is made from software).
-The next block to be prepared is an up-down counter to N (0<N<15). This circuit will be used to change the octaves (there are only 11 valid octaves, so counting to 15 is unnecessary). +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:n_counter.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +The previously created hierarchical blocks are used to display the channel number and the octave index on the 7 segment displays.
-As the Python script will use polling to measure every signal, it might miss certain events of the rotary encoders, so they should be re-encoded as numbers. This is why a pulse counter is designed, which is an up-down counter clocked by the two waves of the rotary encoder in quadrature. The block turns the incremental rotary encoders into 4-bit absolute encoders. +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:pulse_counter.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +Finally, the conditioned output signals are multiplexed (4:1) to the digital I/O pins of the ADP. To generate the multiplexer addresses, two digital pins of the ADP are used, the address being generated from software. 
-While 4-bit binary numbers might be easy to understand for machines, on a user interface (created for humans) numbers should appear in decimal representation. This is why a decoder must be used for the dual 7 segment displays, which displays a number between 1 and 16 (received in binary) in decimal representation. +</WRAP>
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:7sd_decoder.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +<WRAP group> 
-While most FPGA boards have many pins, there are some cases, when "many" is still not enough. This is why the cathodes of the two dual displays should be multiplexed (the same cathodes are used in different times). This block takes two binary numbers (and one clock) as inputs and displays the first number on the first display (decoded) and the second number on the second display. +=== Connecting the Driver === 
-</WRAP><WRAP half column> +In Multisim, define the connections between the FPGA board and the ADP.
-{{ :test-and-measurement:analog-discovery-pro-3x50:7sd_mux.png?600 |}} +
-</WRAP></WRAP>+
 </WRAP> </WRAP>
 +</WRAP>
 +<--
 +</WRAP>
 +----
  
-=== Driver ===+===== Designing the Software ===== 
 +==== Hardware Abstraction Layer ==== 
 +<WRAP group> 
 +To make the program simpler and easier to understand, a sort of Hardware Abstraction Layer (HAL) is needed: a set of functions, which communicate with the hardware, and make the usage of the hardware easier. In this case the WaveForms SDK is used to control the ADP3450, but to further simplify the final script, the module created in the [[test-and-measurement:guides:waveforms-sdk-getting-started|]] guide will be used. 
 +</WRAP> 
 +---- 
 +==== Configuring the FPGA ====
 <WRAP group> <WRAP group>
-After all the blocks were designed and tested, the actual driver can be built.+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.
  
-<WRAP group><WRAP half column> +Create a module in which you use in a subprocess the commands 
-As almost all conditioning circuits need clock signals, the derived clocks (with the desired frequency) must be obtained from the FPGA clock. Use clock dividers to reduce the frequency. +<code>djtgcfg init -d ArtyS7</code> 
-</WRAP><WRAP half column> +and 
-{{ :test-and-measurement:analog-discovery-pro-3x50:clock_divider_wrapper.png?600 |}} +<code>djtgcfg prog -d ArtyS7 -i 0 -f ./FPGA/midi_driver_ArtyS7.bit</code>
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +**Note: **//Don't forget to change the device name and the name of the bit file to match to your preferences.//
-The RGB LED control signals are just passed through the FPGA, they are entirely generated by the ADP. +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:rgb_passthrough.png?400 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +<WRAP center round tip 80%> 
-The play/pause and record buttons are debounced and latched to act like switches. +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 half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:ply_rec_btn.png?400 |}}+
 </WRAP></WRAP> </WRAP></WRAP>
 +----
  
-<WRAP group><WRAP half column> +==== MIDI ==== 
-The PWM signals coming from the potentiometer conditioning circuits are again buffered, then sent to the multiplexers. +<WRAP group> 
-</WRAP><WRAP half column> +Start raveloxmidi in the background as a subprocess, to be able to communicate using RTPMIDI. Use the following command: 
-{{ :test-and-measurement:analog-discovery-pro-3x50:potentiometers_buffered.png?600 |}} +<code>sudo raveloxmidi -c ./MIDI/address.conf</code> 
-</WRAP></WRAP>+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> 
 +</WRAP>
  
-<WRAP group><WRAP half column> +<WRAP group> 
-The button selecting the MIDI channel is debounced, then connected to an up counter. The output of the counter is connected to the multiplexers. +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]].
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:channel_counter.png?600 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +See the drop-downs below for the most important MIDI messages.
-The pulse counter block is used to turn the incremental encoder used as modulation wheel into an absolute encoder. +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:modulation_counter.png?400 |}} +
-</WRAP></WRAP>+
  
-<WRAP group><WRAP half column> +--> MIDI Message Types ^ 
-The same is done for the timing wheel, but the latched timing button decides, if the output is used for the attack time, or for the release time (the distinction is made from software). +<WRAP group> 
-</WRAP><WRAP half column> +|<100% 10% 10% 50% 10% 10% 10%>| 
-{{ :test-and-measurement:analog-discovery-pro-3x50:timing_counter.png?400 |}} +^ Message Type  ^ Code ^ Meaning                                                       ^ Data Byte 1       ^ Data Byte 2 ^ 
-</WRAP></WRAP>+| NOTE_OFF      | 0x80 | This message is sent when a note is stopped.                  | Note number       | Velocity    | 
 +| NOTE_ON       | 0x90 | This message is sent when a note is started.                  | Note number       | Velocity    | 
 +| POLY_KEY_PRES | 0xA0 | Polyphonic Key Pressure (Aftertouch)                          | Note number       | Pressure    | 
 +| CTRL_CHG      | 0xB0 | Sent when a controller value changes.                         | Controller number | ...         | 
 +| PRG_CHG       | 0xC0 | Sent when a patch number changes.                             | Program number    | -           | 
 +| CH_PRS_AFTT   | 0xD0 | Channel Aftertouch                                            | Pressure          | -           | 
 +| PITCH_BND     | 0xE0 | This message is sent to indicate a change in the pitch wheel. | LSB               | MSB         | 
 +| SYS_EX_START  | 0xF0 | This message makes up for all that MIDI doesn't support.      | ...               | ...         | 
 +</WRAP> 
 +<--
  
-<WRAP group><WRAP half column> +<WRAP group><WRAP column half> 
-Octaves are set by two buttons: one buttons shifts the octave up, the other one down. The N counter block is used to set the upper limit of counting to 10 (the block will count from 0 to 10 - 11 positions). +--> MIDI Notes ^ 
-</WRAP><WRAP half column> +<WRAP group> 
-{{ :test-and-measurement:analog-discovery-pro-3x50:octave_counter.png?600 |}} +|<100% 50% 50%>| 
-</WRAP></WRAP> +^ Note ^ Value ^                                                       ^ 
- +| C    | 0     | 
-<WRAP group><WRAP half column> +| C#   | 1     | 
-The piano keys are debounced and sent to the multiplexers. +| D    | 2     | 
-</WRAP><WRAP half column> +| D#   | 3     | 
-{{ :test-and-measurement:analog-discovery-pro-3x50:piano_keys.png?600 |}} +| E    | 4     | 
-</WRAP></WRAP> +| F    | 5     | 
- +| F#   | 6     | 
-<WRAP group><WRAP half column> +| G    | 7     | 
-The previously created hierarchical blocks are used to display the channel number and the octave index on the 7 segment displays. +| G#   | 8     | 
-</WRAP><WRAP half column> +| A    | 9     | 
-{{ :test-and-measurement:analog-discovery-pro-3x50:7sd_wrapper.png?600 |}} +| A#   | 10    | 
-</WRAP></WRAP> +| B    | 11    |
- +
-<WRAP group><WRAP half column> +
-Finally, the conditioned output signals are multiplexed (4:1) to the digital I/O pins of the ADP. To generate the multiplexer addresses, two digital pins of the ADP are used, the address being generated from software. +
-</WRAP><WRAP half column> +
-{{ :test-and-measurement:analog-discovery-pro-3x50:driver_mux.png?200 |}} +
-</WRAP></WRAP>+
 </WRAP> </WRAP>
 +<--
 +</WRAP><WRAP column half>
 +--> MIDI Octaves ^
 +<WRAP group>
 +|<100% 20% 10% 70%>|
 +^ Notation     ^ Value ^ Meaning               ^
 +| DBL_CONTRA_O | 0     | Starts with $C_{-1}$. |
 +| SUB_CONTRA_O | 12    | Starts with $C_{0}$. |
 +| CONTRA_O     | 24    | Starts with $C_{1}$. |
 +| GREAT_O      | 36    | Starts with $C_{2}$. |
 +| SMALL_O      | 48    | Starts with $C_{3}$. |
 +| LINE1_O      | 60    | Starts with $C_{4}$. |
 +| LINE2_O      | 72    | Starts with $C_{5}$. |
 +| LINE3_O      | 84    | Starts with $C_{6}$. |
 +| LINE4_O      | 96    | Starts with $C_{7}$. |
 +| LINE5_O      | 108   | Starts with $C_{8}$. |
 +| LINE6_O      | 120   | Starts with $C_{9}$. |
 </WRAP> </WRAP>
 <-- <--
 +</WRAP></WRAP>
 </WRAP> </WRAP>
----- 
  
-==== Connecting the Driver ==== +<WRAP group> 
-<WRAP group><WRAP half column> +When you are finished, kill every process with the name "raveloxmidi" to terminate the connection. 
-In Multisim, define the connections between the FPGA board and the ADP. +</WRAP>
-</WRAP><WRAP half column> +
- +
-</WRAP></WRAP>+
 ---- ----
  
-===== Designing the Software ===== +==== MIDI Controller Script ==== 
-==== Hardware Abstraction Layer ====+<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.
  
 +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.)
  
-==== MIDI ==== +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.
- +
----- +
- +
-==== Program Body ====+
  
 +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.
 +</WRAP>
 ---- ----
  
Line 389: Line 365:
 Navigate into the project directory, then run the script by typing Navigate into the project directory, then run the script by typing
  
-<code>sudo python3 main.py</code>+<code>sudo python3 midi_controller.py</code>
 </WRAP><WRAP half column> </WRAP><WRAP half column>
 +{{ :test-and-measurement:analog-discovery-pro-3x50:sftp-winscp.png?600 |}}
 </WRAP></WRAP> </WRAP></WRAP>
  
Line 403: Line 379:
 Now you can use your wireless MIDI controller, to play any instrument you like - the limit is your imagination. You can expand the capabilities of your controller by adding extra digital and analog control elements, like sliders, more buttons, switches, etc. Now you can use your wireless MIDI controller, to play any instrument you like - the limit is your imagination. You can expand the capabilities of your controller by adding extra digital and analog control elements, like sliders, more buttons, switches, etc.
 </WRAP><WRAP half column> </WRAP><WRAP half column>
 +{{ :test-and-measurement:analog-discovery-pro-3x50:bandlab_in_use.png?600 |}}
 </WRAP></WRAP> </WRAP></WRAP>
 ---- ----