Convertisseur MIDI CV-GATE ultra simple
Cet article décrit la réalisation convertisseur MIDI CV-GATE pour synthétiseurs analogique ultra simple grâce à l'utilisation d'un microcontrôleur Attiny85 programmable avec l'IDE Arduino.
C’est un tutoriel sur l’utilisation de l'USI sur l’ATtiny en tant que périphérique UART-RX et le MIDI est aussi efficace que toute application pour un UART.
Il y a 3 sorties supplémentaires non utilisées sur l'ATtiny45 / 85 qui peuvent être utilisées pour CV / Gates / Triggers ou Sync. Si vous exécutez ce code sur l’ATtiny44 / 84, 10 sorties au total peuvent être utilisées.
Si vous n'aimez pas ces convertisseurs USB-MIDI sophistiqués ou si vous êtes obligés de convertir votre clavier MIDI en signal CV / Gate pour un équipement vintage, vous pouvez réaliser ce montage.
L’entrée MIDI est une entrée TTL et nécessite l’optocoupleur habituel.
La sortie Gate est de 5 volts pour la note activée et de 0 volt pour la note désactivée.
Remarque: la puce peut fonctionner avec une alimentation fantôme MIDI, mais pour que le CV soit réglé correctement, la tension d'alimentation doit être exactement de 5 volts.
Programme
Deux principaux fonctions de base sont nécessaires à la fabrication du convertisseur:
L'ATtiny n’ayant pas de CAN, nous en créons un en utilisant le PWM.
Il manque également une RS232 mais nous pouvons utiliser le périphérique USI pour cela.
Ce code prend en charge la configuration du PWM et de l'USI.
Ensuite, nous avons besoin d’une interruption de changement d'état pour gérer le bit de départ dans l’entrée série MIDI.
Les données MIDI sont des données série à 31250 bits / s, de sorte qu'une durée de bit équivaut à 32 microsecondes.
Le début d'un octet provoque une interruption de changement d'état de broche. Dans la routine d’interruption, nous vérifions qu’il s’agit d’un front descendant et, si tel est le cas, nous configurons le Timer / Counter0 en mode CTC. Nous voulons mettre en place un délai d'un demi-bit, pour entrer au milieu du bit de départ. Le plus proche que nous pouvons obtenir est un pré-décaleur de 8 et une comparaison de 32. Enfin, nous désactivons et activons l'interruption de comparaison de sortie.
L'interruption de correspondance de comparaison se produit au milieuL'interruption de comparaison se produit au milieu du bit de début. Dans la routine d'interruption, nous réinitialisons la correspondance avec la durée d'un bit, 64 (32uS), permettons à l'USI de commencer à décaler les bits de données lors de la comparaison suivante et activons l'interruption de dépassement d'USI.
Notez que nous définissons le mode de connexion sur 0 avec 0 << USIWM0. Cela garantit que la sortie du registre à décalage USI n'affectera pas la broche de sortie audio, PB1.
Lorsque 8 bits ont été décalés dans l’USI, une interruption de débordement se produit. La routine d'interruption désactive l'USI, lit le registre à décalage USI et active l'interruption de changement de broche prête pour l'octet suivant.
L'UART envoie les bits LSB en premier, tandis que l'USI suppose que le MSB est le premier. Nous devons donc inverser l'ordre des bits après la réception.
Les valeurs de CV de 240 notes sont trop peu nombreuses pour ajouter un pitchbend.
Nous utilisons donc une autre sortie PWM et un filtre RC qui fournit la valeur de pitchbend. Ce CV peut être utilisé séparément ou ajouté à la note CV au moyen d’une résistance de 4,7K.
Ajoutez ce code à la fonction setup et au gestionnaire MIDI:
Le CV de sortie pour pitchbend sera sur PB4 (broche 3 de la puce).
C’est un tutoriel sur l’utilisation de l'USI sur l’ATtiny en tant que périphérique UART-RX et le MIDI est aussi efficace que toute application pour un UART.
Il y a 3 sorties supplémentaires non utilisées sur l'ATtiny45 / 85 qui peuvent être utilisées pour CV / Gates / Triggers ou Sync. Si vous exécutez ce code sur l’ATtiny44 / 84, 10 sorties au total peuvent être utilisées.
Si vous n'aimez pas ces convertisseurs USB-MIDI sophistiqués ou si vous êtes obligés de convertir votre clavier MIDI en signal CV / Gate pour un équipement vintage, vous pouvez réaliser ce montage.
Electronique
Le convertisseur MIDI2CV prend une entrée TTL-MIDI et génère un CV 1V / Octave et un signal Gate.
Le brochage pour l'ATtiny45 / 85 est :
- PB0 est l'entrée MIDI.
- PB1 est la sortie CV.
- PB2 est la sortie de la porte
L’entrée MIDI est une entrée TTL et nécessite l’optocoupleur habituel.
La sortie CV est un signal PWM et nécessite un filtre passe-bas. La plage est C2-C7, 0-5 volts.
La sortie Gate est de 5 volts pour la note activée et de 0 volt pour la note désactivée.
Remarque: la puce peut fonctionner avec une alimentation fantôme MIDI, mais pour que le CV soit réglé correctement, la tension d'alimentation doit être exactement de 5 volts.
Programme
Deux principaux fonctions de base sont nécessaires à la fabrication du convertisseur:
- Convertisseur AD / A pour la sortie CV
- Une entrée série UART pour le MIDI
L'ATtiny n’ayant pas de CAN, nous en créons un en utilisant le PWM.
Il manque également une RS232 mais nous pouvons utiliser le périphérique USI pour cela.
Ce code prend en charge la configuration du PWM et de l'USI.
//Set Fuses to E1 DD FE for PLLCLK 16MHz //Global variables for the MIDI handler volatile uint8_t MIDISTATE=0; volatile uint8_t MIDIRUNNINGSTATUS=0; volatile uint8_t MIDINOTE; volatile uint8_t MIDIVEL; void setup() { // Enable 64 MHz PLL and use as source for Timer1 PLLCSR = 1< // Set up Timer/Counter1 for PWM output TIMSK = 0; // Timer interrupts OFF TCCR1 = 1< // Setup GPIO pinMode(1, OUTPUT); // Enable PWM output pin pinMode(0, INPUT); // Enable USI input pin pinMode(2, OUTPUT); // Enable Gate output pin //Setup the USI USICR = 0; // Disable USI. GIFR = 1< GIMSK |= 1< PCMSK |= 1< GTCCR = 0; OCR1C = 239; //Set count to semi tones OCR1A = 0; //Set initial Pitch to C2 digitalWrite(2,LOW); //Set initial Gate to LOW; } |
Ensuite, nous avons besoin d’une interruption de changement d'état pour gérer le bit de départ dans l’entrée série MIDI.
Les données MIDI sont des données série à 31250 bits / s, de sorte qu'une durée de bit équivaut à 32 microsecondes.
ISR (PCINT0_vect) { if (!(PINB & 1< GIMSK &= ~(1< TCCR0A = 2< TCCR0B = 0< TCNT0 = 0; // Count up from 0 OCR0A = 31; // Delay (31+1)*8 cycles TIFR |= 1< TIMSK |= 1< } } |
ISR (TIMER0_COMPA_vect) { TIMSK &= ~(1< TCNT0 = 0; // Count up from 0 OCR0A = 63; // Shift every (63+1)*8 cycles 32uS // Enable USI OVF interrupt, and select Timer0 compare match as USI Clock source: USICR = 1< USISR = 1< } |
Lorsque 8 bits ont été décalés dans l’USI, une interruption de débordement se produit. La routine d'interruption désactive l'USI, lit le registre à décalage USI et active l'interruption de changement de broche prête pour l'octet suivant.
ISR (USI_OVF_vect) { uint8_t MIDIRX; USICR = 0; // Disable USI MIDIRX = USIDR; GIFR = 1< GIMSK |= 1< //Wrong bit order so swap it MIDIRX = ((MIDIRX >> 1) & 0x55) | ((MIDIRX << 1) & 0xaa); MIDIRX = ((MIDIRX >> 2) & 0x33) | ((MIDIRX << 2) & 0xcc); MIDIRX = ((MIDIRX >> 4) & 0x0f) | ((MIDIRX << 4) & 0xf0); //Parse MIDI data if ((MIDIRX>0xBF)&&(MIDIRX<0xf8 code="">0xf8> MIDIRUNNINGSTATUS=0; MIDISTATE=0; return ; } if (MIDIRX>0xF7) return ; if (MIDIRX & 0x80) { MIDIRUNNINGSTATUS=MIDIRX; MIDISTATE=1; return ; } if (MIDIRX < 0x80) { if (!MIDIRUNNINGSTATUS) return ; if (MIDISTATE==1) { MIDINOTE=MIDIRX; MIDISTATE++; return ; } if (MIDISTATE==2) { MIDIVEL=MIDIRX; MIDISTATE=1; if ((MIDIRUNNINGSTATUS==0x80)||(MIDIRUNNINGSTATUS==0x90)) { if (MIDINOTE<36 code="" midinote="36;"> MIDINOTE=MIDINOTE-36; //Subtract 36 to get into CV range if (MIDINOTE>60) MIDINOTE=60; //If note is higher than C7 set it to C7 if (MIDIRUNNINGSTATUS == 0x90) { //If note on if (MIDIVEL>0) digitalWrite(2, HIGH); //Set Gate HIGH if (MIDIVEL==0) digitalWrite(2, LOW); //Set Gate LOW OCR1A = MIDINOTE<<2 code=""> } if (MIDIRUNNINGSTATUS == 0x80) { //If note off digitalWrite(2, LOW); //Set Gate LOW OCR1A = MIDINOTE<<2 code=""> } } return ; } } |
L'UART envoie les bits LSB en premier, tandis que l'USI suppose que le MSB est le premier. Nous devons donc inverser l'ordre des bits après la réception.
Le gestionnaire MIDI est également inclus ici.
L'état actuel est ce que 99% de tous les synthétiseurs et séquenceurs MIDI font aujourd'hui, ce qui signifie que si l'octet d'état est le même que le précédent, il n'est pas transmis, ce qui entraîne moins d'octets sur la ligne.
Gestion de «l'état de fonctionnement»
1. La mémoire tampon est effacée (c'est-à-dire mise à 0) à la mise sous tension.
2. Le tampon stocke l’état lorsqu’un état de catégorie de voix (0x80 à 0xEF) est reçu.
3. La mémoire tampon est effacée lors de la réception d'un statut de catégorie système commun (c'est-à-dire 0xF0 à 0xF7).
4. Rien n'est fait dans la mémoire tampon lorsqu'un message de catégorie RealTime est reçu.
5. Tous les octets de données sont ignorés lorsque la mémoire tampon est à 0.
Le gestionnaire gère le statut en cours et appelle les fonctions noteon / noteoff et CC.
Les octets 0x80, 0x90 et 0xB0 correspondent au statut MIDI pour Note-on, Note-off et MIDI-CC sur le canal n ° 01. Si vous voulez un autre canal de réception, par exemple le canal 02, vous modifiez le quartet inférieur en 0x01, c’est-à-dire 0x91.
De plus, la majorité des émetteurs utilisent Note-on avec une vélocité nulle pour la Note-off.
La sortie CV est dans la plage C2 à C7 (0-5 volts). Nous soustrayons donc 36 de la clé pour rendre C2 0 volt.
Nous vérifions également si la note est supérieure à C7, ce qui correspond à 5 volts, et la limitons.
Ensuite, nous écrivons la clé dans la sortie du CV.
8 bits est en fait une résolution trop basse pour la hauteur mais une astuce le fait fonctionner.
La plage de CV est définie sur 0-239 au lieu de 255, ce qui donne à chaque semi-ton 4 étapes exactement.
Si l'événement est une note, nous définissons la sortie Gate à l'état haut.
Voici le code complet:
L'état actuel est ce que 99% de tous les synthétiseurs et séquenceurs MIDI font aujourd'hui, ce qui signifie que si l'octet d'état est le même que le précédent, il n'est pas transmis, ce qui entraîne moins d'octets sur la ligne.
Gestion de «l'état de fonctionnement»
1. La mémoire tampon est effacée (c'est-à-dire mise à 0) à la mise sous tension.
2. Le tampon stocke l’état lorsqu’un état de catégorie de voix (0x80 à 0xEF) est reçu.
3. La mémoire tampon est effacée lors de la réception d'un statut de catégorie système commun (c'est-à-dire 0xF0 à 0xF7).
4. Rien n'est fait dans la mémoire tampon lorsqu'un message de catégorie RealTime est reçu.
5. Tous les octets de données sont ignorés lorsque la mémoire tampon est à 0.
Le gestionnaire gère le statut en cours et appelle les fonctions noteon / noteoff et CC.
Les octets 0x80, 0x90 et 0xB0 correspondent au statut MIDI pour Note-on, Note-off et MIDI-CC sur le canal n ° 01. Si vous voulez un autre canal de réception, par exemple le canal 02, vous modifiez le quartet inférieur en 0x01, c’est-à-dire 0x91.
De plus, la majorité des émetteurs utilisent Note-on avec une vélocité nulle pour la Note-off.
La sortie CV est dans la plage C2 à C7 (0-5 volts). Nous soustrayons donc 36 de la clé pour rendre C2 0 volt.
Nous vérifions également si la note est supérieure à C7, ce qui correspond à 5 volts, et la limitons.
Ensuite, nous écrivons la clé dans la sortie du CV.
8 bits est en fait une résolution trop basse pour la hauteur mais une astuce le fait fonctionner.
La plage de CV est définie sur 0-239 au lieu de 255, ce qui donne à chaque semi-ton 4 étapes exactement.
Si l'événement est une note, nous définissons la sortie Gate à l'état haut.
Voici le code complet:
// (*) All in the spirit of open-source and open-hardware // Janost 2019 Sweden // The goMIDI2CV interface // http://blog.dspsynth.eu/diy-good-ol-midi-to-cv/ // Copyright 2019 DSP Synthesizers Sweden. // // Author: Jan Ostman // // This program is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. //Set Fuses to E1 DD FE for PLLCLK 16MHz #include #include #include #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif volatile uint8_t MIDISTATE=0; volatile uint8_t MIDIRUNNINGSTATUS=0; volatile uint8_t MIDINOTE; volatile uint8_t MIDIVEL; void setup() { // Enable 64 MHz PLL and use as source for Timer1 PLLCSR = 1< // Set up Timer/Counter1 for PWM output TIMSK = 0; // Timer interrupts OFF TCCR1 = 1< // Setup GPIO pinMode(1, OUTPUT); // Enable PWM output pin pinMode(0, INPUT); // Enable USI input pin pinMode(2, OUTPUT); // Enable Gate output pin //Setup the USI USICR = 0; // Disable USI. GIFR = 1< GIMSK |= 1< PCMSK |= 1< GTCCR = 0; OCR1C = 239; //Set count to semi tones OCR1A = 0; //Set initial Pitch to C2 digitalWrite(2,LOW); //Set initial Gate to LOW; } ISR (PCINT0_vect) { if (!(PINB & 1< GIMSK &= ~(1< TCCR0A = 2< TCCR0B = 0< TCNT0 = 0; // Count up from 0 OCR0A = 31; // Delay (31+1)*8 cycles TIFR |= 1< TIMSK |= 1< } } ISR (TIMER0_COMPA_vect) { TIMSK &= ~(1< TCNT0 = 0; // Count up from 0 OCR0A = 63; // Shift every (63+1)*8 cycles 32uS // Enable USI OVF interrupt, and select Timer0 compare match as USI Clock source: USICR = 1< USISR = 1< } ISR (USI_OVF_vect) { uint8_t MIDIRX; USICR = 0; // Disable USI MIDIRX = USIDR; GIFR = 1< GIMSK |= 1< //Wrong bit order so swap it MIDIRX = ((MIDIRX >> 1) & 0x55) | ((MIDIRX << 1) & 0xaa); MIDIRX = ((MIDIRX >> 2) & 0x33) | ((MIDIRX << 2) & 0xcc); MIDIRX = ((MIDIRX >> 4) & 0x0f) | ((MIDIRX << 4) & 0xf0); //Parse MIDI data if ((MIDIRX>0xBF)&&(MIDIRX<0xf8 code="">0xf8> MIDIRUNNINGSTATUS=0; MIDISTATE=0; return ; } if (MIDIRX>0xF7) return ; if (MIDIRX & 0x80) { MIDIRUNNINGSTATUS=MIDIRX; MIDISTATE=1; return ; } if (MIDIRX < 0x80) { if (!MIDIRUNNINGSTATUS) return ; if (MIDISTATE==1) { MIDINOTE=MIDIRX; MIDISTATE++; return ; } if (MIDISTATE==2) { MIDIVEL=MIDIRX; MIDISTATE=1; if ((MIDIRUNNINGSTATUS==0x80)||(MIDIRUNNINGSTATUS==0x90)) { if (MIDINOTE<36 code="" midinote="36;"> MIDINOTE=MIDINOTE-36; //Subtract 36 to get into CV range if (MIDINOTE>60) MIDINOTE=60; //If note is higher than C7 set it to C7 if (MIDIRUNNINGSTATUS == 0x90) { //If note on if (MIDIVEL>0) digitalWrite(2, HIGH); //Set Gate HIGH if (MIDIVEL==0) digitalWrite(2, LOW); //Set Gate LOW OCR1A = MIDINOTE<<2 code=""> } if (MIDIRUNNINGSTATUS == 0x80) { //If note off digitalWrite(2, LOW); //Set Gate LOW OCR1A = MIDINOTE<<2 code=""> } } return ; } } void loop() { } |
Ajouter un CV pitchbend
Nous utilisons donc une autre sortie PWM et un filtre RC qui fournit la valeur de pitchbend. Ce CV peut être utilisé séparément ou ajouté à la note CV au moyen d’une résistance de 4,7K.
Ajoutez ce code à la fonction setup et au gestionnaire MIDI:
//Setup addon for pitchbend output pinMode(4, OUTPUT); // Enable PB4 output pin for pitchbend CV GTCCR = 1< //USI_OVF_vect addon if (MIDIRUNNINGSTATUS == 0xE0) { //If pitchbend data if (MIDIVEL<4 code="" midivel="4;"> if (MIDIVEL>119) MIDIVEL=119; //Limit pitchbend to +60 MIDIVEL-=4; //Center the pitchbend value OCR1B = (MIDIVEL<<1 code=""> } |
Commentaires
Enregistrer un commentaire