--- liblscp/trunk/src/client.c 2006/12/17 20:29:45 978 +++ liblscp/trunk/src/client.c 2008/02/15 17:04:34 1692 @@ -2,7 +2,7 @@ // /**************************************************************************** liblscp - LinuxSampler Control Protocol API - Copyright (C) 2004-2006, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2004-2008, rncbc aka Rui Nuno Capela. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -84,27 +84,30 @@ if (cchBuffer > 0) { // Make sure received buffer it's null terminated. achBuffer[cchBuffer] = (char) 0; - // Parse for the notification event message... - pszToken = lscp_strtok(achBuffer, pszSeps, &(pch)); // Have "NOTIFY". - if (strcasecmp(pszToken, "NOTIFY") == 0) { - pszToken = lscp_strtok(NULL, pszSeps, &(pch)); - event = lscp_event_from_text(pszToken); - // And pick the rest of data... - pszToken = lscp_strtok(NULL, pszSeps, &(pch)); - cchToken = (pszToken == NULL ? 0 : strlen(pszToken)); - // Double-check if we're really up to it... - if (pClient->events & event) { - // Invoke the client event callback... - if ((*pClient->pfnCallback)( - pClient, - event, - pszToken, - cchToken, - pClient->pvData) != LSCP_OK) { - pClient->evt.iState = 0; + pch = achBuffer; + do { + // Parse for the notification event message... + pszToken = lscp_strtok(NULL, pszSeps, &(pch)); // Have "NOTIFY" + if (strcasecmp(pszToken, "NOTIFY") == 0) { + pszToken = lscp_strtok(NULL, pszSeps, &(pch)); + event = lscp_event_from_text(pszToken); + // And pick the rest of data... + pszToken = lscp_strtok(NULL, pszSeps, &(pch)); + cchToken = (pszToken == NULL ? 0 : strlen(pszToken)); + // Double-check if we're really up to it... + if (pClient->events & event) { + // Invoke the client event callback... + if ((*pClient->pfnCallback)( + pClient, + event, + pszToken, + cchToken, + pClient->pvData) != LSCP_OK) { + pClient->evt.iState = 0; + } } } - } + } while (*pch); } else { lscp_socket_perror("_lscp_client_evt_proc: recv"); pClient->evt.iState = 0; @@ -327,6 +330,7 @@ pClient->midi_devices = NULL; pClient->engines = NULL; pClient->channels = NULL; + pClient->fxsends = NULL; pClient->midi_instruments = NULL; pClient->midi_maps = NULL; pClient->midi_map_name = NULL; @@ -343,6 +347,7 @@ lscp_server_info_init(&(pClient->server_info)); lscp_engine_info_init(&(pClient->engine_info)); lscp_channel_info_init(&(pClient->channel_info)); + lscp_fxsend_info_init(&(pClient->fxsend_info)); lscp_midi_instrument_info_init(&(pClient->midi_instrument_info)); // Initialize error stuff. pClient->pszResult = NULL; @@ -405,6 +410,7 @@ // Free up all cached members. lscp_midi_instrument_info_free(&(pClient->midi_instrument_info)); + lscp_fxsend_info_free(&(pClient->fxsend_info)); lscp_channel_info_free(&(pClient->channel_info)); lscp_engine_info_free(&(pClient->engine_info)); lscp_server_info_free(&(pClient->server_info)); @@ -425,6 +431,7 @@ lscp_isplit_destroy(pClient->midi_devices); lscp_szsplit_destroy(pClient->engines); lscp_isplit_destroy(pClient->channels); + lscp_isplit_destroy(pClient->fxsends); lscp_midi_instruments_destroy(pClient->midi_instruments); lscp_isplit_destroy(pClient->midi_maps); if (pClient->midi_map_name) @@ -436,6 +443,7 @@ pClient->midi_devices = NULL; pClient->engines = NULL; pClient->channels = NULL; + pClient->fxsends = NULL; pClient->midi_instruments = NULL; pClient->midi_maps = NULL; pClient->midi_map_name = NULL; @@ -573,9 +581,27 @@ // Client registration protocol functions. /** - * Register frontend for receiving event messages: - * SUBSCRIBE CHANNEL_COUNT | VOICE_COUNT | STREAM_COUNT | BUFFER_FILL - * | CHANNEL_INFO | MISCELLANEOUS + * Register frontend for receiving event messages. + * @e Caution: since liblscp v0.5.5.4 you have to call lscp_client_subscribe() + * for @e each event you want to subscribe. That is the old bitflag approach + * was abondoned at this point. You can however still register all older + * events with one lscp_client_subscribe() call at once. Thus, the old + * behavior of this functions was not broken. Those older events are namely: + * @code + * SUBSCRIBE CHANNEL_COUNT | VOICE_COUNT | STREAM_COUNT + * | BUFFER_FILL | CHANNEL_INFO | TOTAL_VOICE_COUNT + * | AUDIO_OUTPUT_DEVICE_COUNT | AUDIO_OUTPUT_DEVICE_INFO + * | MIDI_INPUT_DEVICE_COUNT | MIDI_INPUT_DEVICE_INFO + * | MIDI_INSTRUMENT_MAP_COUNT | MIDI_INSTRUMENT_MAP_INFO + * | MIDI_INSTRUMENT_COUNT | MIDI_INSTRUMENT_INFO + * | MISCELLANEOUS + * @endcode + * The old events occupy the lower 16 bits (as bit flags), and all younger + * events enumerate the whole upper 16 bits range. The new, enumerated + * events are namely: + * @code + * SUBSCRIBE CHANNEL_MIDI + * @endcode * * @param pClient Pointer to client instance structure. * @param events Bit-wise OR'ed event flags to subscribe. @@ -584,7 +610,7 @@ */ lscp_status_t lscp_client_subscribe ( lscp_client_t *pClient, lscp_event_t events ) { - lscp_status_t ret = LSCP_FAILED; + lscp_status_t ret = LSCP_OK; if (pClient == NULL) return LSCP_FAILED; @@ -607,8 +633,29 @@ ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_BUFFER_FILL); if (ret == LSCP_OK && (events & LSCP_EVENT_CHANNEL_INFO)) ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_CHANNEL_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_TOTAL_VOICE_COUNT)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_TOTAL_VOICE_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INPUT_DEVICE_INFO)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_MAP_COUNT)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MIDI_INSTRUMENT_MAP_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_MAP_INFO)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MIDI_INSTRUMENT_MAP_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_COUNT)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MIDI_INSTRUMENT_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_INFO)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MIDI_INSTRUMENT_INFO); if (ret == LSCP_OK && (events & LSCP_EVENT_MISCELLANEOUS)) ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_MISCELLANEOUS); + // Caution: for the upper 16 bits, we don't use bit flags anymore ... + if (ret == LSCP_OK && ((events & 0xffff0000) == LSCP_EVENT_CHANNEL_MIDI)) + ret = _lscp_client_evt_request(pClient, 1, LSCP_EVENT_CHANNEL_MIDI); // Unlock this section down. lscp_mutex_unlock(pClient->mutex); @@ -619,8 +666,27 @@ /** * Deregister frontend from receiving UDP event messages anymore: - * SUBSCRIBE CHANNEL_COUNT | VOICE_COUNT | STREAM_COUNT | BUFFER_FILL - * | CHANNEL_INFO | MISCELLANEOUS + * @e Caution: since liblscp v0.5.5.4 you have to call + * lscp_client_unsubscribe() for @e each event you want to unsubscribe. + * That is the old bitflag approach was abondoned at this point. You can + * however still register all older events with one lscp_client_subscribe() + * call at once. Thus, the old behavior of this functions was not broken. + * Those older events are namely: + * @code + * UNSUBSCRIBE CHANNEL_COUNT | VOICE_COUNT | STREAM_COUNT + * | BUFFER_FILL | CHANNEL_INFO | TOTAL_VOICE_COUNT + * | AUDIO_OUTPUT_DEVICE_COUNT | AUDIO_OUTPUT_DEVICE_INFO + * | MIDI_INPUT_DEVICE_COUNT | MIDI_INPUT_DEVICE_INFO + * | MIDI_INSTRUMENT_MAP_COUNT | MIDI_INSTRUMENT_MAP_INFO + * | MIDI_INSTRUMENT_COUNT | MIDI_INSTRUMENT_INFO + * | MISCELLANEOUS + * @endcode + * The old events occupy the lower 16 bits (as bit flags), and all younger + * events enumerate the whole upper 16 bits range. The new, enumerated + * events are namely: + * @code + * UNSUBSCRIBE CHANNEL_MIDI + * @endcode * * @param pClient Pointer to client instance structure. * @param events Bit-wise OR'ed event flags to unsubscribe. @@ -648,8 +714,29 @@ ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_BUFFER_FILL); if (ret == LSCP_OK && (events & LSCP_EVENT_CHANNEL_INFO)) ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_CHANNEL_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_TOTAL_VOICE_COUNT)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_TOTAL_VOICE_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INPUT_DEVICE_INFO)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_MAP_COUNT)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MIDI_INSTRUMENT_MAP_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_MAP_INFO)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MIDI_INSTRUMENT_MAP_INFO); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_COUNT)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MIDI_INSTRUMENT_COUNT); + if (ret == LSCP_OK && (events & LSCP_EVENT_MIDI_INSTRUMENT_INFO)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MIDI_INSTRUMENT_INFO); if (ret == LSCP_OK && (events & LSCP_EVENT_MISCELLANEOUS)) ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_MISCELLANEOUS); + // Caution: for the upper 16 bits, we don't use bit flags anymore ... + if (ret == LSCP_OK && ((events & 0xffff0000) == LSCP_EVENT_CHANNEL_MIDI)) + ret = _lscp_client_evt_request(pClient, 0, LSCP_EVENT_CHANNEL_MIDI); // If necessary, close the alternate connection... if (pClient->events == LSCP_EVENT_NONE) @@ -1038,8 +1125,8 @@ pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); if (pszToken) { if (pChannelInfo->audio_routing) - lscp_szsplit_destroy(pChannelInfo->audio_routing); - pChannelInfo->audio_routing = lscp_szsplit_create(pszToken, ","); + lscp_isplit_destroy(pChannelInfo->audio_routing); + pChannelInfo->audio_routing = lscp_isplit_create(pszToken, ","); } } else if (strcasecmp(pszToken, "INSTRUMENT_FILE") == 0) { @@ -1530,7 +1617,7 @@ { char szQuery[LSCP_BUFSIZ]; - if (iSamplerChannel < 0 || fVolume < 0.0) + if (iSamplerChannel < 0 || fVolume < 0.0f) return LSCP_FAILED; sprintf(szQuery, "SET CHANNEL VOLUME %d %g\r\n", iSamplerChannel, fVolume); @@ -1617,6 +1704,7 @@ */ lscp_status_t lscp_reset_sampler ( lscp_client_t *pClient ) { + // Do actual whole sampler reset... return lscp_client_query(pClient, "RESET\r\n"); } @@ -1738,6 +1826,364 @@ /** + * Get global volume attenuation: + * GET VOLUME + * + * @param pClient Pointer to client instance structure. + * + * @returns The global volume as positive floating point value usually in + * the range between 0.0 and 1.0; in case of failure 0.0 is returned. + */ +float lscp_get_volume ( lscp_client_t *pClient ) +{ + float fVolume = 0.0f; + + if (pClient == NULL) + return 0.0f; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + if (lscp_client_call(pClient, "GET VOLUME\r\n", 0) == LSCP_OK) + fVolume = (float) atof(lscp_client_get_result(pClient)); + + // Unlock this section down. + lscp_mutex_unlock(pClient->mutex); + + return fVolume; +} + + +/** + * Setting global volume attenuation: + * SET VOLUME + * + * @param pClient Pointer to client instance structure. + * @param fVolume Global volume parameter as positive floating point + * value usually be in the range between 0.0 and 1.0, + * that is for attenuating the overall volume. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_volume ( lscp_client_t *pClient, float fVolume ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (fVolume < 0.0f) + return LSCP_FAILED; + + sprintf(szQuery, "SET VOLUME %g\r\n", fVolume); + return lscp_client_query(pClient, szQuery); +} + + +/** + * Add an effect send to a sampler channel: + * CREATE FX_SEND [] + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iMidiController MIDI controller used to alter the effect, + * usually a number between 0 and 127. + * @param pszName Optional name for the effect send entity, + * does not have to be unique. + * + * @returns The new effect send number identifier, or -1 in case of failure. + */ +int lscp_create_fxsend ( lscp_client_t *pClient, int iSamplerChannel, int iMidiController, const char *pszFxName ) +{ + int iFxSend = -1; + char szQuery[LSCP_BUFSIZ]; + + if (pClient == NULL) + return -1; + if (iSamplerChannel < 0 || iMidiController < 0 || iMidiController > 127) + return -1; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + sprintf(szQuery, "CREATE FX_SEND %d %d", iSamplerChannel, iMidiController); + + if (pszFxName) + sprintf(szQuery + strlen(szQuery), " '%s'", pszFxName); + + strcat(szQuery, "\r\n"); + + if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) + iFxSend = atoi(lscp_client_get_result(pClient)); + + // Unlock this section down. + lscp_mutex_unlock(pClient->mutex); + + return iFxSend; +} + + +/** + * Remove an effect send from a sampler channel: + * DESTROY FX_SEND + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iFxSend Effect send number. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_destroy_fxsend ( lscp_client_t *pClient, int iSamplerChannel, int iFxSend ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iSamplerChannel < 0 || iFxSend < 0) + return LSCP_FAILED; + + sprintf(szQuery, "DESTROY FX_SEND %d %d\r\n", iSamplerChannel, iFxSend); + + return lscp_client_query(pClient, szQuery); +} + + +/** + * Get amount of effect sends on a sampler channel: + * GET FX_SENDS + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * + * @returns The current total number of effect sends of the sampler channel + * on success, -1 otherwise. + */ +int lscp_get_fxsends ( lscp_client_t *pClient, int iSamplerChannel ) +{ + int iFxSends = -1; + char szQuery[LSCP_BUFSIZ]; + + if (pClient == NULL) + return -1; + if (iSamplerChannel < 0) + return -1; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + sprintf(szQuery, "GET FX_SENDS %d\r\n", iSamplerChannel); + + if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) + iFxSends = atoi(lscp_client_get_result(pClient)); + + // Unlock this section doen. + lscp_mutex_unlock(pClient->mutex); + + return iFxSends; +} + + +/** + * List all effect sends on a sampler channel: + * LIST FX_SENDS + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * + * @returns An array of the effect sends identifiers as positive integers, + * terminated with -1 on success, NULL otherwise. + */ +int *lscp_list_fxsends ( lscp_client_t *pClient, int iSamplerChannel ) +{ + const char *pszSeps = ","; + char szQuery[LSCP_BUFSIZ]; + + if (pClient == NULL) + return NULL; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + if (pClient->fxsends) { + lscp_isplit_destroy(pClient->fxsends); + pClient->fxsends = NULL; + } + + sprintf(szQuery, "LIST FX_SENDS %d\r\n", iSamplerChannel); + + if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) + pClient->fxsends = lscp_isplit_create(lscp_client_get_result(pClient), pszSeps); + + // Unlock this section down. + lscp_mutex_unlock(pClient->mutex); + + return pClient->fxsends; +} + + +/** + * Getting effect send information + * GET FX_SEND INFO + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iFxSend Effect send number. + * + * @returns A pointer to a @ref lscp_fxsend_info_t structure, with the + * information of the given FX send, or NULL in case of failure. + */ +lscp_fxsend_info_t *lscp_get_fxsend_info ( lscp_client_t *pClient, int iSamplerChannel, int iFxSend ) +{ + lscp_fxsend_info_t *pFxSendInfo; + char szQuery[LSCP_BUFSIZ]; + const char *pszResult; + const char *pszSeps = ":"; + const char *pszCrlf = "\r\n"; + char *pszToken; + char *pch; + + if (pClient == NULL) + return NULL; + if (iSamplerChannel < 0 || iFxSend < 0) + return NULL; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + pFxSendInfo = &(pClient->fxsend_info); + lscp_fxsend_info_reset(pFxSendInfo); + + sprintf(szQuery, "GET FX_SEND INFO %d %d\r\n", iSamplerChannel, iFxSend); + if (lscp_client_call(pClient, szQuery, 1) == LSCP_OK) { + pszResult = lscp_client_get_result(pClient); + pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch)); + while (pszToken) { + if (strcasecmp(pszToken, "NAME") == 0) { + pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); + if (pszToken) + lscp_unquote_dup(&(pFxSendInfo->name), &pszToken); + } + else if (strcasecmp(pszToken, "MIDI_CONTROLLER") == 0) { + pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); + if (pszToken) + pFxSendInfo->midi_controller = atoi(lscp_ltrim(pszToken)); + } + else if (strcasecmp(pszToken, "AUDIO_OUTPUT_ROUTING") == 0) { + pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); + if (pszToken) { + if (pFxSendInfo->audio_routing) + lscp_isplit_destroy(pFxSendInfo->audio_routing); + pFxSendInfo->audio_routing = lscp_isplit_create(pszToken, ","); + } + } + else if (strcasecmp(pszToken, "LEVEL") == 0) { + pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); + if (pszToken) + pFxSendInfo->level = (float) atof(lscp_ltrim(pszToken)); + } + pszToken = lscp_strtok(NULL, pszSeps, &(pch)); + } + } + else pFxSendInfo = NULL; + + // Unlock this section up. + lscp_mutex_unlock(pClient->mutex); + + return pFxSendInfo; +} + +/** + * Alter effect send's name: + * @code + * SET FX_SEND NAME + * @endcode + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iFxSend Effect send number. + * @param pszFxName Effect send's new name. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_fxsend_name ( lscp_client_t *pClient, int iSamplerChannel, int iFxSend, const char *pszFxName ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (!pClient || iSamplerChannel < 0 || iFxSend < 0 || !pszFxName) + return LSCP_FAILED; + + snprintf(szQuery, LSCP_BUFSIZ, "SET FX_SEND NAME %d %d '%s'\r\n", iSamplerChannel, iFxSend, pszFxName); + return lscp_client_query(pClient, szQuery); +} + +/** + * Alter effect send's audio routing: + * SET FX_SEND AUDIO_OUTPUT_CHANNEL + * + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iFxSend Effect send number. + * @param iAudioSrc Audio output device channel to be routed from. + * @param iAudioDst Audio output device channel to be routed into. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_fxsend_audio_channel ( lscp_client_t *pClient, int iSamplerChannel, int iFxSend, int iAudioSrc, int iAudioDst ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iSamplerChannel < 0 || iFxSend < 0 || iAudioSrc < 0 || iAudioDst < 0) + return LSCP_FAILED; + + sprintf(szQuery, "SET FX_SEND AUDIO_OUTPUT_CHANNEL %d %d %d %d\r\n", iSamplerChannel, iFxSend, iAudioSrc, iAudioDst); + return lscp_client_query(pClient, szQuery); +} + + +/** + * Alter effect send's MIDI controller: + * SET FX_SEND MIDI_CONTROLLER + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iFxSend Effect send number. + * @param iMidiController MIDI controller used to alter the effect, + * usually a number between 0 and 127. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_fxsend_midi_controller ( lscp_client_t *pClient, int iSamplerChannel, int iFxSend, int iMidiController ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iSamplerChannel < 0 || iFxSend < 0 || iMidiController < 0 || iMidiController > 127) + return LSCP_FAILED; + + sprintf(szQuery, "SET FX_SEND MIDI_CONTROLLER %d %d %d\r\n", iSamplerChannel, iFxSend, iMidiController); + return lscp_client_query(pClient, szQuery); +} + + +/** + * Alter effect send's audio level: + * SET FX_SEND LEVEL + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iFxSend Effect send number. + * @param fLevel Effect send volume level. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_fxsend_level ( lscp_client_t *pClient, int iSamplerChannel, int iFxSend, float fLevel ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iSamplerChannel < 0 || iFxSend < 0 || fLevel < 0.0f) + return LSCP_FAILED; + + sprintf(szQuery, "SET FX_SEND LEVEL %d %d %f\r\n", iSamplerChannel, iFxSend, fLevel); + return lscp_client_query(pClient, szQuery); +} + + +/** * Create a new MIDI instrument map: * ADD MIDI_INSTRUMENT_MAP [] * @@ -1892,7 +2338,7 @@ } sprintf(szQuery, "GET MIDI_INSTRUMENT_MAP INFO %d\r\n", iMidiMap); - if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) { + if (lscp_client_call(pClient, szQuery, 1) == LSCP_OK) { pszResult = lscp_client_get_result(pClient); pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch)); while (pszToken) { @@ -2240,6 +2686,28 @@ return lscp_client_query(pClient, szQuery); } + +/** + * Open an instrument editor application for the instrument + * on the given sampler channel: + * EDIT CHANNEL INSTRUMENT + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler Channel. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_edit_channel_instrument ( lscp_client_t *pClient, int iSamplerChannel ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iSamplerChannel < 0) + return LSCP_FAILED; + + sprintf(szQuery, "EDIT CHANNEL INSTRUMENT %d\r\n", iSamplerChannel); + + return lscp_client_query(pClient, szQuery); +} // end of client.c