3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005 - 2013 Christian Schoenebeck * |
* Copyright (C) 2005 - 2014 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This library is free software; you can redistribute it and/or modify * |
* This library is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
47 |
|
|
48 |
namespace LinuxSampler { |
namespace LinuxSampler { |
49 |
|
|
50 |
|
String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param); |
51 |
|
|
52 |
/** |
/** |
53 |
* Returns a copy of the given string where all special characters are |
* Returns a copy of the given string where all special characters are |
54 |
* replaced by LSCP escape sequences ("\xHH"). This function shall be used |
* replaced by LSCP escape sequences ("\xHH"). This function shall be used |
594 |
//Something was selected and it was not the hSocket, so it must be some command(s) coming. |
//Something was selected and it was not the hSocket, so it must be some command(s) coming. |
595 |
for (std::vector<yyparse_param_t>::iterator iter = Sessions.begin(); iter != Sessions.end(); iter++) { |
for (std::vector<yyparse_param_t>::iterator iter = Sessions.begin(); iter != Sessions.end(); iter++) { |
596 |
if (FD_ISSET((*iter).hSession, &selectSet)) { //Was it this socket? |
if (FD_ISSET((*iter).hSession, &selectSet)) { //Was it this socket? |
597 |
|
currentSocket = (*iter).hSession; //a hack |
598 |
if (GetLSCPCommand(iter)) { //Have we read the entire command? |
if (GetLSCPCommand(iter)) { //Have we read the entire command? |
599 |
dmsg(3,("LSCPServer: Got command on socket %d, calling parser.\n", currentSocket)); |
dmsg(3,("LSCPServer: Got command on socket %d, calling parser.\n", currentSocket)); |
600 |
int dummy; // just a temporary hack to fulfill the restart() function prototype |
int dummy; // just a temporary hack to fulfill the restart() function prototype |
601 |
restart(NULL, dummy); // restart the 'scanner' |
restart(NULL, dummy); // restart the 'scanner' |
|
currentSocket = (*iter).hSession; //a hack |
|
602 |
itCurrentSession = iter; // another hack |
itCurrentSession = iter; // another hack |
603 |
dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str())); |
dmsg(2,("LSCPServer: [%s]\n",bufferedCommands[currentSocket].c_str())); |
604 |
if ((*iter).bVerbose) { // if echo mode enabled |
if ((*iter).bVerbose) { // if echo mode enabled |
612 |
CloseConnection(iter); |
CloseConnection(iter); |
613 |
} |
} |
614 |
} |
} |
615 |
|
currentSocket = -1; //continuation of a hack |
616 |
//socket may have been closed, iter may be invalid, get out of the loop for now. |
//socket may have been closed, iter may be invalid, get out of the loop for now. |
617 |
//we'll be back if there is data. |
//we'll be back if there is data. |
618 |
break; |
break; |
742 |
bufferedCommands[socket] += "\r\n"; |
bufferedCommands[socket] += "\r\n"; |
743 |
return true; //Complete command was read |
return true; //Complete command was read |
744 |
} |
} |
745 |
bufferedCommands[socket] += c; |
// backspace character - should only happen with shell |
746 |
|
if (c == '\b') { |
747 |
|
if (!bufferedCommands[socket].empty()) { |
748 |
|
bufferedCommands[socket] = bufferedCommands[socket].substr( |
749 |
|
0, bufferedCommands[socket].length() - 1 |
750 |
|
); |
751 |
|
} |
752 |
|
} else bufferedCommands[socket] += c; |
753 |
|
// only if the other side is the LSCP shell application: |
754 |
|
// check the current (incomplete) command line for syntax errors, |
755 |
|
// possible completions and report everything back to the shell |
756 |
|
if ((*iter).bShellInteract) { |
757 |
|
String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter)); |
758 |
|
if (!s.empty()) AnswerClient(s + "\n"); |
759 |
|
} |
760 |
} |
} |
761 |
#if defined(WIN32) |
#if defined(WIN32) |
762 |
if (result == SOCKET_ERROR) { |
if (result == SOCKET_ERROR) { |
818 |
* @param ReturnMessage - message that will be send to the client |
* @param ReturnMessage - message that will be send to the client |
819 |
*/ |
*/ |
820 |
void LSCPServer::AnswerClient(String ReturnMessage) { |
void LSCPServer::AnswerClient(String ReturnMessage) { |
821 |
dmsg(2,("LSCPServer::AnswerClient(ReturnMessage=%s)", ReturnMessage.c_str())); |
dmsg(2,("LSCPServer::AnswerClient(ReturnMessage='%s')", ReturnMessage.c_str())); |
822 |
if (currentSocket != -1) { |
if (currentSocket != -1) { |
823 |
LockGuard lock(NotifyMutex); |
LockGuard lock(NotifyMutex); |
824 |
|
|
825 |
|
// just if other side is LSCP shell: in case respose is a multi-line |
826 |
|
// one, then inform client about it before sending the actual mult-line |
827 |
|
// response |
828 |
|
if (GetCurrentYaccSession()->bShellInteract) { |
829 |
|
// check if this is a multi-line response |
830 |
|
int n = 0; |
831 |
|
for (int i = 0; i < ReturnMessage.size(); ++i) |
832 |
|
if (ReturnMessage[i] == '\n') ++n; |
833 |
|
if (n >= 2) { |
834 |
|
dmsg(2,("LSCP Shell <- expect mult-line response\n")); |
835 |
|
String s = LSCP_SHK_EXPECT_MULTI_LINE "\r\n"; |
836 |
|
#ifdef MSG_NOSIGNAL |
837 |
|
send(currentSocket, s.c_str(), s.size(), MSG_NOSIGNAL); |
838 |
|
#else |
839 |
|
send(currentSocket, s.c_str(), s.size(), 0); |
840 |
|
#endif |
841 |
|
} |
842 |
|
} |
843 |
|
|
844 |
#ifdef MSG_NOSIGNAL |
#ifdef MSG_NOSIGNAL |
845 |
send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), MSG_NOSIGNAL); |
send(currentSocket, ReturnMessage.c_str(), ReturnMessage.size(), MSG_NOSIGNAL); |
846 |
#else |
#else |
1815 |
return result.Produce(); |
return result.Produce(); |
1816 |
} |
} |
1817 |
|
|
1818 |
|
String LSCPServer::AddChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId, uint MIDIPort) { |
1819 |
|
dmsg(2,("LSCPServer: AddChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d, MIDIPort=%d)\n",uiSamplerChannel,MIDIDeviceId,MIDIPort)); |
1820 |
|
LSCPResultSet result; |
1821 |
|
try { |
1822 |
|
SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); |
1823 |
|
if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); |
1824 |
|
|
1825 |
|
std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices(); |
1826 |
|
if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId)); |
1827 |
|
MidiInputDevice* pDevice = devices[MIDIDeviceId]; |
1828 |
|
|
1829 |
|
MidiInputPort* pPort = pDevice->GetPort(MIDIPort); |
1830 |
|
if (!pPort) throw Exception("There is no MIDI input port with index " + ToString(MIDIPort) + " on MIDI input device with index " + ToString(MIDIDeviceId)); |
1831 |
|
|
1832 |
|
pSamplerChannel->Connect(pPort); |
1833 |
|
} catch (Exception e) { |
1834 |
|
result.Error(e); |
1835 |
|
} |
1836 |
|
return result.Produce(); |
1837 |
|
} |
1838 |
|
|
1839 |
|
String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel) { |
1840 |
|
dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d)\n",uiSamplerChannel)); |
1841 |
|
LSCPResultSet result; |
1842 |
|
try { |
1843 |
|
SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); |
1844 |
|
if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); |
1845 |
|
pSamplerChannel->DisconnectAllMidiInputPorts(); |
1846 |
|
} catch (Exception e) { |
1847 |
|
result.Error(e); |
1848 |
|
} |
1849 |
|
return result.Produce(); |
1850 |
|
} |
1851 |
|
|
1852 |
|
String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId) { |
1853 |
|
dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d)\n",uiSamplerChannel,MIDIDeviceId)); |
1854 |
|
LSCPResultSet result; |
1855 |
|
try { |
1856 |
|
SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); |
1857 |
|
if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); |
1858 |
|
|
1859 |
|
std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices(); |
1860 |
|
if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId)); |
1861 |
|
MidiInputDevice* pDevice = devices[MIDIDeviceId]; |
1862 |
|
|
1863 |
|
std::vector<MidiInputPort*> vPorts = pSamplerChannel->GetMidiInputPorts(); |
1864 |
|
for (int i = 0; i < vPorts.size(); ++i) |
1865 |
|
if (vPorts[i]->GetDevice() == pDevice) |
1866 |
|
pSamplerChannel->Disconnect(vPorts[i]); |
1867 |
|
|
1868 |
|
} catch (Exception e) { |
1869 |
|
result.Error(e); |
1870 |
|
} |
1871 |
|
return result.Produce(); |
1872 |
|
} |
1873 |
|
|
1874 |
|
String LSCPServer::RemoveChannelMidiInput(uint uiSamplerChannel, uint MIDIDeviceId, uint MIDIPort) { |
1875 |
|
dmsg(2,("LSCPServer: RemoveChannelMidiInput(uiSamplerChannel=%d, MIDIDeviceId=%d, MIDIPort=%d)\n",uiSamplerChannel,MIDIDeviceId,MIDIPort)); |
1876 |
|
LSCPResultSet result; |
1877 |
|
try { |
1878 |
|
SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); |
1879 |
|
if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); |
1880 |
|
|
1881 |
|
std::map<uint, MidiInputDevice*> devices = pSampler->GetMidiInputDevices(); |
1882 |
|
if (!devices.count(MIDIDeviceId)) throw Exception("There is no MIDI input device with index " + ToString(MIDIDeviceId)); |
1883 |
|
MidiInputDevice* pDevice = devices[MIDIDeviceId]; |
1884 |
|
|
1885 |
|
MidiInputPort* pPort = pDevice->GetPort(MIDIPort); |
1886 |
|
if (!pPort) throw Exception("There is no MIDI input port with index " + ToString(MIDIPort) + " on MIDI input device with index " + ToString(MIDIDeviceId)); |
1887 |
|
|
1888 |
|
pSamplerChannel->Disconnect(pPort); |
1889 |
|
} catch (Exception e) { |
1890 |
|
result.Error(e); |
1891 |
|
} |
1892 |
|
return result.Produce(); |
1893 |
|
} |
1894 |
|
|
1895 |
|
String LSCPServer::ListChannelMidiInputs(uint uiSamplerChannel) { |
1896 |
|
dmsg(2,("LSCPServer: ListChannelMidiInputs(uiSamplerChannel=%d)\n",uiSamplerChannel)); |
1897 |
|
LSCPResultSet result; |
1898 |
|
try { |
1899 |
|
SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(uiSamplerChannel); |
1900 |
|
if (!pSamplerChannel) throw Exception("Invalid sampler channel number " + ToString(uiSamplerChannel)); |
1901 |
|
std::vector<MidiInputPort*> vPorts = pSamplerChannel->GetMidiInputPorts(); |
1902 |
|
|
1903 |
|
String s; |
1904 |
|
for (int i = 0; i < vPorts.size(); ++i) { |
1905 |
|
const int iDeviceID = vPorts[i]->GetDevice()->MidiInputDeviceID(); |
1906 |
|
const int iPortNr = vPorts[i]->GetPortNumber(); |
1907 |
|
if (s.size()) s += ","; |
1908 |
|
s += "{" + ToString(iDeviceID) + "," |
1909 |
|
+ ToString(iPortNr) + "}"; |
1910 |
|
} |
1911 |
|
result.Add(s); |
1912 |
|
} catch (Exception e) { |
1913 |
|
result.Error(e); |
1914 |
|
} |
1915 |
|
return result.Produce(); |
1916 |
|
} |
1917 |
|
|
1918 |
String LSCPServer::SetMIDIInputPort(uint MIDIPort, uint uiSamplerChannel) { |
String LSCPServer::SetMIDIInputPort(uint MIDIPort, uint uiSamplerChannel) { |
1919 |
dmsg(2,("LSCPServer: SetMIDIInputPort(MIDIPort=%d, SamplerChannel=%d)\n",MIDIPort,uiSamplerChannel)); |
dmsg(2,("LSCPServer: SetMIDIInputPort(MIDIPort=%d, SamplerChannel=%d)\n",MIDIPort,uiSamplerChannel)); |
1920 |
LSCPResultSet result; |
LSCPResultSet result; |
3996 |
} |
} |
3997 |
return result.Produce(); |
return result.Produce(); |
3998 |
} |
} |
3999 |
|
|
4000 |
|
String LSCPServer::SetShellInteract(yyparse_param_t* pSession, double boolean_value) { |
4001 |
|
dmsg(2,("LSCPServer: SetShellInteract(val=%f)\n", boolean_value)); |
4002 |
|
LSCPResultSet result; |
4003 |
|
try { |
4004 |
|
if (boolean_value == 0) pSession->bShellInteract = false; |
4005 |
|
else if (boolean_value == 1) pSession->bShellInteract = true; |
4006 |
|
else throw Exception("Not a boolean value, must either be 0 or 1"); |
4007 |
|
} catch (Exception e) { |
4008 |
|
result.Error(e); |
4009 |
|
} |
4010 |
|
return result.Produce(); |
4011 |
|
} |
4012 |
|
|
4013 |
} |
} |