|
| 1 | +from ludwig import mixer, Mixer, Midi |
| 2 | +from rtmidi.midiconstants import NOTE_ON |
| 3 | +from ludwig.types import uint1, uint2, uint3, uint4, uint7, uint8 |
| 4 | +from pydantic import conint |
| 5 | + |
| 6 | + |
| 7 | +class Gld(Midi, Mixer): |
| 8 | + def __init__(self, *args, **kwargs): |
| 9 | + super().__init__(self, *args, **kwargs) |
| 10 | + self.sysex_header = [0xF0, 0x0, 0x0, 0x1A, 0x50, 0x10, 0x1, 0x0, self.channel] |
| 11 | + |
| 12 | + @mixer |
| 13 | + def allCall(self): |
| 14 | + self.send(self.sysex_header[:-1] + [0x7F] + [0x10, 0x0, 0xF7]) |
| 15 | + |
| 16 | + @mixer |
| 17 | + def meters(self): |
| 18 | + self.sysex([0x12, 0x1]) |
| 19 | + |
| 20 | + @mixer |
| 21 | + def fader(self, channel: uint7, volume: uint8): |
| 22 | + self.nrpn(channel=channel, param=0x17, data1=volume, data2=0x7) |
| 23 | + |
| 24 | + @mixer |
| 25 | + def channel_assign_to_main_mix(self, channel: uint7, on: bool): |
| 26 | + self.nrpn(channel=channel, param=0x18, data1=0x7F if on else 0x3F, data2=0x7) |
| 27 | + |
| 28 | + @mixer |
| 29 | + def aux_send_level(self, channel: uint7, snd: uint8, level: uint8): |
| 30 | + self.nrpn(channel=channel, param=snd, data1=level, data2=0x7) |
| 31 | + |
| 32 | + @mixer |
| 33 | + def dca_assign(self, channel: uint7, dca: conint(ge=1, le=16), on: bool): |
| 34 | + """1 indexed""" |
| 35 | + self.nrpn( |
| 36 | + channel=channel, param=on * 0x40 | dca - 1, data1=0x4 | dca, data2=0x7 |
| 37 | + ) |
| 38 | + |
| 39 | + @mixer |
| 40 | + def channel_name(self, channel: uint7, name: str): |
| 41 | + if len(name) > 8: |
| 42 | + raise Exception("Name must be less than 8 characters") |
| 43 | + self.sysex([0x3, channel] + [ord(n) for n in name]) |
| 44 | + |
| 45 | + @mixer |
| 46 | + def channel_color(self, channel: uint7, color: uint3): |
| 47 | + self.sysex([0x6, channel, color]) |
| 48 | + |
| 49 | + @mixer |
| 50 | + def scene_recall(self, scene: conint(ge=1, le=500)): |
| 51 | + """recall scene, where scenes are 1 indexed""" |
| 52 | + self.send([0xB0 | self.channel, 0x0, scene // 128, scene % 128]) |
| 53 | + |
| 54 | + @mixer |
| 55 | + def mix_select(self, channel: uint7, select: bool): |
| 56 | + self.send([0xA0 | self.channel, channel, int(select)]) |
| 57 | + |
| 58 | + @mixer |
| 59 | + def pan(self, channel: uint7, pan: uint8): |
| 60 | + self.nrpn(channel, 0x16, pan, 0x7) |
| 61 | + |
| 62 | + @mixer |
| 63 | + def mute(self, channel: uint7): |
| 64 | + self.send([NOTE_ON | self.channel, channel, 127]) |
| 65 | + |
| 66 | + @mixer |
| 67 | + def unmute(self, channel: uint7): |
| 68 | + self.send([NOTE_ON | self.channel, channel, 1]) |
| 69 | + |
| 70 | + @mixer |
| 71 | + def compressor( |
| 72 | + self, |
| 73 | + channel: uint7, |
| 74 | + type: uint2 | None = None, |
| 75 | + attack: uint7 | None = None, |
| 76 | + release: uint7 | None = None, |
| 77 | + knee: uint1 | None = None, |
| 78 | + ratio: uint7 | None = None, |
| 79 | + threshold: uint7 | None = None, |
| 80 | + gain: uint7 | None = None, |
| 81 | + ): |
| 82 | + """send values to the compressor |
| 83 | +
|
| 84 | + Reuqired arguments: |
| 85 | + channel (uint7): MIDI channel |
| 86 | +
|
| 87 | + Optional arguments: |
| 88 | + type (uint2): 4 allowed types |
| 89 | + attack (uint7): 300us to 300ms |
| 90 | + release (uint7): 100ms to 2s |
| 91 | + knee (uint1): 0 = hard, 1 = soft |
| 92 | + ratio (uint7): 1:1 to inf (e.g. 2.6:1 = 80) |
| 93 | + threshold (uint7): -46 to +18dB |
| 94 | + gain (uint7): 0 +18dB |
| 95 | + """ |
| 96 | + |
| 97 | + if type: |
| 98 | + self.nrpn(channel, 0x61, type, 0x7) |
| 99 | + if attack: |
| 100 | + self.nrpn(channel, 0x62, attack, 0x7) |
| 101 | + if release: |
| 102 | + self.nrpn(channel, 0x63, release, 0x7) |
| 103 | + if knee: |
| 104 | + self.nrpn(channel, 0x64, knee, 0x7) |
| 105 | + if ratio: |
| 106 | + self.nrpn(channel, 0x65, ratio, 0x7) |
| 107 | + if threshold: |
| 108 | + self.nrpn(channel, 0x66, threshold, 0x7) |
| 109 | + if gain: |
| 110 | + self.nrpn(channel, 0x67, gain, 0x7) |
0 commit comments