Skip to content

Commit

Permalink
🪵 Logs (#8)
Browse files Browse the repository at this point in the history
# Logs
- Migrates logging to [loguru](https://github.com/Delgan/loguru)
- Sets default level to `TRACE`
- Converts code comments to proper log levels!
  • Loading branch information
mrharpo authored Jan 16, 2024
2 parents a2382f3 + 0d6a2c6 commit 6042fe1
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 70 deletions.
135 changes: 67 additions & 68 deletions holophonor/launchpadX.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from rtmidi.midiutil import open_midiinput
from rtmidi.midiconstants import NOTE_ON, CONTROL_CHANGE, NOTE_OFF
from rtmidi import API_UNIX_JACK
import logging as log
from loguru import logger as log


class LaunchpadX(Holophonor):
Expand Down Expand Up @@ -112,20 +112,20 @@ def lightButton(self, note):

@holoimpl
def close(self):
log.debug(f'Closing launchpadX: exiting live mode')
log.info(f'Closing launchpadX: exiting live mode')

# exit programming mode
self.midi.send_message([240, 0, 32, 41, 2, 12, 14, 0, 247])

@holoimpl
def recordLoop(self, loop):
log.debug(f'recording loop {loop}')
log.info(f'recording loop {loop}')
self.midi.send_message([NOTE_ON | 0x2, self.map[loop], RECORDING])
self.loops[loop] = -1

@holoimpl
def playLoop(self, loop, volume):
log.debug(f'playing loop {loop} at {volume}')
log.info(f'playing loop {loop} at {volume}')

self.midi.send_message(
[NOTE_ON | 0x2, self.map[loop], GREEN[(volume if volume > 0 else 100) >> 4]]
Expand All @@ -138,31 +138,31 @@ def playLoop(self, loop, volume):

@holoimpl
def stopLoop(self, loop):
log.debug(f'stopping loop {loop}')
log.info(f'stopping loop {loop}')
self.midi.send_message([NOTE_ON, self.map[loop], STOPPED])
self.loops[loop] = 0

@holoimpl
def eraseLoop(self, loop):
log.debug(f'erasing loop {loop}')
log.info(f'erasing loop {loop}')
self.midi.send_message([NOTE_ON, self.map[loop], ERASE])
self.loops[loop] = None

@holoimpl
def clearLoop(self, loop):
log.debug(f'clearing loop {loop}')
log.info(f'clearing loop {loop}')
self.midi.send_message([NOTE_ON, self.map[loop], EMPTY])

@holoimpl
def overdubLoop(self, loop: int):
log.debug(f'overdubbing loop {loop}')
log.info(f'overdubbing loop {loop}')
if self.loops[loop] != -2:
self.midi.send_message([NOTE_ON, self.map[loop], RECORDING])
self.loops[loop] = -2

@holoimpl
def recallScene(self, scene: int):
log.debug(f'recalling scene {scene}')
log.info(f'recalling scene {scene}')
if self.current_scene != None:
self.midi.send_message([NOTE_ON, self.SCENES[self.current_scene], STOPPED])
if self.scenes[self.current_scene] == -1:
Expand All @@ -188,7 +188,7 @@ def recallScene(self, scene: int):

@holoimpl
def storeScene(self, scene: int):
log.debug(f'storing scene {scene}')
log.info(f'storing scene {scene}')
if self.current_scene != None:
# if we are playing a scene currently, stop the light
self.midi.send_message([NOTE_ON, self.SCENES[self.current_scene], STOPPED])
Expand All @@ -204,45 +204,44 @@ def storeScene(self, scene: int):

@holoimpl
def eraseScene(self, scene: int):
log.debug(f'erasing scene {scene}')
log.info(f'erasing scene {scene}')
self.midi.send_message([NOTE_ON, self.SCENES[scene], ERASE])
self.scenes[scene] = None
if self.current_scene == scene:
self.current_scene = None

@holoimpl
def clearScene(self, scene: int):
log.debug(f'clearing scene {scene}')
log.info(f'clearing scene {scene}')
self.midi.send_message([NOTE_ON, self.SCENES[scene], EMPTY])

@holoimpl
def toggleShift(self):
log.debug(f'Toggling shift mode from {self.shift}')
self.shift = not self.shift
log.info(f'Toggling shift mode: {self.shift}')
self.midi.send_message(
[CONTROL_CHANGE, self.CAPTURE_MIDI_BUTTON, ERASE if self.shift else 0]
)

@holoimpl
def toggleCut(self):
log.debug(f'Toggling cut mode from {self.cut}')
self.cut = not self.cut
log.info(f'Toggling cut mode: {self.cut}')
self.midi.send_message(
[CONTROL_CHANGE, self.NOTE_BUTTON, CUT if self.cut else 0]
)

@holoimpl
def toggleOverdub(self):
log.debug(f'Toggling overdub mode from {self.overdub}')

self.overdub = not self.overdub
log.info(f'Toggling overdub mode: {self.overdub}')
self.midi.send_message(
[CONTROL_CHANGE, self.CUSTOM_BUTTON, RECORDING if self.overdub else 0]
)

@holoimpl
def deletePulse(self):
log.debug(f'Deleting pulse')
log.info(f'Deleting pulse')
self.midi.send_message([CONTROL_CHANGE, self.SESSION_BUTTON, ERASE])
self.clear()
self.pulse = False
Expand All @@ -252,12 +251,12 @@ def deletePulse(self):

@holoimpl
def clearPulse(self):
log.debug(f'Clearing pulse')
log.info(f'Clearing pulse')
self.midi.send_message([CONTROL_CHANGE, self.SESSION_BUTTON, INACTIVE])

@holoimpl
def stopAllLoops(self):
log.debug(f'Stopping all loops')
log.info(f'Stopping all loops')
for i, l in enumerate(self.loops):
if l:
self.midi.send_message([NOTE_ON, self.map[i], STOPPED])
Expand All @@ -269,7 +268,7 @@ def stopAllLoops(self):

@holoimpl
def tapPulse(self):
log.debug('tap pulse pressed')
log.info('tap pulse pressed')
self.tap = not self.tap
self.midi.send_message(
[CONTROL_CHANGE, self.SESSION_BUTTON, TAP if self.tap else PULSE]
Expand All @@ -280,23 +279,23 @@ def tapPulse(self):

@holoimpl
def toggleMute(self, channel: int):
log.debug(f'Toggling mute on channel {channel}')
log.info(f'{"un" if self.mutes[channel] else ""}muting channel {channel}')
self.midi.send_message(
[NOTE_ON, self.MUTES[channel], RECORDING if self.mutes[channel] else EMPTY]
)
self.mutes[channel] = not self.mutes[channel]

@holoimpl
def toggleFX(self, fx: int):
log.debug(f'Toggling fx {fx}')
log.info(f'{"de" if self.fx[fx] else ""}activating fx {fx}')
self.midi.send_message(
[NOTE_ON, self.FX[fx], EMPTY if self.fx[fx] else self.FX[fx]]
)
self.fx[fx] = not self.fx[fx]

@holoimpl
def setDrumPatch(self, patch: int):
log.debug(f'setting drum patch {patch}')
log.info(f'setting drum patch {patch}')
self.midi.send_message(
[NOTE_ON, self.DRUM_PATCHES[patch], self.DRUM_PATCH_COLORS[patch]]
)
Expand All @@ -306,53 +305,52 @@ def setDrumPatch(self, patch: int):

@holoimpl
def setDrumBank(self, bank: int):
log.debug(f'Setting drum bank {bank}')
log.info(f'Setting drum bank {bank}')
self.drum_bank = bank
self.lightDrums()

def __call__(self, event, data=None):
message, deltatime = event
log.info(message)
log.debug(message)
if message[0] == NOTE_ON:
log.debug(f'NOTE ON detected')
log.trace(f'NOTE ON detected')
if message[1] in self.map:
log.debug(f'This is a loop button')
log.trace(f'This is a loop button')
l = self.map.index(message[1])
loop = self.loops[l]
if message[2]:
# note on event
log.trace('note on event')
if not self.shift:
# normal (unshifted) mode
log.trace('normal (unshifted) mode')
if loop == None:
# no existing loop, we are now recording.
log.trace('no existing loop, we are now recording.')
self.hook.recordLoop(loop=l, volume=message[2])
elif self.cut:
# cut mode
log.trace(f'cut mode. Play loop {l} at volume {message[2]}')
self.hook.playLoop(loop=l, volume=message[2])
elif self.overdub:
# overdub loop
log.trace(f'overdub loop {l}')
if loop != -2:
self.hook.overdubLoop(loop=l)
else:
self.hook.playLoop(loop=l, volume=message[2])
# regular mode - no cut, no overdub
log.trace('regular mode - no cut, no overdub')
elif loop > 0:
# loop was playing
log.trace('loop was playing')
self.hook.stopLoop(loop=l)
else:
# loop must be stopped, recording or overdubbing
log.trace('loop must be stopped, recording or overdubbing')
self.hook.playLoop(loop=l, volume=message[2])
else:
# shift mode
# erase loop
log.trace('shift mode. Erase loop')
self.hook.eraseLoop(loop=l)
else:
# note off
# button released
log.trace('note off. Button released')
if self.loops[l] == None:
# if we erased the loop, clear the color
log.trace('if we erased the loop, clear the color')
self.hook.clearLoop(loop=l)
elif message[1] in self.DRUMS:
log.trace('this is a drum button. Playing note')
self.hook.playNote(
note=[
NOTE_ON | 0x9,
Expand All @@ -368,96 +366,97 @@ def __call__(self, event, data=None):
]
)
elif message[1] in self.FX and message[2]:
log.trace('this is an FX button. Toggling FX')
f = self.FX.index(message[1])
self.hook.toggleFX(fx=f)
elif message[1] in self.DRUM_PATCHES and message[2]:
log.trace('this is a drum patch button. Setting drum patch')
i = self.DRUM_PATCHES.index(message[1])
self.hook.setDrumPatch(patch=i)
elif message[1] in self.MUTES and message[2]:
log.trace('this is a mute button. Toggling mute')
n = self.MUTES.index(message[1])
self.hook.toggleMute(channel=n)
else:
# no matching rule found for note
log.debug('no matching rule found for note')
log.trace(f'no matching rule found for note {message[1]}')
if message[0] in (CONTROL_CHANGE, NOTE_ON):
# for MK2 compatibility, where scenes are sent as NOTE_ON
if message[1] in self.SCENES:
log.trace('this is a scene button')
s = self.SCENES.index(message[1])
if message[2] == 127:
# scene button pressed
log.trace('scene button pressed')
if self.shift:
# erase scene
log.trace('shift mode. erase scene')
self.hook.eraseScene(scene=s)
else:
# normal (unshifted) mode
log.trace('normal (unshifted) mode. store/recall scene')
if self.scenes[s] in (None, -1):
# store scene
log.trace('store scene')
self.hook.storeScene(scene=s)
else:
# recall scene
log.trace('recall scene')
self.hook.recallScene(scene=s)
else:
# scene button released
log.trace('scene button released')
if self.scenes[s] == None:
log.trace('if we erased the scene, clear the color')
self.hook.clearScene(scene=s)
if message[0] == CONTROL_CHANGE:
if message[1] in self.FUNCTIONS:
if message[1] == self.CAPTURE_MIDI_BUTTON:
# capture midi button
# enable shift mode
log.trace(
f'capture midi button {"released" if self.shift else "pressed"}. {"de" if self.shift else ""}activating shift mode'
)
self.toggleShift()
if self.shift:
if message[1] == self.SESSION_BUTTON:
# erase session
# delete pulse
if message[2] == 127:
log.trace('erase all loops and pulse')
self.hook.deletePulse()
else:
log.trace('clearning pulse color')
self.hook.clearPulse()
else:
# normal (unshifted) mode
if message[1] == self.UP_ARROW and message[2] == 127:
# arrow up button
# drum bank increment
log.trace('arrow up button. drum bank increment')
# not attached to hook
# multiple devices can have seperate local banks
self.setDrumBank(bank=min(self.drum_bank + 1, 3))
elif message[1] == self.DOWN_ARROW and message[2] == 127:
# arrow down button
# drum bank decrement
log.trace('arrow down button. drum bank decrement')
self.setDrumBank(bank=max(self.drum_bank - 1, -1))
elif message[1] == self.LEFT_ARROW and message[2] == 127:
# left arrow button
log.trace('left arrow button. Stop all loops')
self.hook.stopAllLoops()
elif message[1] == self.NOTE_BUTTON:
# note button
# momentary cut mode - normal on release
log.trace('note button. toggle cut mode while pressed')
# note: because all logic is explicit (playLoop, stopLoop, etc)
# all state changes can be purely local!
self.toggleCut()
elif message[1] == self.CUSTOM_BUTTON and message[2] == 127:
# custom button
# toggle overdub on button press
log.trace('custom button. toggle overdub mode')
self.toggleOverdub()
elif message[1] == self.SESSION_BUTTON:
# session button
# tap-pulse
if message[2] == 127:
log.trace('session button pressed. tap pulse')
self.hook.tapPulse()
elif self.pulse == False:
# this also clears the ERASE color from the Session button if shift mode is released first
log.trace('session button released. clear pulse')
# this clears the ERASE color from the Session button if shift mode is released first
self.hook.clearPulse()
if message[0] == NOTE_OFF:
log.debug('NOTE OFF detected')
log.trace('NOTE OFF detected')
if message[1] in self.map:
log.debug('This is a loop button')
log.trace('This is a loop button')
l = self.map.index(message[1])
loop = self.loops[l]
if loop == None:
log.debug('Clearing erased loop')
log.trace('Clearing erased loop')
self.clearLoop(loop=l)
elif message[1] in self.DRUMS:
log.debug('clearing drum note')
log.trace('clearing drum note')
self.lightButton(
[
NOTE_ON,
Expand Down
7 changes: 5 additions & 2 deletions holophonor/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
from holophonor.launchpadX import LaunchpadX
from holophonor.launchpadMK2 import LaunchpadMK2
from pluggy import PluginManager
import logging as log
from loguru import logger as log


def main():
# log.basicConfig(level=log.DEBUG)
from sys import stderr, stdout

log.configure(handlers=[{"sink": stderr, "level": "TRACE"}])
pm = get_plugin_manager()
log.info('Holophonor: ready!')
try:
while True:
input()
Expand Down

0 comments on commit 6042fe1

Please sign in to comment.