--- jlscp/trunk/src/org/linuxsampler/lscp/Client.java 2007/05/24 20:17:25 1202 +++ jlscp/trunk/src/org/linuxsampler/lscp/Client.java 2007/12/03 22:59:39 1539 @@ -34,9 +34,10 @@ import java.util.logging.Level; import java.util.logging.Logger; -import static org.linuxsampler.lscp.Parser.*; import org.linuxsampler.lscp.event.*; +import static org.linuxsampler.lscp.Parser.*; + /** * This class is the abstraction representing a client endpoint for communication with LinuxSampler @@ -542,8 +543,10 @@ if(s.startsWith("NAME ")) { String[] list; try { - list = parseStringList(s.substring("NAME ".length()), ' '); + s = s.substring("NAME ".length()); + list = parseEscapedStringList(s, ' '); if(list.length != 2) throw new LscpException(); + list[1] = toNonEscapedString(list[1]); e = new InstrumentsDbEvent(this, list[0], list[1]); for(InstrumentsDbListener l : llID) { l.directoryNameChanged(e); @@ -569,8 +572,10 @@ if(s.startsWith("NAME ")) { String[] list; try { - list = parseStringList(s.substring("NAME ".length()), ' '); + s = s.substring("NAME ".length()); + list = parseEscapedStringList(s, ' '); if(list.length != 2) throw new LscpException(); + list[1] = toNonEscapedString(list[1]); e = new InstrumentsDbEvent(this, list[0], list[1]); for(InstrumentsDbListener l : llID) { l.instrumentNameChanged(e); @@ -1355,7 +1360,7 @@ /** * Gets detailed information about a specific audio output driver. * @param driverName The name of the audio output driver. - * + * @param depList An optional list of dependences parameters. * @return An AudioOutputDriver object containing * information about the specified audio output driver. * @@ -1365,8 +1370,10 @@ * * @see #getAudioOutputDriverNames */ - private synchronized AudioOutputDriver - getAudioOutputDriverInfo(String driverName) throws IOException, LscpException, LSException { + public synchronized AudioOutputDriver + getAudioOutputDriverInfo(String driverName, Parameter... depList) + throws IOException, LscpException, LSException { + verifyConnection(); out.writeLine("GET AUDIO_OUTPUT_DRIVER INFO " + driverName); if(getPrintOnlyMode()) return null; @@ -1376,7 +1383,7 @@ aod.setName(driverName); for(String s : aod.getParameterNames()) - aod.addParameter(getAudioOutputDriverParameterInfo(driverName, s)); + aod.addParameter(getAudioOutputDriverParameterInfo(driverName, s, depList)); return aod; } @@ -1410,8 +1417,10 @@ StringBuffer args = new StringBuffer(driver); args.append(' ').append(param); - for(Parameter p : deplist) + for(Parameter p : deplist) { + if(p.getValue() == null) continue; args.append(' ').append(p.getName()).append('=').append(p.getStringValue()); + } out.writeLine("GET AUDIO_OUTPUT_DRIVER_PARAMETER INFO " + args.toString()); if(getPrintOnlyMode()) return null; @@ -1472,8 +1481,10 @@ verifyConnection(); StringBuffer args = new StringBuffer(aoDriver); - for(Parameter p : paramList) + for(Parameter p : paramList) { + if(p.getValue() == null) continue; args.append(' ').append(p.getName()).append('=').append(p.getStringValue()); + } out.writeLine("CREATE AUDIO_OUTPUT_DEVICE " + args.toString()); if(getPrintOnlyMode()) return -1; @@ -1934,7 +1945,7 @@ /** * Gets detailed information about a specific MIDI input driver. * @param driverName The name of the MIDI input driver. - * + * @param depList An optional list of dependences parameters. * @return A MidiInputDriver object containing * information about the specified MIDI input driver. * @@ -1944,8 +1955,10 @@ * * @see #getMidiInputDriverNames */ - private synchronized MidiInputDriver - getMidiInputDriverInfo(String driverName) throws IOException, LscpException, LSException { + public synchronized MidiInputDriver + getMidiInputDriverInfo(String driverName, Parameter... depList) + throws IOException, LscpException, LSException { + verifyConnection(); out.writeLine("GET MIDI_INPUT_DRIVER INFO " + driverName); if(getPrintOnlyMode()) return null; @@ -1956,7 +1969,7 @@ mid.setName(driverName); for(String s : mid.getParameterNames()) - mid.addParameter(getMidiInputDriverParameterInfo(driverName, s)); + mid.addParameter(getMidiInputDriverParameterInfo(driverName, s, depList)); return mid; } @@ -1990,8 +2003,10 @@ StringBuffer args = new StringBuffer(driver); args.append(' ').append(param); - for(Parameter p : deplist) + for(Parameter p : deplist) { + if(p.getValue() == null) continue; args.append(' ').append(p.getName()).append('=').append(p.getStringValue()); + } out.writeLine("GET MIDI_INPUT_DRIVER_PARAMETER INFO " + args.toString()); if(getPrintOnlyMode()) return null; @@ -2053,8 +2068,10 @@ verifyConnection(); StringBuffer args = new StringBuffer(miDriver); - for(Parameter p : paramList) + for(Parameter p : paramList) { + if(p.getValue() == null) continue; args.append(' ').append(p.getName()).append('=').append(p.getStringValue()); + } out.writeLine("CREATE MIDI_INPUT_DEVICE " + args.toString()); if(getPrintOnlyMode()) return -1; @@ -2199,8 +2216,15 @@ mid.setActive(Boolean.parseBoolean(s)); } else if(s.startsWith("PORTS: ")) { s = s.substring("PORTS: ".length()); - int ports = Parser.parseInt(s); - MidiPort[] midiPorts = new MidiPort[ports > 0 ? ports : 0]; + + Parameter ports = (Parameter) + getMidiInputDriverParameterInfo(drv, "PORTS"); + + ports.parseValue(s); + mid.setPortsParameter(ports); + + int j = ports.getValue(); + MidiPort[] midiPorts = new MidiPort[j > 0 ? j : 0]; for(int i = 0; i < midiPorts.length; i++) midiPorts[i] = getMidiInputPortInfo(deviceId, i); @@ -2443,7 +2467,7 @@ public synchronized int addMidiInstrumentMap(String name) throws IOException, LSException, LscpException { verifyConnection(); - out.writeLine("ADD MIDI_INSTRUMENT_MAP '" + name + "'"); + out.writeLine("ADD MIDI_INSTRUMENT_MAP '" + toEscapedString(name) + "'"); if(getPrintOnlyMode()) return -1; ResultSet rs = getEmptyResultSet(); @@ -2546,7 +2570,7 @@ for(String s : lnS) { if(s.startsWith("NAME: ")) { - name = s.substring("NAME: ".length()); + name = toNonEscapedString(s.substring("NAME: ".length())); } else if(s.startsWith("DEFAULT: ")) { b = Boolean.parseBoolean(s.substring("DEFAULT: ".length())); } else { @@ -2594,6 +2618,7 @@ throws IOException, LscpException, LSException { verifyConnection(); + name = toEscapedString(name); out.writeLine("SET MIDI_INSTRUMENT_MAP NAME " + + mapId + " '" + name + "'"); if(getPrintOnlyMode()) return; @@ -2649,7 +2674,11 @@ if(!info.getLoadMode().name().equals("DEFAULT")) { cmd.append(' ').append(info.getLoadMode().name()); } - if(info.getName() != null) cmd.append(" '").append(info.getName()).append("'"); + + if(info.getName() != null) { + String s = toEscapedString(info.getName()); + cmd.append(" '").append(s).append("'"); + } out.writeLine(cmd.toString()); if(getPrintOnlyMode()) return; @@ -3498,7 +3527,7 @@ verifyConnection(); String s = String.valueOf(channel) + " " + String.valueOf(midiCtrl); - if(name != null) s += " '" + name + "'"; + if(name != null) s += " '" + toEscapedString(name) + "'"; out.writeLine("CREATE FX_SEND " + s); if(getPrintOnlyMode()) return -1; @@ -3629,7 +3658,7 @@ throws IOException, LscpException, LSException { verifyConnection(); - String args = " " + channel + " " + fxSend + " '" + name + "'"; + String args = " " + channel + " " + fxSend + " '" + toEscapedString(name) + "'"; out.writeLine("SET FX_SEND NAME" + args); if(getPrintOnlyMode()) return; @@ -3717,11 +3746,30 @@ ResultSet rs = getEmptyResultSet(); } + /** + * Starts an instrument editor for editing the loaded instrument + * on the specified sampler channel. + * @param samplerChn The sampler channel number. + * @throws IOException If some I/O error occurs. + * @throws LscpException If LSCP protocol corruption occurs. + * @throws LSException If samplerChn is not a valid channel number or if + * there is no instrument loaded on the specified sampler channel. + * @see #getSamplerChannels + */ + public synchronized void + editChannelInstrument(int samplerChn) throws IOException, LscpException, LSException { + verifyConnection(); + out.writeLine("EDIT CHANNEL INSTRUMENT " + samplerChn); + if(getPrintOnlyMode()) return; + + ResultSet rs = getEmptyResultSet(); + } + /** * Adds the specified directory to the instruments database. - * @param dir The absolute path name of the directory to add. + * @param dir The absolute (escaped) path name of the directory to add. * @throws IOException If some I/O error occurs. * @throws LSException If the creation of the directory failed. * @throws LscpException If LSCP protocol corruption occurs. @@ -3737,7 +3785,7 @@ /** * Removes the specified directory from the instruments database. - * @param dir The absolute path name of the directory to remove. + * @param dir The absolute (escaped) path name of the directory to remove. * @throws IOException If some I/O error occurs. * @throws LscpException If LSCP protocol corruption occurs. * @throws LSException If the specified directory is not @@ -3772,7 +3820,7 @@ /** * Removes the specified directories from the instruments database. - * @param dirs The absolute path names of the directories to remove. + * @param dirs The absolute (escaped) path names of the directories to remove. * @param force If true forces the removal of non-empty * directories. * @throws IOException If some I/O error occurs. @@ -3847,7 +3895,11 @@ out.writeLine("LIST DB_INSTRUMENT_DIRECTORIES '" + dir + "'"); if(getPrintOnlyMode()) return null; - return parseStringList(getSingleLineResultSet().getResult()); + String[] names = parseEscapedStringList(getSingleLineResultSet().getResult()); + for(int i = 0; i < names.length; i++) { + names[i] = toNonEscapedString(names[i]); + } + return names; } /** @@ -3869,15 +3921,13 @@ DbDirectoryInfo info = new DbDirectoryInfo(rs.getMultiLineResult()); if(dir.equals("/")) { info.setName("/"); - } else if(dir.length() > 1 && dir.charAt(dir.length() - 1) == '/') { - dir = dir.substring(0, dir.length() - 1); - } - int i = dir.lastIndexOf('/'); - if(i != -1 && i < dir.length() - 1) { - info.setName(dir.substring(i + 1)); - if(i == 0) info.setParentDirectoryPath("/"); - else info.setParentDirectoryPath(dir.substring(0, i)); + } else { + dir = removeEndingFileSeparator(dir); } + String s = getFileName(dir); + if(s != null) info.setName(toNonEscapedFileName(s)); + s = getParentDirectory(dir); + if(s != null) info.setParentDirectoryPath(s); return info; } @@ -3894,9 +3944,11 @@ public synchronized DbDirectoryInfo[] getDbDirectories(String dir) throws IOException, LscpException, LSException { String[] dirS = getDbDirectoryNames(dir); - if(dir.charAt(dir.length() - 1) != '/') dir += "/"; + if(!hasEndingFileSeparator(dir)) dir += "/"; DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length]; - for(int i = 0; i < dirS.length; i++) infoS[i] = getDbDirectoryInfo(dir + dirS[i]); + for(int i = 0; i < dirS.length; i++) { + infoS[i] = getDbDirectoryInfo(dir + toEscapedFileName(dirS[i])); + } return infoS; } @@ -3961,6 +4013,7 @@ public synchronized void renameDbDirectory(String dir, String name) throws IOException, LSException, LscpException { verifyConnection(); + name = toEscapedString(name); out.writeLine("SET DB_INSTRUMENT_DIRECTORY NAME '" + dir + "' '" + name + "'"); if(getPrintOnlyMode()) return; @@ -4053,7 +4106,7 @@ verifyConnection(); String s = "SET DB_INSTRUMENT_DIRECTORY DESCRIPTION '"; - out.writeLine(s + dir + "' '" + desc + "'"); + out.writeLine(s + dir + "' '" + toEscapedString(desc) + "'"); if(getPrintOnlyMode()) return; ResultSet rs = getEmptyResultSet(); @@ -4232,7 +4285,8 @@ break; } - sb.append(" '").append(dbDir).append("' '").append(fsDir).append("'"); + sb.append(" '").append(dbDir).append("' '"); + sb.append(fsDir).append("'"); out.writeLine(sb.toString()); if(getPrintOnlyMode()) return -1; @@ -4328,7 +4382,11 @@ out.writeLine("LIST DB_INSTRUMENTS '" + dir + "'"); if(getPrintOnlyMode()) return null; - return parseStringList(getSingleLineResultSet().getResult()); + String[] names = parseEscapedStringList(getSingleLineResultSet().getResult()); + for(int i = 0; i < names.length; i++) { + names[i] = toNonEscapedString(names[i]); + } + return names; } /** @@ -4348,12 +4406,10 @@ ResultSet rs = getMultiLineResultSet(); DbInstrumentInfo info = new DbInstrumentInfo(rs.getMultiLineResult()); - int i = instr.lastIndexOf('/'); - if(i != -1 && i < instr.length() - 1) { - info.setName(instr.substring(i + 1)); - if(i == 0) info.setDirectoryPath("/"); - else info.setDirectoryPath(instr.substring(0, i)); - } + String s = getParentDirectory(instr); + if(s != null) info.setDirectoryPath(s); + s = getFileName(instr); + if(s != null) info.setName(toNonEscapedFileName(s)); return info; } @@ -4370,11 +4426,11 @@ public synchronized DbInstrumentInfo[] getDbInstruments(String dir) throws IOException, LscpException, LSException { String[] instrS = getDbInstrumentNames(dir); - if(dir.charAt(dir.length() - 1) != '/') dir += "/"; + if(!hasEndingFileSeparator(dir)) dir += "/"; DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length]; for(int i = 0; i < instrS.length; i++) { - infoS[i] = getDbInstrumentInfo(dir + instrS[i]); + infoS[i] = getDbInstrumentInfo(dir + toEscapedFileName(instrS[i])); } return infoS; } @@ -4442,6 +4498,7 @@ throws IOException, LSException, LscpException { verifyConnection(); + name = toEscapedString(name); out.writeLine("SET DB_INSTRUMENT NAME '" + instr + "' '" + name + "'"); if(getPrintOnlyMode()) return; @@ -4533,6 +4590,7 @@ throws IOException, LSException, LscpException { verifyConnection(); + desc = toEscapedString(desc); out.writeLine("SET DB_INSTRUMENT DESCRIPTION '" + instr + "' '" + desc + "'"); if(getPrintOnlyMode()) return; @@ -4580,7 +4638,7 @@ sb.append(" '").append(dir).append("'"); if(query.name != null && query.name.length() > 0) { - sb.append(" NAME='").append(query.name).append("'"); + sb.append(" NAME='").append(toEscapedString(query.name)).append("'"); } String s = query.getCreatedAfter(); @@ -4604,13 +4662,14 @@ } if(query.description != null && query.description.length() > 0) { - sb.append(" DESCRIPTION='").append(query.description).append("'"); + sb.append(" DESCRIPTION='"); + sb.append(toEscapedString(query.description)).append("'"); } out.writeLine(sb.toString()); if(getPrintOnlyMode()) return null; - String[] dirS = parseStringList(getSingleLineResultSet().getResult()); + String[] dirS = parseEscapedStringList(getSingleLineResultSet().getResult()); DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length]; for(int i = 0; i < dirS.length; i++) { @@ -4660,7 +4719,7 @@ sb.append(" '").append(dir).append("'"); if(query.name != null && query.name.length() > 0) { - sb.append(" NAME='").append(query.name).append("'"); + sb.append(" NAME='").append(toEscapedString(query.name)).append("'"); } if(query.formatFamilies.size() > 0) { @@ -4700,7 +4759,8 @@ } if(query.description != null && query.description.length() > 0) { - sb.append(" DESCRIPTION='").append(query.description).append("'"); + sb.append(" DESCRIPTION='"); + sb.append(toEscapedString(query.description)).append("'"); } if(query.instrumentType != DbSearchQuery.InstrumentType.BOTH) { @@ -4713,21 +4773,22 @@ } if(query.product != null && query.product.length() > 0) { - sb.append(" PRODUCT='").append(query.product).append("'"); + sb.append(" PRODUCT='").append(toEscapedString(query.product)).append("'"); } if(query.artists != null && query.artists.length() > 0) { - sb.append(" ARTISTS='").append(query.artists).append("'"); + sb.append(" ARTISTS='").append(toEscapedString(query.artists)).append("'"); } if(query.keywords != null && query.keywords.length() > 0) { - sb.append(" KEYWORDS='").append(query.keywords).append("'"); + sb.append(" KEYWORDS='"); + sb.append(toEscapedString(query.keywords)).append("'"); } out.writeLine(sb.toString()); if(getPrintOnlyMode()) return null; - String[] instrS = parseStringList(getSingleLineResultSet().getResult()); + String[] instrS = parseEscapedStringList(getSingleLineResultSet().getResult()); DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length]; for(int i = 0; i < instrS.length; i++) { @@ -4758,6 +4819,22 @@ } /** + * Removes all instruments and directories and re-creates + * the instruments database structure. + * @throws IOException If some I/O error occurs. + * @throws LscpException If LSCP protocol corruption occurs. + * @throws LSException If the formatting of the instruments database failed. + */ + public synchronized void + formatInstrumentsDb() throws IOException, LscpException, LSException { + verifyConnection(); + out.writeLine("FORMAT INSTRUMENTS_DB"); + if(getPrintOnlyMode()) return; + + ResultSet rs = getEmptyResultSet(); + } + + /** * Resets the specified sampler channel. * * @param samplerChn The sampler channel number. @@ -4882,6 +4959,86 @@ ResultSet rs = getEmptyResultSet(); } + /** + * Gets the number of instruments in the specified instrument file. + * @param filename The absolute path name of the instrument file. + * @return The number of instruments in the specified instrument file. + * @throws IOException If some I/O error occurs. + * @throws LscpException If LSCP protocol corruption occurs. + * @throws LSException If the file is not found, or other error occur. + */ + public synchronized int + getFileInstrumentCount(String filename) throws IOException, LscpException, LSException { + verifyConnection(); + out.writeLine("GET FILE INSTRUMENTS '" + filename +"'"); + if(getPrintOnlyMode()) return -1; + + String s = getSingleLineResultSet().getResult(); + return parseInt(s); + } + + /** + * Gets information about the instrument with index + * instrIdx in the specified instrument file. + * @param filename The absolute path name of the instrument file. + * @param instrIdx The index of the instrument in the specified instrument file. + * @throws IOException If some I/O error occurs. + * @throws LscpException If LSCP protocol corruption occurs. + * @throws LSException If failed to retrieve information. + */ + public synchronized Instrument + getFileInstrumentInfo(String filename, int instrIdx) + throws IOException, LscpException, LSException { + + verifyConnection(); + out.writeLine("GET FILE INSTRUMENT INFO '" + filename + "' " + String.valueOf(instrIdx)); + if(getPrintOnlyMode()) return null; + + ResultSet rs = getMultiLineResultSet(); + Instrument instr = new FileInstrument(rs.getMultiLineResult()) { }; + + return instr; + } + + /** + * Gets the list of instruments in the specified instrument file. + * @param filename The absolute path name of the instrument file. + * @return An Instrument array providing + * information about all instruments in the specified instrument file. + * @throws IOException If some I/O error occurs. + * @throws LscpException If LSCP protocol corruption occurs. + * @throws LSException If the specified file name is invalid. + */ + public synchronized Instrument[] + getFileInstruments(String filename) throws IOException, LscpException, LSException { + int l = getFileInstrumentCount(filename); + if(l < 0) return null; + Instrument[] instrS = new FileInstrument[l]; + + for(int i = 0; i < instrS.length; i++) { + instrS[i] = getFileInstrumentInfo(filename, i); + } + return instrS; + } + + private static class FileInstrument extends AbstractInstrument { + FileInstrument(String[] resultSet) throws LscpException { + super(resultSet); + } + + public String + getEngine() { + // TODO: engine lookup? + return getFormatFamily(); + } + + public boolean + parse(String s) throws LscpException { + if(s.startsWith("PRODUCT: ") || s.startsWith("ARTISTS: ")) return true; + return super.parse(s); + } + } + private void getEmptyResultSets(int count, String err) throws LSException { StringBuffer sb = new StringBuffer();