--- linuxsampler/trunk/src/network/lscpserver.cpp 2006/07/23 16:23:13 905 +++ linuxsampler/trunk/src/network/lscpserver.cpp 2007/01/02 15:37:01 1007 @@ -24,7 +24,7 @@ #include "lscpserver.h" #include "lscpresultset.h" #include "lscpevent.h" -//#include "../common/global.h" +#include "../common/global.h" #include @@ -66,11 +66,19 @@ SocketAddress.sin_addr.s_addr = addr; SocketAddress.sin_port = port; this->pSampler = pSampler; + LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_count, "AUDIO_OUTPUT_DEVICE_COUNT"); + LSCPEvent::RegisterEvent(LSCPEvent::event_audio_device_info, "AUDIO_OUTPUT_DEVICE_INFO"); + LSCPEvent::RegisterEvent(LSCPEvent::event_midi_device_count, "MIDI_INPUT_DEVICE_COUNT"); + LSCPEvent::RegisterEvent(LSCPEvent::event_midi_device_info, "MIDI_INPUT_DEVICE_INFO"); LSCPEvent::RegisterEvent(LSCPEvent::event_channel_count, "CHANNEL_COUNT"); LSCPEvent::RegisterEvent(LSCPEvent::event_voice_count, "VOICE_COUNT"); LSCPEvent::RegisterEvent(LSCPEvent::event_stream_count, "STREAM_COUNT"); LSCPEvent::RegisterEvent(LSCPEvent::event_buffer_fill, "BUFFER_FILL"); LSCPEvent::RegisterEvent(LSCPEvent::event_channel_info, "CHANNEL_INFO"); + LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_map_count, "MIDI_INSTRUMENT_MAP_COUNT"); + LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_map_info, "MIDI_INSTRUMENT_MAP_INFO"); + LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_count, "MIDI_INSTRUMENT_COUNT"); + LSCPEvent::RegisterEvent(LSCPEvent::event_midi_instr_info, "MIDI_INSTRUMENT_INFO"); LSCPEvent::RegisterEvent(LSCPEvent::event_misc, "MISCELLANEOUS"); LSCPEvent::RegisterEvent(LSCPEvent::event_total_voice_count, "TOTAL_VOICE_COUNT"); hSocket = -1; @@ -322,7 +330,7 @@ continue; //Ignore CR if (c == '\n') { LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket)); - bufferedCommands[socket] += "\n"; + bufferedCommands[socket] += "\r\n"; return true; //Complete command was read } bufferedCommands[socket] += c; @@ -496,7 +504,10 @@ if (!pSamplerChannel->GetAudioOutputDevice()) throw Exception("No audio output device connected to sampler channel"); if (bBackground) { - InstrumentLoader.StartNewLoad(Filename, uiInstrument, pEngineChannel); + InstrumentManager::instrument_id_t id; + id.FileName = Filename; + id.Index = uiInstrument; + InstrumentManager::LoadInstrumentInBackground(id, pEngineChannel); } else { // tell the engine channel which instrument to load @@ -659,6 +670,7 @@ String AudioRouting; int Mute = 0; bool Solo = false; + String MidiInstrumentMap; if (pEngineChannel) { EngineName = pEngineChannel->EngineName(); @@ -676,6 +688,12 @@ } Mute = pEngineChannel->GetMute(); Solo = pEngineChannel->GetSolo(); + if (pEngineChannel->UsesNoMidiInstrumentMap()) + MidiInstrumentMap = "NONE"; + else if (pEngineChannel->UsesDefaultMidiInstrumentMap()) + MidiInstrumentMap = "DEFAULT"; + else + MidiInstrumentMap = ToString(pEngineChannel->GetMidiInstrumentMap()); } result.Add("ENGINE_NAME", EngineName); @@ -697,6 +715,7 @@ result.Add("INSTRUMENT_STATUS", InstrumentStatus); result.Add("MUTE", Mute == -1 ? "MUTED_BY_SOLO" : (Mute ? "true" : "false")); result.Add("SOLO", Solo); + result.Add("MIDI_INSTRUMENT_MAP", MidiInstrumentMap); } catch (Exception e) { result.Error(e); @@ -1174,6 +1193,7 @@ // set new channel parameter value pParameter->SetValue(ParamVal); + LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_info, DeviceId)); } catch (Exception e) { result.Error(e); @@ -1191,6 +1211,7 @@ std::map parameters = pDevice->DeviceParameters(); if (!parameters.count(ParamKey)) throw Exception("Audio output device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'"); parameters[ParamKey]->SetValue(ParamVal); + LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_audio_device_info, DeviceIndex)); } catch (Exception e) { result.Error(e); @@ -1208,6 +1229,7 @@ std::map parameters = pDevice->DeviceParameters(); if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(DeviceIndex) + " does not have a device parameter '" + ParamKey + "'"); parameters[ParamKey]->SetValue(ParamVal); + LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_info, DeviceIndex)); } catch (Exception e) { result.Error(e); @@ -1232,6 +1254,7 @@ std::map parameters = pMidiInputPort->PortParameters(); if (!parameters.count(ParamKey)) throw Exception("MIDI input device " + ToString(PortIndex) + " does not have a parameter '" + ParamKey + "'"); parameters[ParamKey]->SetValue(ParamVal); + LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_device_info, DeviceIndex)); } catch (Exception e) { result.Error(e); @@ -1544,6 +1567,451 @@ } } +String LSCPServer::AddOrReplaceMIDIInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg, String EngineType, String InstrumentFile, uint InstrumentIndex, float Volume, MidiInstrumentMapper::mode_t LoadMode, String Name) { + dmsg(2,("LSCPServer: AddOrReplaceMIDIInstrumentMapping()\n")); + + midi_prog_index_t idx; + idx.midi_bank_msb = (MidiBank >> 7) & 0x7f; + idx.midi_bank_lsb = MidiBank & 0x7f; + idx.midi_prog = MidiProg; + + MidiInstrumentMapper::entry_t entry; + entry.EngineName = EngineType; + entry.InstrumentFile = InstrumentFile; + entry.InstrumentIndex = InstrumentIndex; + entry.LoadMode = LoadMode; + entry.Volume = Volume; + entry.Name = Name; + + LSCPResultSet result; + try { + // PERSISTENT mapping commands might bloock for a long time, so in + // that case we add/replace the mapping in another thread + bool bInBackground = (entry.LoadMode == MidiInstrumentMapper::PERSISTENT); + MidiInstrumentMapper::AddOrReplaceEntry(MidiMapID, idx, entry, bInBackground); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::RemoveMIDIInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg) { + dmsg(2,("LSCPServer: RemoveMIDIInstrumentMapping()\n")); + + midi_prog_index_t idx; + idx.midi_bank_msb = (MidiBank >> 7) & 0x7f; + idx.midi_bank_lsb = MidiBank & 0x7f; + idx.midi_prog = MidiProg; + + LSCPResultSet result; + try { + MidiInstrumentMapper::RemoveEntry(MidiMapID, idx); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::GetMidiInstrumentMappings(uint MidiMapID) { + dmsg(2,("LSCPServer: GetMidiInstrumentMappings()\n")); + LSCPResultSet result; + try { + result.Add(MidiInstrumentMapper::Entries(MidiMapID).size()); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + + +String LSCPServer::GetAllMidiInstrumentMappings() { + dmsg(2,("LSCPServer: GetAllMidiInstrumentMappings()\n")); + LSCPResultSet result; + std::vector maps = MidiInstrumentMapper::Maps(); + int totalMappings = 0; + for (int i = 0; i < maps.size(); i++) { + try { + totalMappings += MidiInstrumentMapper::Entries(maps[i]).size(); + } catch (Exception e) { /*NOOP*/ } + } + result.Add(totalMappings); + return result.Produce(); +} + +String LSCPServer::GetMidiInstrumentMapping(uint MidiMapID, uint MidiBank, uint MidiProg) { + dmsg(2,("LSCPServer: GetMidiIstrumentMapping()\n")); + LSCPResultSet result; + try { + midi_prog_index_t idx; + idx.midi_bank_msb = (MidiBank >> 7) & 0x7f; + idx.midi_bank_lsb = MidiBank & 0x7f; + idx.midi_prog = MidiProg; + + std::map mappings = MidiInstrumentMapper::Entries(MidiMapID); + std::map::iterator iter = mappings.find(idx); + if (iter == mappings.end()) result.Error("there is no map entry with that index"); + else { // found + result.Add("NAME", iter->second.Name); + result.Add("ENGINE_NAME", iter->second.EngineName); + result.Add("INSTRUMENT_FILE", iter->second.InstrumentFile); + result.Add("INSTRUMENT_NR", (int) iter->second.InstrumentIndex); + String instrumentName; + Engine* pEngine = EngineFactory::Create(iter->second.EngineName); + if (pEngine) { + if (pEngine->GetInstrumentManager()) { + InstrumentManager::instrument_id_t instrID; + instrID.FileName = iter->second.InstrumentFile; + instrID.Index = iter->second.InstrumentIndex; + instrumentName = pEngine->GetInstrumentManager()->GetInstrumentName(instrID); + } + EngineFactory::Destroy(pEngine); + } + result.Add("INSTRUMENT_NAME", instrumentName); + switch (iter->second.LoadMode) { + case MidiInstrumentMapper::ON_DEMAND: + result.Add("LOAD_MODE", "ON_DEMAND"); + break; + case MidiInstrumentMapper::ON_DEMAND_HOLD: + result.Add("LOAD_MODE", "ON_DEMAND_HOLD"); + break; + case MidiInstrumentMapper::PERSISTENT: + result.Add("LOAD_MODE", "PERSISTENT"); + break; + default: + throw Exception("entry reflects invalid LOAD_MODE, consider this as a bug!"); + } + result.Add("VOLUME", iter->second.Volume); + } + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::ListMidiInstrumentMappings(uint MidiMapID) { + dmsg(2,("LSCPServer: ListMidiInstrumentMappings()\n")); + LSCPResultSet result; + try { + String s; + std::map mappings = MidiInstrumentMapper::Entries(MidiMapID); + std::map::iterator iter = mappings.begin(); + for (; iter != mappings.end(); iter++) { + if (s.size()) s += ","; + s += "{" + ToString(MidiMapID) + "," + + ToString((int(iter->first.midi_bank_msb) << 7) | int(iter->first.midi_bank_lsb)) + "," + + ToString(int(iter->first.midi_prog)) + "}"; + } + result.Add(s); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::ListAllMidiInstrumentMappings() { + dmsg(2,("LSCPServer: ListAllMidiInstrumentMappings()\n")); + LSCPResultSet result; + try { + std::vector maps = MidiInstrumentMapper::Maps(); + String s; + for (int i = 0; i < maps.size(); i++) { + std::map mappings = MidiInstrumentMapper::Entries(maps[i]); + std::map::iterator iter = mappings.begin(); + for (; iter != mappings.end(); iter++) { + if (s.size()) s += ","; + s += "{" + ToString(maps[i]) + "," + + ToString((int(iter->first.midi_bank_msb) << 7) & int(iter->first.midi_bank_lsb)) + "," + + ToString(int(iter->first.midi_prog)) + "}"; + } + } + result.Add(s); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::ClearMidiInstrumentMappings(uint MidiMapID) { + dmsg(2,("LSCPServer: ClearMidiInstrumentMappings()\n")); + LSCPResultSet result; + try { + MidiInstrumentMapper::RemoveAllEntries(MidiMapID); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::ClearAllMidiInstrumentMappings() { + dmsg(2,("LSCPServer: ClearAllMidiInstrumentMappings()\n")); + LSCPResultSet result; + try { + std::vector maps = MidiInstrumentMapper::Maps(); + for (int i = 0; i < maps.size(); i++) + MidiInstrumentMapper::RemoveAllEntries(maps[i]); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::AddMidiInstrumentMap(String MapName) { + dmsg(2,("LSCPServer: AddMidiInstrumentMap()\n")); + LSCPResultSet result; + try { + int MapID = MidiInstrumentMapper::AddMap(MapName); + result = LSCPResultSet(MapID); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::RemoveMidiInstrumentMap(uint MidiMapID) { + dmsg(2,("LSCPServer: RemoveMidiInstrumentMap()\n")); + LSCPResultSet result; + try { + MidiInstrumentMapper::RemoveMap(MidiMapID); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::RemoveAllMidiInstrumentMaps() { + dmsg(2,("LSCPServer: RemoveAllMidiInstrumentMaps()\n")); + LSCPResultSet result; + try { + MidiInstrumentMapper::RemoveAllMaps(); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::GetMidiInstrumentMaps() { + dmsg(2,("LSCPServer: GetMidiInstrumentMaps()\n")); + LSCPResultSet result; + try { + result.Add(MidiInstrumentMapper::Maps().size()); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::ListMidiInstrumentMaps() { + dmsg(2,("LSCPServer: ListMidiInstrumentMaps()\n")); + LSCPResultSet result; + try { + std::vector maps = MidiInstrumentMapper::Maps(); + String sList; + for (int i = 0; i < maps.size(); i++) { + if (sList != "") sList += ","; + sList += ToString(maps[i]); + } + result.Add(sList); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::GetMidiInstrumentMap(uint MidiMapID) { + dmsg(2,("LSCPServer: GetMidiInstrumentMap()\n")); + LSCPResultSet result; + try { + result.Add("NAME", MidiInstrumentMapper::MapName(MidiMapID)); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::SetMidiInstrumentMapName(uint MidiMapID, String NewName) { + dmsg(2,("LSCPServer: SetMidiInstrumentMapName()\n")); + LSCPResultSet result; + try { + MidiInstrumentMapper::RenameMap(MidiMapID, NewName); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +/** + * Set the MIDI instrument map the given sampler channel shall use for + * handling MIDI program change messages. There are the following two + * special (negative) values: + * + * - (-1) : set to NONE (ignore program changes) + * - (-2) : set to DEFAULT map + */ +String LSCPServer::SetChannelMap(uint uiSamplerChannel, int MidiMapID) { + dmsg(2,("LSCPServer: SetChannelMap()\n")); + LSCPResultSet result; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + if (MidiMapID == -1) pEngineChannel->SetMidiInstrumentMapToNone(); + else if (MidiMapID == -2) pEngineChannel->SetMidiInstrumentMapToDefault(); + else pEngineChannel->SetMidiInstrumentMap(MidiMapID); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::CreateFxSend(uint uiSamplerChannel, uint MidiCtrl, String Name) { + dmsg(2,("LSCPServer: CreateFxSend()\n")); + LSCPResultSet result; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + FxSend* pFxSend = pEngineChannel->AddFxSend(MidiCtrl, Name); + if (!pFxSend) throw Exception("Could not add FxSend, don't ask, I don't know why (probably a bug)"); + + result = LSCPResultSet(pFxSend->Id()); // success + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::DestroyFxSend(uint uiSamplerChannel, uint FxSendID) { + dmsg(2,("LSCPServer: DestroyFxSend()\n")); + LSCPResultSet result; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + FxSend* pFxSend = NULL; + for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) { + if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) { + pFxSend = pEngineChannel->GetFxSend(i); + break; + } + } + if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel"); + pEngineChannel->RemoveFxSend(pFxSend); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::GetFxSends(uint uiSamplerChannel) { + dmsg(2,("LSCPServer: GetFxSends()\n")); + LSCPResultSet result; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + result.Add(pEngineChannel->GetFxSendCount()); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::ListFxSends(uint uiSamplerChannel) { + dmsg(2,("LSCPServer: ListFxSends()\n")); + LSCPResultSet result; + String list; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) { + FxSend* pFxSend = pEngineChannel->GetFxSend(i); + if (list != "") list += ","; + list += ToString(pFxSend->Id()); + } + result.Add(list); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::GetFxSendInfo(uint uiSamplerChannel, uint FxSendID) { + dmsg(2,("LSCPServer: GetFxSendInfo()\n")); + LSCPResultSet result; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + FxSend* pFxSend = NULL; + for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) { + if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) { + pFxSend = pEngineChannel->GetFxSend(i); + break; + } + } + if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel"); + + // gather audio routing informations + String AudioRouting; + for (int chan = 0; chan < pEngineChannel->Channels(); chan++) { + if (AudioRouting != "") AudioRouting += ","; + AudioRouting += ToString(pFxSend->DestinationChannel(chan)); + } + + // success + result.Add("NAME", pFxSend->Name()); + result.Add("AUDIO_OUTPUT_ROUTING", AudioRouting); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + +String LSCPServer::SetFxSendAudioOutputChannel(uint uiSamplerChannel, uint FxSendID, uint FxSendChannel, uint DeviceChannel) { + dmsg(2,("LSCPServer: SetFxSendAudioOutputChannel()\n")); + LSCPResultSet result; + try { + SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); + if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); + + EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel(); + if (!pEngineChannel) throw Exception("There is no engine deployed on this sampler channel yet"); + + FxSend* pFxSend = NULL; + for (int i = 0; i < pEngineChannel->GetFxSendCount(); i++) { + if (pEngineChannel->GetFxSend(i)->Id() == FxSendID) { + pFxSend = pEngineChannel->GetFxSend(i); + break; + } + } + if (!pFxSend) throw Exception("There is no FxSend with that ID on the given sampler channel"); + + pFxSend->SetDestinationChannel(FxSendChannel, DeviceChannel); + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + /** * Will be called by the parser to reset a particular sampler channel. */ @@ -1582,7 +2050,7 @@ LSCPResultSet result; result.Add("DESCRIPTION", "LinuxSampler - modular, streaming capable sampler"); result.Add("VERSION", VERSION); - result.Add("PROTOCOL_VERSION", "1.0"); + result.Add("PROTOCOL_VERSION", ToString(LSCP_RELEASE_MAJOR) + "." + ToString(LSCP_RELEASE_MINOR)); return result.Produce(); } @@ -1606,6 +2074,23 @@ return result.Produce(); } +String LSCPServer::GetGlobalVolume() { + LSCPResultSet result; + result.Add(ToString(GLOBAL_VOLUME)); // see common/global.cpp + return result.Produce(); +} + +String LSCPServer::SetGlobalVolume(double dVolume) { + LSCPResultSet result; + try { + if (dVolume < 0) throw Exception("Volume may not be negative"); + GLOBAL_VOLUME = dVolume; // see common/global.cpp + } catch (Exception e) { + result.Error(e); + } + return result.Produce(); +} + /** * Will be called by the parser to subscribe a client (frontend) on the * server for receiving event messages.