def test_get_enabled_controllers(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) # Get active project metadata testMsg = mido.Message('sysex') testMsg.data = [0x01, 0x30] # Init in-memory config cfg = serverconfiguration.ServerConfiguration() proj = cfg.getActiveProjectOrDefault() proj.activate() # Needs to be activated proj.stopProcessing() # Handle message ctrl.handleMidiMsg(testMsg, cfg, proj) assert f.call_count == 1 retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x01 assert retMsg.data[1] == 0x30 # Decode data dec = sysex_data.decode(retMsg.data[2:]) metadata = json.loads(bytes(dec)) assert metadata is not None assert len(metadata.keys()) == len(modulation.allController) for k, v in metadata.items(): assert not v
def test_get_projects(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) # Get active project metadata testMsg = mido.Message('sysex') testMsg.data = [0x00, 0x30] # Init in-memory config cfg = serverconfiguration.ServerConfiguration() proj = cfg.getActiveProjectOrDefault() cfg.initDefaultProject() proj.stopProcessing() # Handle message ctrl.handleMidiMsg(testMsg, cfg, None) assert f.call_count == 1 retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x00 assert retMsg.data[1] == 0x30 # Decode data dec = sysex_data.decode(retMsg.data[2:]) assert dec is not None metadata = json.loads(bytes(dec)) assert metadata is not None # TODO: Adjust check assert len(metadata.keys()) == 2
def test_dec_list1_long(self): to_dec = [ 0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x00, 0x7E, 0x00, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x3F ] dec = sysex_data.decode(to_dec) self.assertListEqual(dec, [ 0xF6, 0xE5, 0xD4, 0xC3, 0xB2, 0xA1, 0x00, 0x00, 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6 ])
def test_get_version(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) version._test_version = "1.0.0" # Get Version messsage testMsg = mido.Message('sysex') testMsg.data = [0x00, 0x00] # Handle message ctrl.handleMidiMsg(testMsg, None, None) retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x00 assert retMsg.data[1] == 0x00 # Decode data dec = sysex_data.decode(retMsg.data[2:]) v = str(bytes(dec), encoding='utf8') # Check is version string assert len(v.split('.')) >= 3
def test_get_audio_rms(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) num_channels = 2 chunk = [1 for _ in range(20)] audio.GlobalAudio.buffer = np.array( [chunk[i::num_channels] for i in range(num_channels)]) print(audio.GlobalAudio.buffer) # Get Version messsage testMsg = mido.Message('sysex') testMsg.data = [0x02, 0x20] # Handle message ctrl.handleMidiMsg(testMsg, None, None) retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x02 assert retMsg.data[1] == 0x20 # Decode data dec = sysex_data.decode(retMsg.data[2:]) v = json.loads(str(bytes(dec), encoding='utf8')) assert "0" in v
def test_get_active_scene_id_successful(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) # Init in-memory config cfg = serverconfiguration.ServerConfiguration() proj = cfg.getActiveProjectOrDefault() # type: project.Project proj.stopProcessing() # Activate project testMsg = mido.Message('sysex') testMsg.data = [0x01, 0x00] # Handle message ctrl.handleMidiMsg(testMsg, cfg, proj) assert f.call_count == 1 retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x01 assert retMsg.data[1] == 0x00 data = sysex_data.decode(retMsg.data[2:]) data = bytes(data) assert data == bytes("12", encoding='utf8')
def test_get_server_config(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) # Init in-memory config cfg = serverconfiguration.ServerConfiguration() # Get active project metadata testMsg = mido.Message('sysex') testMsg.data = [0x02, 0x00] # Handle message ctrl.handleMidiMsg(testMsg, cfg, None) assert f.call_count == 1 retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x02 assert retMsg.data[1] == 0x00 # Decode data dec = sysex_data.decode(retMsg.data[2:]) dec = zlib.decompress(bytes(dec)) j_dict = json.loads(dec) assert j_dict is not None print(j_dict) assert not j_dict["advertise_bluetooth"]
def test_export_project(): # Setup f = mock.Mock() ctrl = midi_full.MidiProjectController(callback=f) # Init in-memory config cfg = serverconfiguration.ServerConfiguration() proj = cfg.getActiveProjectOrDefault() proj.stopProcessing() # Get active project metadata testMsg = mido.Message('sysex') testMsg.data = [0x00, 0x60] + sysex_data.encode(proj.id) # Handle message ctrl.handleMidiMsg(testMsg, cfg, proj) assert f.call_count == 1 retMsg = f.call_args[0][0] # Check response message ID assert retMsg.data[0] == 0x00 assert retMsg.data[1] == 0x60 # Decode data dec = sysex_data.decode(retMsg.data[2:]) dec = zlib.decompress(bytes(dec)) restoredProj = jsonpickle.loads(dec) # type project.Project assert restoredProj is not None assert restoredProj.id == proj.id
def test_dec_list2(self): to_dec = [0x00, 0x21, 0x20] dec = sysex_data.decode(to_dec) self.assertListEqual(dec, [0x00, 0xA1])
def test_dec_0x80(self): to_dec = [0x00, 0x40] dec = sysex_data.decode(to_dec) self.assertListEqual(dec, [0x80])
def _handleSysex(self, data, serverconfig: serverconfiguration.ServerConfiguration, proj: project.Project): if len(data) < 2: logger.error("Sysex message too short") return if data[0] == 0x00 and data[1] == 0x00: # Version logger.info("MIDI-BLE REQ Version") if self._sendMidiCallback is not None: self._sendMidiCallback(self._createVersionMsg()) elif data[0] == 0x00 and data[1] == 0x10: # Update logger.info("MIDI-BLE REQ Update") logger.info("Checking for update, current version is {}".format( version.get_version())) self._updatePathsAndUrls(serverconfig) if not self._isUpdating: self._isUpdating = True # New Downloaders will be created on request self.client.refresh() app_update = self.client.update_check('Molecole', version.get_version()) if app_update is not None: logger.info("Update {} available".format( app_update.current_version)) threading.Thread(target=self._updateApp, args=[app_update]).start() else: self._isUpdating = False logger.info("Update check returned no update") if self._sendMidiCallback is not None: self._sendMidiCallback( self._createUpdateNotAvailableMsg()) else: if self._sendMidiCallback is not None: self._sendMidiCallback(self._createUpdateBusyMsg()) elif data[0] == 0x00 and data[1] == 0x11: # Update check logger.info("MIDI-BLE REQ Update check") logger.info("Checking for update, current version is {}".format( version.get_version())) self._updatePathsAndUrls(serverconfig) if not self._isUpdating: self._isUpdating = True try: # Move version.gz to force a reload oldFile = os.path.join(self.client.data_dir, self.client.version_file) if os.path.exists(oldFile): shutil.move(oldFile, oldFile.replace('.gz', '.gz.bak')) oldFile = os.path.join(self.client.data_dir, self.client.version_file_compat) if os.path.exists(oldFile): shutil.move(oldFile, oldFile.replace('.gz', '.gz.bak')) self.client.refresh() app_update = self.client.update_check( 'Molecole', version.get_version()) self._isUpdating = False if app_update is not None: logger.info("Update {} available".format( app_update.version)) if self._sendMidiCallback is not None: self._sendMidiCallback( self._createUpdateVersionAvailableMsg( app_update.version)) else: logger.info("Update check returned no update") if self._sendMidiCallback is not None: self._sendMidiCallback( self._createUpdateNotAvailableMsg()) except Exception as e: logger.error("Error trying to update: {}".format(e)) self._isUpdating = False else: if self._sendMidiCallback is not None: self._sendMidiCallback(self._createUpdateBusyMsg()) elif data[0] == 0x00 and data[1] == 0x20: # Active project metadata if self._sendMidiCallback is not None: metadata = serverconfig.getProjectMetadata(proj.id) self._sendMidiCallback(self._createActiveProjectMsg(metadata)) elif data[0] == 0x00 and data[1] == 0x30: # Get projects if self._sendMidiCallback is not None: metadata = serverconfig.getProjectsMetadata() self._sendMidiCallback(self._createProjectsMsg(metadata)) elif data[0] == 0x00 and data[1] == 0x40: # Activate project projUid = str(bytes(sysex_data.decode(data[2:])), encoding='utf8') logger.info("MIDI-BLE REQ Activate project {}".format(projUid)) proj = serverconfig.getProject(projUid) if proj is not None: if self._sendMidiCallback is not None: self._sendMidiCallback( self._createActivateProjSuccessfulMsg()) else: if self._sendMidiCallback is not None: self._sendMidiCallback( self._createActivateProjNotFoundMsg()) elif data[0] == 0x00 and data[1] == 0x50: # Import project logger.info("MIDI-BLE REQ Import project") dec = sysex_data.decode(data[2:]) projGzip = zlib.decompress(bytes(dec)) projJson = str(projGzip, encoding='utf8') try: serverconfig.importProject(projJson) if self._sendMidiCallback is not None: self._sendMidiCallback( self._createImportProjSuccessfulMsg()) except Exception: if self._sendMidiCallback is not None: self._sendMidiCallback(self._createImportProjErrorMsg()) elif data[0] == 0x00 and data[1] == 0x60: # Export project byteArr = bytes(sysex_data.decode(data[2:])) logger.debug("Decoded {} to {}".format([hex(c) for c in data[2:]], byteArr)) projUid = str(byteArr, encoding='utf8') logger.info("MIDI-BLE REQ Export project {}".format(projUid)) proj = serverconfig.getProject(projUid) if proj is not None: if self._sendMidiCallback is not None: self._sendMidiCallback( self._createExportProjSuccessfulMsg(proj)) else: if self._sendMidiCallback is not None: self._sendMidiCallback(self._createExportProjNotFoundMsg()) elif data[0] == 0x00 and data[1] == 0x70: # Activate project projUid = str(bytes(sysex_data.decode(data[2:])), encoding='utf8') logger.info("MIDI-BLE REQ Delete project {}".format(projUid)) proj = serverconfig.getProject(projUid) if proj is not None: serverconfig.deleteProject(projUid) if self._sendMidiCallback is not None: self._sendMidiCallback(self._deleteProjSuccessfulMsg()) else: if self._sendMidiCallback is not None: self._sendMidiCallback(self._deleteProjNotFoundMsg()) elif data[0] == 0x01 and data[1] == 0x00: # Get active scene ID logger.info("MIDI-BLE REQ Active scene index") sceneId = serverconfig.getActiveProjectOrDefault().activeSceneId if self._sendMidiCallback is not None: self._sendMidiCallback( self._createGetActiveSceneIdMsg(sceneId)) elif data[0] == 0x01 and data[1] == 0x10: # Get active scene metadata logger.info("MIDI-BLE REQ Get active scene metadata") proj = serverconfig.getActiveProjectOrDefault() metadata = proj.getSceneMetadata(proj.activeSceneId) if self._sendMidiCallback is not None: self._sendMidiCallback( self._createActiveSceneMetadataMsg(metadata)) elif data[0] == 0x01 and data[1] == 0x20: # Get scenes metadata logger.info("MIDI-BLE REQ Get scenes") proj = serverconfig.getActiveProjectOrDefault() metadata = proj.sceneMetadata if self._sendMidiCallback is not None: self._sendMidiCallback(self._createScenesMetadataMsg(metadata)) elif data[0] == 0x01 and data[1] == 0x30: # Get enabled controllers for active scene logger.info("MIDI-BLE REQ Get controller enabled for active scene") proj = serverconfig.getActiveProjectOrDefault() if self._sendMidiCallback is not None: self._sendMidiCallback(self._createEnabledControllersMsg(proj)) elif data[0] == 0x01 and data[1] == 0x40: # Request controller values for active project logger.info("MIDI-BLE REQ Get controller values for active scene") proj = serverconfig.getActiveProjectOrDefault() self._sendControllerStatus(proj) elif data[0] == 0x01 and data[1] == 0x50: # Reset controller values for active project logger.info("MIDI-BLE REQ Reset controller for active scene") proj = serverconfig.getActiveProjectOrDefault() proj.resetControllerModulation() self._sendControllerStatus(proj) elif data[0] == 0x02 and data[1] == 0x00: # Get server configuration logger.info("MIDI-BLE REQ Get server configuration") config = serverconfig.getFullConfiguration() if self._sendMidiCallback is not None: self._sendMidiCallback(self._createGetServerConfigMsg(config)) elif data[0] == 0x02 and data[1] == 0x10: # Update server configuration logger.info("MIDI-BLE REQ Update server configuration") dec = sysex_data.decode(data[2:]) configGzip = zlib.decompress(bytes(dec)) configJson = str(configGzip, encoding='utf8') config = json.loads(configJson) try: serverconfig.setConfiguration(config) if self._sendMidiCallback is not None: self._sendMidiCallback( self._createUpdateServerConfigSuccessfulMsg()) except Exception: if self._sendMidiCallback is not None: self._sendMidiCallback( self._createUpdateServerConfigErrorMsg()) elif data[0] == 0x02 and data[1] == 0x20: logger.info("MIDI-BLE REQ Audio rms") rms = {"0": "NO_BUFFER"} if audio.GlobalAudio.buffer is not None: if isinstance(audio.GlobalAudio.buffer, Iterable): numChannels = len(audio.GlobalAudio.buffer) for i in range(numChannels): rmsFromChannel = dsp.rms(audio.GlobalAudio.buffer[i]) rms[str(i)] = rmsFromChannel else: logger.debug("audio.GlobalAudio.buffer not iterateable") if self._sendMidiCallback is not None: self._sendMidiCallback(self._createAudioRMSMsg( json.dumps(rms))) else: logger.error("MIDI-BLE Unknown sysex {} {}".format( hex(data[0]), hex(data[1])))