Differences
This shows you the differences between two versions of the page.
| test-and-measurement:analog-discovery-pro-3x50:midi [2021/11/24 14:34] – [Testing] Álmos Veres-Vitályos | test-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/ | ====== Building a MIDI Controller with Analog Discovery Pro (ADP3450/ | ||
| ~~TechArticle~~ | ~~TechArticle~~ | ||
| + | |||
| + | {{ : | ||
| <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/ | 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/ | ||
| - | Digital signals can be directly connected in the driver circuit. They must be debounced (the mechanical noise created by the " | + | Digital signals can be directly connected in the driver circuit. They must be debounced (the mechanical noise created by the " |
| </ | </ | ||
| Line 164: | Line 166: | ||
| <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 |
| --> 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: |
| - | + | | |
| - | 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. |
| - | </ | + | * In the third block, six potentiometers (with analog-to-PWM converters) are used to control the effects set in the DAW. |
| - | {{ :test-and-measurement:analog-discovery-pro-3x50:main_sound.png? | + | * 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 " | ||
| </ | </ | ||
| - | === 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 | + | Connect |
| - | The RGB LEDs are also present here, to provide | + | The BNC oscilloscope connectors |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | === Effect Control === | + | The Pmod connectors |
| - | <WRAP half column> | + | |
| - | Six potentiometers (with analog-to-PWM converters) | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| - | + | ||
| - | === 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 RGB LEDs are connected to a connector for an open-drain MOSFET driver module. | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| - | + | ||
| - | === 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 " | + | |
| - | </ | + | |
| - | {{ : | + | |
| </ | </ | ||
| </ | </ | ||
| <-- | <-- | ||
| </ | </ | ||
| - | ---- | ||
| - | |||
| - | ==== Connecting the User Interface ==== | ||
| - | <WRAP group>< | ||
| - | Connect the output signals of the user interface to the FPGA board, but keep track of the connections, | ||
| - | |||
| - | 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 group>< | ||
| - | 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. | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| ---- | ---- | ||
| Line 243: | 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 |
| --> The Driver Circuit # | --> The Driver Circuit # | ||
| + | <WRAP group> | ||
| <WRAP group> | <WRAP group> | ||
| === Hierarchical Blocks === | === Hierarchical Blocks === | ||
| - | <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. |
| - | 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. | + | |
| - | + | * debouncer | |
| - | <WRAP group>< | + | * latch - so buttons can be used as switches (on press turns the signal high, the next one turns it low). |
| - | The first hierarchical block created is the clock divider. Several | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | * pulse counter |
| - | </ | + | * 7 segment display decoder |
| - | + | * display selector | |
| - | <WRAP group>< | + | |
| - | 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 " | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP group>< | + | |
| - | A simple latch should also be implemented, | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP group>< | + | |
| - | A 1:2 demultiplexer | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP group>< | + | |
| - | The next block to be prepared is an up-down counter to N (0< | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP group>< | + | |
| - | 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. | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP group>< | + | |
| - | 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. | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | + | ||
| - | <WRAP group>< | + | |
| - | While most FPGA boards have many pins, there are some cases, when " | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| </ | </ | ||
| + | <WRAP group> | ||
| === Driver === | === Driver === | ||
| - | <WRAP group> | ||
| After all the blocks were designed and tested, the actual driver can be built. | After all the blocks were designed and tested, the actual driver can be built. | ||
| - | <WRAP group>< | ||
| 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. | 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. | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| - | <WRAP group>< | + | 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. |
| - | The RGB LED control signals are just passed through the FPGA, they are entirely generated by the ADP. | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| - | <WRAP group>< | + | The play/pause and record buttons are debounced and latched to act like switches. |
| - | The play/pause and record buttons are debounced and latched to act like switches. | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | <WRAP group>< | + | The button selecting |
| - | The PWM signals coming from the potentiometer conditioning circuits are again buffered, then sent to the multiplexers. | + | |
| - | </ | + | |
| - | {{ :test-and-measurement: | + | |
| - | </ | + | |
| - | <WRAP group>< | + | 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 |
| - | The button selecting the MIDI channel | + | |
| - | </ | + | |
| - | {{ : | + | |
| - | </ | + | |
| - | <WRAP group>< | ||
| - | The pulse counter block is used to turn the incremental encoder used as modulation wheel into an absolute encoder. | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| - | |||
| - | <WRAP group>< | ||
| - | 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>< | ||
| - | 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). | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| - | |||
| - | <WRAP group>< | ||
| - | The piano keys are debounced and sent to the multiplexers. | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| - | |||
| - | <WRAP group>< | ||
| The previously created hierarchical blocks are used to display the channel number and the octave index on the 7 segment displays. | The previously created hierarchical blocks are used to display the channel number and the octave index on the 7 segment displays. | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| - | <WRAP group>< | ||
| 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. | 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. | ||
| - | </ | ||
| - | {{ : | ||
| - | </ | ||
| </ | </ | ||
| - | </ | ||
| - | <-- | ||
| - | </ | ||
| - | ---- | ||
| - | ==== Connecting the Driver ==== | ||
| <WRAP group> | <WRAP group> | ||
| + | === Connecting the Driver === | ||
| In Multisim, define the connections between the FPGA board and the ADP. | In Multisim, define the connections between the FPGA board and the ADP. | ||
| - | + | </ | |
| - | {{ : | + | </ |
| + | <-- | ||
| </ | </ | ||
| ---- | ---- | ||
| Line 390: | Line 259: | ||
| ---- | ---- | ||
| ==== Configuring the FPGA ==== | ==== Configuring the FPGA ==== | ||
| - | <WRAP group>< | + | <WRAP group> |
| To configure the FPGA board connected to the ADP3450, with the bit file created with Multisim, the [[https:// | To configure the FPGA board connected to the ADP3450, with the bit file created with Multisim, the [[https:// | ||
| Line 397: | Line 266: | ||
| and | and | ||
| < | < | ||
| + | |||
| **Note: **// | **Note: **// | ||
| - | </WRAP>< | + | |
| - | <script | + | < |
| - | </ | + | 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. |
| + | </ | ||
| ---- | ---- | ||
| ==== MIDI ==== | ==== MIDI ==== | ||
| - | [[content]] | + | <WRAP group> |
| + | Start raveloxmidi in the background as a subprocess, to be able to communicate using RTPMIDI. Use the following command: | ||
| + | < | ||
| + | Don't forget to change the path of the configuration file, to a file, which contains the bind address: " | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | <WRAP group> | ||
| + | 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:// | ||
| + | |||
| + | See the drop-downs below for the most important MIDI messages. | ||
| + | |||
| + | --> MIDI Message Types ^ | ||
| + | <WRAP group> | ||
| + | |<100% 10% 10% 50% 10% 10% 10%>| | ||
| + | ^ Message Type ^ Code ^ Meaning | ||
| + | | NOTE_OFF | ||
| + | | NOTE_ON | ||
| + | | POLY_KEY_PRES | 0xA0 | Polyphonic Key Pressure (Aftertouch) | ||
| + | | CTRL_CHG | ||
| + | | PRG_CHG | ||
| + | | CH_PRS_AFTT | ||
| + | | PITCH_BND | ||
| + | | SYS_EX_START | ||
| + | </ | ||
| + | <-- | ||
| + | |||
| + | <WRAP group>< | ||
| + | --> MIDI Notes ^ | ||
| + | <WRAP group> | ||
| + | |<100% 50% 50%>| | ||
| + | ^ Note ^ Value ^ ^ | ||
| + | | C | 0 | | ||
| + | | C# | 1 | | ||
| + | | D | 2 | | ||
| + | | D# | 3 | | ||
| + | | E | 4 | | ||
| + | | F | 5 | | ||
| + | | F# | 6 | | ||
| + | | G | 7 | | ||
| + | | G# | 8 | | ||
| + | | A | 9 | | ||
| + | | A# | 10 | | ||
| + | | B | 11 | | ||
| + | </ | ||
| + | <-- | ||
| + | </ | ||
| + | --> MIDI Octaves ^ | ||
| + | <WRAP group> | ||
| + | |<100% 20% 10% 70%>| | ||
| + | ^ Notation | ||
| + | | DBL_CONTRA_O | 0 | Starts with $C_{-1}$. | | ||
| + | | SUB_CONTRA_O | 12 | Starts with $C_{0}$. | | ||
| + | | CONTRA_O | ||
| + | | GREAT_O | ||
| + | | SMALL_O | ||
| + | | LINE1_O | ||
| + | | LINE2_O | ||
| + | | LINE3_O | ||
| + | | LINE4_O | ||
| + | | LINE5_O | ||
| + | | LINE6_O | ||
| + | </ | ||
| + | <-- | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP group> | ||
| + | When you are finished, kill every process with the name " | ||
| + | </ | ||
| ---- | ---- | ||
| - | ==== Program Body ==== | + | ==== MIDI Controller Script |
| - | [[content]] | + | <WRAP group> |
| + | In your wrapper script, define the connections between the devices and other parameters like the frequency and amplitude/ | ||
| + | |||
| + | 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.) | ||
| + | |||
| + | 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. | ||
| + | |||
| + | 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. | ||
| + | </ | ||
| ---- | ---- | ||
| Line 417: | Line 365: | ||
| Navigate into the project directory, then run the script by typing | Navigate into the project directory, then run the script by typing | ||
| - | < | + | < |
| </ | </ | ||
| - | [[image]] | + | {{ : |
| </ | </ | ||

