|
| 1 | +''' |
| 2 | + Refer to https://github.com/fluxly/Fluxamasynth. |
| 3 | +''' |
| 4 | + |
| 5 | + |
| 6 | +from machine import UART, Pin |
| 7 | + |
| 8 | + |
| 9 | +MIDI_CMD_NOTE_OFF = 0x80 # Note Off |
| 10 | +MIDI_CMD_NOTE_ON = 0x90 # Note On |
| 11 | +MIDI_CMD_POLYPHONIC_AFTERTOUCH = 0xA0 # Polyphonic Aftertouch (or Key Pressure) |
| 12 | +MIDI_CMD_CONTROL_CHANGE = 0xB0 # Control Change (or Channel Mode Message) |
| 13 | +MIDI_CMD_PROGRAM_CHANGE = 0xC0 # Program Change |
| 14 | +MIDI_CMD_CHANNEL_AFTERTOUCH = 0xD0 # Channel Aftertouch (or Channel Pressure) |
| 15 | +MIDI_CMD_PITCH_BEND = 0xE0 # Pitch Bend |
| 16 | +MIDI_CMD_SYSTEM_EXCLUSIVE = 0xF0 # System Exclusive (SysEx) Start |
| 17 | +MIDI_CMD_TIME_CODE = 0xF1 # MIDI Time Code Quarter Frame |
| 18 | +MIDI_CMD_SONG_POSITION = 0xF2 # Song Position Pointer |
| 19 | +MIDI_CMD_SONG_SELECT = 0xF3 # Song Select |
| 20 | +MIDI_CMD_TUNE_REQUEST = 0xF6 # Tune Request |
| 21 | +MIDI_CMD_END_OF_SYSEX = 0xF7 # End of SysEx |
| 22 | +MIDI_CMD_TIMING_CLOCK = 0xF8 # Timing Clock (used in System Real-Time Messages) |
| 23 | +MIDI_CMD_START = 0xFA # Start (used in System Real-Time Messages) |
| 24 | +MIDI_CMD_CONTINUE = 0xFB # Continue (used in System Real-Time Messages) |
| 25 | +MIDI_CMD_STOP = 0xFC # Stop (used in System Real-Time Messages) |
| 26 | +MIDI_CMD_ACTIVE_SENSING = 0xFE # Active Sensing (used in System Real-Time Messages) |
| 27 | +MIDI_CMD_SYSTEM_RESET = 0xFF # System Reset |
| 28 | + |
| 29 | +DRUM_SET ={ "Closed Hi Hat [EXC1]" :[27, 49], |
| 30 | + "Pedal Hi-Hat [EXC1]" :[28, 49], |
| 31 | + "Open Hi Hat [EXC1]" :[29, 49], |
| 32 | + "Ride Cymbal" :[30, 49], |
| 33 | + "Kick drum2" :[35, 1], |
| 34 | + "Jazz BD 2" :[35, 41], |
| 35 | + "Kick drum" :[35, 128], |
| 36 | + "Kick drum1" :[36, 1], |
| 37 | + "Jazz BD 1" :[36, 41], |
| 38 | + # "Kick drum" :[36, 128], |
| 39 | + "Side Stick" :[37, 1], |
| 40 | + "Rim Shot" :[37, 128], |
| 41 | + "Snare Drum 1" :[38, 1], |
| 42 | + "Gated Snare" :[38, 17], |
| 43 | + "Brush Tap" :[38, 41], |
| 44 | + "Snare Drum 2" :[38, 49], |
| 45 | + "Snare Drum" :[38, 128], |
| 46 | + "Hand Clap" :[39, 1], |
| 47 | + "Brush Slap" :[39, 41], |
| 48 | + "Castanets" :[39, 49], |
| 49 | + "Hand Clap" :[39, 128], |
| 50 | + "Snare Drum 2" :[40, 1], |
| 51 | + "Brush Swirl" :[40, 41], |
| 52 | + "Snare Drum 2" :[40, 49], |
| 53 | + "Elec Snare Drum" :[40, 128], |
| 54 | + "Low Floor Tom" :[41, 1], |
| 55 | + "Timpani F" :[41, 49], |
| 56 | + "Acoustic Low Tom" :[41, 128], |
| 57 | + "Closed Hi Hat [EXC1]" :[42, 1], |
| 58 | + "Timpani F#" :[42, 49], |
| 59 | + "Closed Hi-Hat [Exc1]" :[42, 128], |
| 60 | + "High Floor Tom" :[43, 49], |
| 61 | + "Timpani G" :[43, 49], |
| 62 | + "Acoustic Low Tom" :[43, 128], |
| 63 | + "Pedal Hi-Hat [EXC1]" :[44, 1], |
| 64 | + "Timpani G#" :[44, 49], |
| 65 | + "Open Hi-Hat 2" :[44, 128], |
| 66 | + "Low Tom" :[45, 1], |
| 67 | + "Timpani A" :[45, 49], |
| 68 | + "Acoustic Middle Tom" :[45, 128], |
| 69 | + "Open Hi-Hat [EXC1]" :[46, 1], |
| 70 | + "Timpani A#" :[46, 49], |
| 71 | + "Open Hi-Hat 1 [Exc1]" :[46, 128], |
| 72 | + "Low-Mid Tom" :[47, 1], |
| 73 | + "Timpani B" :[47, 49], |
| 74 | + "Acoustic Middle Tom" :[47, 128], |
| 75 | + "Hi Mid Tom" :[48, 1], |
| 76 | + "Timpani c" :[48, 49], |
| 77 | + "Acoustic High Tom" :[48, 128], |
| 78 | + "Crash Cymbal 1" :[49, 1], |
| 79 | + "Timpani c#" :[49, 49], |
| 80 | + "Crash Cymbal" :[49, 128], |
| 81 | + "High Tom" :[50, 1], |
| 82 | + "Timpani d" :[50, 49], |
| 83 | + "Acoustic High Tom" :[50, 128], |
| 84 | + "Ride Cymbal 1" :[51, 1], |
| 85 | + "Timpani d#" :[51, 49], |
| 86 | + "Ride Cymbal" :[51, 128], |
| 87 | + "Chinese Cymbal" :[52, 1], |
| 88 | + "Timpani e" :[52, 49], |
| 89 | + "Ride Bell" :[53, 1], |
| 90 | + "Timpani f" :[53, 49], |
| 91 | + "Tambourine" :[54, 1], |
| 92 | + # "Tambourine" :[54, 128], |
| 93 | + "Splash Cymbal" :[55, 1], |
| 94 | + "Cowbell" :[56, 1], |
| 95 | + # "Cowbell" :[56, 128], |
| 96 | + "Crash Cymbal 2" :[57, 1], |
| 97 | + "Vibraslap" :[58, 1], |
| 98 | + "Ride Cymbal 2" :[59, 1], |
| 99 | + "Hi Bongo" :[60, 1], |
| 100 | + "Low Bongo" :[61, 1], |
| 101 | + "Mute Hi Conga" :[62, 1], |
| 102 | + "Open Hi Conga" :[63, 1], |
| 103 | + "Low Conga" :[64, 1], |
| 104 | + "High Timbale" :[65, 1], |
| 105 | + "Low Timbale" :[66, 1], |
| 106 | + "High Agogo" :[67, 1], |
| 107 | + "Low Agogo" :[68, 1], |
| 108 | + "Cabasa" :[69, 1], |
| 109 | + "Maracas" :[70, 1], |
| 110 | + "Short Whistle[EXC2]" :[71, 1], |
| 111 | + "Long Whistle[EXC2]" :[72, 1], |
| 112 | + "Short Guiro [EXC3]" :[73, 1], |
| 113 | + "Vibra Slap" :[73, 128], |
| 114 | + "Long Guiro [EXC3]" :[74, 1], |
| 115 | + "Claves" :[75, 1], |
| 116 | + # "Claves" :[75, 128], |
| 117 | + "Hi Wood Block" :[76, 1], |
| 118 | + "Low Wood Block" :[77, 1], |
| 119 | + "Mute Cuica [EXC4]" :[78, 1], |
| 120 | + "Open Cuica [EXC4]" :[79, 1], |
| 121 | + "Mute Triangle [EXC5]" :[80, 1], |
| 122 | + "Open Triangle[EXC5]" :[81, 1], |
| 123 | + "Applauses" :[82, 128], |
| 124 | + # "Applauses" :[88, 49], |
| 125 | + "Helicopter" :[94, 127], |
| 126 | + "Gun Shot" :[96, 127], |
| 127 | + "Birds" :[102, 127], |
| 128 | + "SeaShore" :[106, 127], |
| 129 | + } |
| 130 | + |
| 131 | +class SYNTHUnit: |
| 132 | + |
| 133 | + def __init__(self, port, port_id=1): |
| 134 | + Pinx = Pin(port[0], Pin.IN, Pin.PULL_UP) |
| 135 | + self._uart = UART(port_id, tx=port[1], rx=port[0]) |
| 136 | + self._uart.init(31250, bits=8, parity=None, stop=1) |
| 137 | + |
| 138 | + def set_note_on(self, channel, pitch, velocity): |
| 139 | + cmd = [MIDI_CMD_NOTE_ON | (channel & 0x0f), pitch, velocity] |
| 140 | + self.cmd_write(cmd) |
| 141 | + |
| 142 | + def set_note_off(self, channel, pitch): |
| 143 | + cmd = [MIDI_CMD_NOTE_OFF | (channel & 0x0f), pitch, 0x00] |
| 144 | + self.cmd_write(cmd) |
| 145 | + |
| 146 | + def set_instrument(self, bank, channel, value): |
| 147 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x00, bank] |
| 148 | + self.cmd_write(cmd) |
| 149 | + cmd = [MIDI_CMD_PROGRAM_CHANGE | (channel & 0x0f), value] |
| 150 | + self.cmd_write(cmd) |
| 151 | + |
| 152 | + def set_drums_instrument(self, drum_pitch, velocity): |
| 153 | + self.set_instrument(0, 9, DRUM_SET[drum_pitch][1]) |
| 154 | + self.set_note_on(9, DRUM_SET[drum_pitch][0], velocity) |
| 155 | + |
| 156 | + def set_pitch_bend(self, channel, value): |
| 157 | + value = self.map(value, 0, 1023, 0, 0x3fff) |
| 158 | + cmd = [MIDI_CMD_PITCH_BEND | (channel & 0x0f), (value & 0xef), ((value >> 7) & 0xff)] |
| 159 | + self.cmd_write(cmd) |
| 160 | + |
| 161 | + def set_pitch_bend_range(self, channel, value): |
| 162 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x65, 0x00, 0x64, 0x00, 0x06, (value & 0x7f)] |
| 163 | + self.cmd_write(cmd) |
| 164 | + |
| 165 | + def midi_reset(self): |
| 166 | + self.cmd_write([MIDI_CMD_SYSTEM_RESET]) |
| 167 | + |
| 168 | + def set_channel_volume(self, channel, level): |
| 169 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x07, level] |
| 170 | + self.cmd_write(cmd) |
| 171 | + |
| 172 | + def set_all_notes_off(self, channel): |
| 173 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x7b, 0x00] |
| 174 | + self.cmd_write(cmd) |
| 175 | + |
| 176 | + def set_master_volume(self, level): |
| 177 | + cmd = [MIDI_CMD_SYSTEM_EXCLUSIVE, 0x7f, 0x7f, 0x04, 0x01, 0x00, (level & 0x7f), MIDI_CMD_END_OF_SYSEX] |
| 178 | + self.cmd_write(cmd) |
| 179 | + |
| 180 | + def set_reverb(self, channel, program, level, delayfeedback): |
| 181 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x50, (program & 0x07)] |
| 182 | + self.cmd_write(cmd) |
| 183 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x5b, (level & 0x7f)] |
| 184 | + self.cmd_write(cmd) |
| 185 | + if delayfeedback > 0: |
| 186 | + cmd=[MIDI_CMD_SYSTEM_EXCLUSIVE, 0x41, 0x00, 0x42, 0x12, 0x40, 0x01, 0x35, (delayfeedback & 0x7f), 0x00, MIDI_CMD_END_OF_SYSEX] |
| 187 | + self.cmd_write(cmd) |
| 188 | + |
| 189 | + def set_chorus(self, channel, program, level, feedback, chorusdelay): |
| 190 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x51, (program & 0x07)] |
| 191 | + self.cmd_write(cmd) |
| 192 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x5d, (level & 0x7f)] |
| 193 | + self.cmd_write(cmd) |
| 194 | + if feedback > 0: |
| 195 | + cmd=[MIDI_CMD_SYSTEM_EXCLUSIVE, 0x41, 0x00, 0x42, 0x12, 0x40, 0x01, 0x3b, (feedback & 0x7f), 0x00, MIDI_CMD_END_OF_SYSEX] |
| 196 | + self.cmd_write(cmd) |
| 197 | + if chorusdelay > 0: |
| 198 | + cmd=[MIDI_CMD_SYSTEM_EXCLUSIVE, 0x41, 0x00, 0x42, 0x12, 0x40, 0x01, 0x3c, (feedback & 0x7f), 0x00, MIDI_CMD_END_OF_SYSEX] |
| 199 | + self.cmd_write(cmd) |
| 200 | + |
| 201 | + def set_pan(self, channel, value): |
| 202 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x0A, value] |
| 203 | + self.cmd_write(cmd) |
| 204 | + |
| 205 | + def set_equalizer(self, channel, lowband, medlowband, medhighband, highband, |
| 206 | + lowfreq, medlowfreq, medhighfreq, highfreq): |
| 207 | + |
| 208 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x63, 0x37, 0x62, 0x00, 0x06, (lowband & 0x7f)] |
| 209 | + self.cmd_write(cmd) |
| 210 | + cmd[4] = 0x01 |
| 211 | + cmd[6] = (medlowband & 0x7f) |
| 212 | + self.cmd_write(cmd) |
| 213 | + cmd[4] = 0x02 |
| 214 | + cmd[6] = (medhighband & 0x7f) |
| 215 | + self.cmd_write(cmd) |
| 216 | + cmd[4] = 0x03 |
| 217 | + cmd[6] = (highband & 0x7f) |
| 218 | + self.cmd_write(cmd) |
| 219 | + cmd[4] = 0x08 |
| 220 | + cmd[6] = (lowfreq & 0x7f) |
| 221 | + self.cmd_write(cmd) |
| 222 | + cmd[4] = 0x09 |
| 223 | + cmd[6] = (medlowfreq & 0x7f) |
| 224 | + self.cmd_write(cmd) |
| 225 | + cmd[4] = 0x0A |
| 226 | + cmd[6] = (medhighfreq & 0x7f) |
| 227 | + self.cmd_write(cmd) |
| 228 | + cmd[4] = 0x0B |
| 229 | + cmd[6] = (highfreq & 0x7f) |
| 230 | + self.cmd_write(cmd) |
| 231 | + |
| 232 | + def set_tuning(self, channel, fine, coarse): |
| 233 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x65, 0x00, 0x64, 0x01, 0x06, (fine & 0x7f)] |
| 234 | + self.cmd_write(cmd) |
| 235 | + cmd[4] = 0x02 |
| 236 | + cmd[6] = (coarse & 0x7f) |
| 237 | + self.cmd_write(cmd) |
| 238 | + |
| 239 | + def set_vibrate(self, channel, rate, depth, delay): |
| 240 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x63, 0x01, 0x62, 0x08, 0x06, (rate & 0x7f)] |
| 241 | + self.cmd_write(cmd) |
| 242 | + cmd[4] = 0x09 |
| 243 | + cmd[6] = (depth & 0x7f) |
| 244 | + self.cmd_write(cmd) |
| 245 | + cmd[4] = 0x0A |
| 246 | + cmd[6] = (delay & 0x7f) |
| 247 | + self.cmd_write(cmd) |
| 248 | + |
| 249 | + def set_tvf(self, channel, cutoff, resonance): |
| 250 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x63, 0x01, 0x62, 0x20, 0x06, (cutoff & 0x7f)] |
| 251 | + self.cmd_write(cmd) |
| 252 | + cmd[4] = 0x21 |
| 253 | + cmd[6] = (resonance & 0x7f) |
| 254 | + self.cmd_write(cmd) |
| 255 | + |
| 256 | + def set_envelope(self, channel, attack, decay, release): |
| 257 | + cmd = [MIDI_CMD_CONTROL_CHANGE | (channel & 0x0f), 0x63, 0x01, 0x62, 0x63, 0x06, (attack & 0x7f)] |
| 258 | + self.cmd_write(cmd) |
| 259 | + cmd[4] = 0x64 |
| 260 | + cmd[6] = (decay & 0x7f) |
| 261 | + self.cmd_write(cmd) |
| 262 | + cmd[4] = 0x66 |
| 263 | + cmd[6] = (release & 0x7f) |
| 264 | + self.cmd_write(cmd) |
| 265 | + |
| 266 | + def set_scale_tuning(self, channel, v1, v2, v3, v4, v5, v6, |
| 267 | + v7, v8, v9, v10, v11, v12): |
| 268 | + cmd = [MIDI_CMD_CONTROL_CHANGE, 0x41, 0x00, 0x42, 0x12, 0x40, 0x10 | (channel & 0x0f), 0x40, |
| 269 | + v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, MIDI_CMD_END_OF_SYSEX] |
| 270 | + self.cmd_write(cmd) |
| 271 | + |
| 272 | + def set_mod_wheel(self, channel, pitch, tvtcutoff, amplitude, rate, pitchdepth, tvfdepth, tvadepth): |
| 273 | + cmd = [MIDI_CMD_CONTROL_CHANGE, 0x41, 0x00, 0x42, 0x12, 0x40, 0x20 | (channel & 0x0f), 0x00, pitch, 0x00, MIDI_CMD_END_OF_SYSEX] |
| 274 | + self.cmd_write(cmd) |
| 275 | + cmd[8] = 0x01 |
| 276 | + cmd[9] = tvtcutoff |
| 277 | + self.cmd_write(cmd) |
| 278 | + cmd[8] = 0x02 |
| 279 | + cmd[9] = amplitude |
| 280 | + self.cmd_write(cmd) |
| 281 | + cmd[8] = 0x03 |
| 282 | + cmd[9] = rate |
| 283 | + self.cmd_write(cmd) |
| 284 | + cmd[8] = 0x04 |
| 285 | + cmd[9] = pitchdepth |
| 286 | + self.cmd_write(cmd) |
| 287 | + cmd[8] = 0x05 |
| 288 | + cmd[9] = tvfdepth |
| 289 | + self.cmd_write(cmd) |
| 290 | + cmd[8] = 0x06 |
| 291 | + cmd[9] = tvadepth |
| 292 | + self.cmd_write(cmd) |
| 293 | + |
| 294 | + def set_all_drums(self): |
| 295 | + cmd = [MIDI_CMD_CONTROL_CHANGE, 0x41, 0x00, 0x42, 0x12, 0x40, 0x10, 0x15, 0x01, 0x00, MIDI_CMD_END_OF_SYSEX] |
| 296 | + self.cmd_write(cmd) |
| 297 | + for i in range(1, 15): |
| 298 | + cmd[6] = i |
| 299 | + self.cmd_write(cmd) |
| 300 | + |
| 301 | + def cmd_write(self, cmd): |
| 302 | + self._uart.write(bytes(cmd)) |
| 303 | + |
| 304 | + def map(self, x, in_min, in_max, out_min, out_max): |
| 305 | + return round((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min) |
| 306 | + |
| 307 | + |
0 commit comments