--- liblscp/trunk/src/client.c 2006/12/03 18:30:04 963 +++ liblscp/trunk/src/client.c 2007/01/11 12:33:05 1019 @@ -2,7 +2,7 @@ // /**************************************************************************** liblscp - LinuxSampler Control Protocol API - Copyright (C) 2004-2006, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2004-2007, 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 @@ -327,7 +327,10 @@ 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; lscp_driver_info_init(&(pClient->audio_driver_info)); lscp_driver_info_init(&(pClient->midi_driver_info)); lscp_device_info_init(&(pClient->audio_device_info)); @@ -341,6 +344,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; @@ -403,6 +407,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)); @@ -423,7 +428,11 @@ 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) + free(pClient->midi_map_name); // Make them null. pClient->audio_drivers = NULL; pClient->midi_drivers = NULL; @@ -431,7 +440,10 @@ 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; // Free result error stuff. lscp_client_set_result(pClient, NULL, 0); // Free stream usage stuff. @@ -512,6 +524,9 @@ { lscp_status_t ret; + if (pClient == NULL) + return LSCP_FAILED; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -564,8 +579,13 @@ /** * Register frontend for receiving event messages: - * SUBSCRIBE CHANNEL_COUNT | VOICE_COUNT | STREAM_COUNT | BUFFER_FILL - * | CHANNEL_INFO | MISCELLANEOUS + * 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 * * @param pClient Pointer to client instance structure. * @param events Bit-wise OR'ed event flags to subscribe. @@ -597,6 +617,24 @@ 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); @@ -609,8 +647,13 @@ /** * Deregister frontend from receiving UDP event messages anymore: - * SUBSCRIBE CHANNEL_COUNT | VOICE_COUNT | STREAM_COUNT | BUFFER_FILL - * | CHANNEL_INFO | MISCELLANEOUS + * 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 * * @param pClient Pointer to client instance structure. * @param events Bit-wise OR'ed event flags to unsubscribe. @@ -638,6 +681,24 @@ 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); @@ -752,6 +813,9 @@ { int iChannels = -1; + if (pClient == NULL) + return -1; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -812,6 +876,9 @@ { int iSamplerChannel = -1; + if (pClient == NULL) + return -1; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -859,6 +926,9 @@ { int iAvailableEngines = -1; + if (pClient == NULL) + return -1; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -885,6 +955,9 @@ { const char *pszSeps = ","; + if (pClient == NULL) + return NULL; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -923,6 +996,8 @@ char *pszToken; char *pch; + if (pClient == NULL) + return NULL; if (pszEngineName == NULL) return NULL; @@ -979,6 +1054,8 @@ char *pszToken; char *pch; + if (pClient == NULL) + return NULL; if (iSamplerChannel < 0) return NULL; @@ -1056,6 +1133,19 @@ pChannelInfo->midi_channel = atoi(pszToken); } } + else if (strcasecmp(pszToken, "MIDI_INSTRUMENT_MAP") == 0) { + pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); + if (pszToken) { + pszToken = lscp_ltrim(pszToken); + if (strcasecmp(pszToken, "NONE") == 0) + pChannelInfo->midi_map = LSCP_MIDI_MAP_NONE; + else + if (strcasecmp(pszToken, "DEFAULT") == 0) + pChannelInfo->midi_map = LSCP_MIDI_MAP_DEFAULT; + else + pChannelInfo->midi_map = atoi(pszToken); + } + } else if (strcasecmp(pszToken, "VOLUME") == 0) { pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); if (pszToken) @@ -1097,8 +1187,10 @@ char szQuery[LSCP_BUFSIZ]; int iVoiceCount = -1; + if (pClient == NULL) + return -1; if (iSamplerChannel < 0) - return iVoiceCount; + return -1; // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -1128,8 +1220,10 @@ char szQuery[LSCP_BUFSIZ]; int iStreamCount = -1; + if (pClient == NULL) + return -1; if (iSamplerChannel < 0) - return iStreamCount; + return -1; // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -1165,8 +1259,10 @@ int iStream; int iPercent; + if (pClient == NULL) + return -1; if (iSamplerChannel < 0) - return iStreamUsage; + return -1; // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -1227,7 +1323,7 @@ // Retrieve a channel stream estimation. iStreamCount = lscp_get_channel_stream_count(pClient, iSamplerChannel); - if (pClient->iStreamCount < 0) + if (iStreamCount < 0) return NULL; // Lock this section up. @@ -1416,7 +1512,7 @@ * @param pClient Pointer to client instance structure. * @param iSamplerChannel Sampler channel number. * @param iMidiChannel MIDI channel address number to listen (0-15) or - * LSCP_MIDI_CHANNEL_ALL (16) to listen on all channels. + * @ref LSCP_MIDI_CHANNEL_ALL (16) to listen on all channels. * * @returns LSCP_OK on success, LSCP_FAILED otherwise. */ @@ -1436,6 +1532,40 @@ /** + * Setting MIDI instrument map: + * SET CHANNEL MIDI_INSTRUMENT_MAP + * + * @param pClient Pointer to client instance structure. + * @param iSamplerChannel Sampler channel number. + * @param iMidiMap MIDI instrument map number, or either + * @ref LSCP_MIDI_MAP_NONE or + * @ref LSCP_MIDI_MAP_DEFAULT . + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_channel_midi_map ( lscp_client_t *pClient, int iSamplerChannel, int iMidiMap ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iSamplerChannel < 0) + return LSCP_FAILED; + + sprintf(szQuery, "SET CHANNEL MIDI_INSTRUMENT_MAP %d ", iSamplerChannel); + if (iMidiMap == LSCP_MIDI_MAP_NONE) + strcat(szQuery , "NONE"); + else + if (iMidiMap == LSCP_MIDI_MAP_DEFAULT) + strcat(szQuery , "DEFAULT"); + else + sprintf(szQuery + strlen(szQuery), "%d", iMidiMap); + + strcat(szQuery, "\r\n"); + + return lscp_client_query(pClient, szQuery); +} + + +/** * Setting channel volume: * SET CHANNEL VOLUME * @@ -1451,7 +1581,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); @@ -1538,6 +1668,7 @@ */ lscp_status_t lscp_reset_sampler ( lscp_client_t *pClient ) { + // Do actual whole sampler reset... return lscp_client_query(pClient, "RESET\r\n"); } @@ -1560,6 +1691,9 @@ char *pszToken; char *pch; + if (pClient == NULL) + return NULL; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -1580,6 +1714,11 @@ if (pszToken) lscp_unquote_dup(&(pServerInfo->version), &pszToken); } + else if (strcasecmp(pszToken, "PROTOCOL_VERSION") == 0) { + pszToken = lscp_strtok(NULL, pszCrlf, &(pch)); + if (pszToken) + lscp_unquote_dup(&(pServerInfo->protocol_version), &pszToken); + } pszToken = lscp_strtok(NULL, pszSeps, &(pch)); } } @@ -1605,6 +1744,9 @@ { int iVoiceCount = -1; + if (pClient == NULL) + return -1; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -1631,6 +1773,9 @@ { int iVoiceCount = -1; + if (pClient == NULL) + return -1; + // Lock this section up. lscp_mutex_lock(pClient->mutex); @@ -1645,9 +1790,493 @@ /** + * 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_szsplit_destroy(pFxSendInfo->audio_routing); + pFxSendInfo->audio_routing = lscp_szsplit_create(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 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); +} + + +/** + * Create a new MIDI instrument map: + * ADD MIDI_INSTRUMENT_MAP [] + * + * @param pClient Pointer to client instance structure. + * @param pszMapName MIDI instrument map name (optional) + * + * @returns The new MIDI instrument map number identifier, + * or -1 in case of failure. + */ +int lscp_add_midi_instrument_map ( lscp_client_t *pClient, const char *pszMapName ) +{ + int iMidiMap = -1; + char szQuery[LSCP_BUFSIZ]; + + if (pClient == NULL) + return -1; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + strcpy(szQuery, "ADD MIDI_INSTRUMENT_MAP"); + + if (pszMapName) + sprintf(szQuery + strlen(szQuery), " '%s'", pszMapName); + + strcat(szQuery, "\r\n"); + + if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) + iMidiMap = atoi(lscp_client_get_result(pClient)); + + // Unlock this section down. + lscp_mutex_unlock(pClient->mutex); + + return iMidiMap; +} + + +/** + * Delete one particular or all MIDI instrument maps: + * REMOVE MIDI_INSTRUMENT_MAP + * + * @param pClient Pointer to client instance structure. + * @param iMidiMap MIDI instrument map number. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_remove_midi_instrument_map ( lscp_client_t *pClient, int iMidiMap ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iMidiMap < 0) + return LSCP_FAILED; + + sprintf(szQuery, "REMOVE MIDI_INSTRUMENT_MAP %d\r\n", iMidiMap); + + return lscp_client_query(pClient, szQuery); +} + + +/** + * Get amount of existing MIDI instrument maps: + * GET MIDI_INSTRUMENT_MAPS + * + * @param pClient Pointer to client instance structure. + * + * @returns The current total number of MIDI instrument maps + * on success, -1 otherwise. + */ +int lscp_get_midi_instrument_maps ( lscp_client_t *pClient ) +{ + int iMidiMaps = -1; + + if (pClient == NULL) + return -1; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + if (lscp_client_call(pClient, "GET MIDI_INSTRUMENT_MAPS\r\n", 0) == LSCP_OK) + iMidiMaps = atoi(lscp_client_get_result(pClient)); + + // Unlock this section doen. + lscp_mutex_unlock(pClient->mutex); + + return iMidiMaps; +} + + +/** + * Getting all created MIDI instrument maps: + * LIST MIDI_INSTRUMENT_MAPS + * + * @param pClient Pointer to client instance structure. + * + * @returns An array of the MIDI instrument map identifiers as positive + * integers, terminated with -1 on success, NULL otherwise. + */ +int *lscp_list_midi_instrument_maps ( lscp_client_t *pClient ) +{ + const char *pszSeps = ","; + + if (pClient == NULL) + return NULL; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + if (pClient->midi_maps) { + lscp_isplit_destroy(pClient->midi_maps); + pClient->midi_maps = NULL; + } + + if (lscp_client_call(pClient, "LIST MIDI_INSTRUMENT_MAPS\r\n", 0) == LSCP_OK) + pClient->midi_maps = lscp_isplit_create(lscp_client_get_result(pClient), pszSeps); + + // Unlock this section down. + lscp_mutex_unlock(pClient->mutex); + + return pClient->midi_maps; +} + + +/** + * Getting a MIDI instrument map name: + * GET MIDI_INSTRUMENT_MAP INFO + * + * @param pClient Pointer to client instance structure. + * @param iMidiMap MIDI instrument map number. + * + * @returns The MIDI instrument map name on success, NULL on failure. + */ +const char *lscp_get_midi_instrument_map_name ( lscp_client_t *pClient, int iMidiMap ) +{ + 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 (iMidiMap < 0) + return NULL; + + // Lock this section up. + lscp_mutex_lock(pClient->mutex); + + if (pClient->midi_map_name) { + free(pClient->midi_map_name); + pClient->midi_map_name = NULL; + } + + sprintf(szQuery, "GET MIDI_INSTRUMENT_MAP INFO %d\r\n", iMidiMap); + 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(&(pClient->midi_map_name), &pszToken); + } + pszToken = lscp_strtok(NULL, pszSeps, &(pch)); + } + } + + // Unlock this section down. + lscp_mutex_unlock(pClient->mutex); + + return pClient->midi_map_name; +} + + +/** + * Renaming a MIDI instrument map: + * SET MIDI_INSTRUMENT_MAP NAME + * + * @param pClient Pointer to client instance structure. + * @param iMidiMap MIDI instrument map number. + * @param pszMapName MIDI instrument map name. + * + * @returns LSCP_OK on success, LSCP_FAILED otherwise. + */ +lscp_status_t lscp_set_midi_instrument_map_name ( lscp_client_t *pClient, int iMidiMap, const char *pszMapName ) +{ + char szQuery[LSCP_BUFSIZ]; + + if (iMidiMap < 0) + return LSCP_FAILED; + if (pszMapName == NULL) + return LSCP_FAILED; + + sprintf(szQuery, "SET MIDI_INSTRUMENT_MAP NAME %d '%s'\r\n", + iMidiMap, pszMapName); + + return lscp_client_query(pClient, szQuery); +} + + +/** * Create or replace a MIDI instrumnet map entry: - * MAP MIDI_INSTRUMENT - * [] + * MAP MIDI_INSTRUMENT + * [ []} * * @param pClient Pointer to client instance structure. * @param pMidiInstr MIDI instrument bank and program parameter key. @@ -1663,7 +2292,7 @@ * @ref LSCP_LOAD_ON_DEMAND, or * @ref LSCP_LOAD_ON_DEMAND_HOLD, or * @ref LSCP_LOAD_PERSISTENT. - * @param pszName Instrument custom name for the map entry. + * @param pszName Instrument custom name for the map entry (optional). * * @returns LSCP_OK on success, LSCP_FAILED otherwise. */ @@ -1671,11 +2300,11 @@ { char szQuery[LSCP_BUFSIZ]; - if (pMidiInstr->bank_msb < 0 || pMidiInstr->bank_msb > 127) + if (pMidiInstr->map < 0) return LSCP_FAILED; - if (pMidiInstr->bank_lsb < 0 || pMidiInstr->bank_lsb > 127) + if (pMidiInstr->bank < 0 || pMidiInstr->bank > 16383) return LSCP_FAILED; - if (pMidiInstr->program < 0 || pMidiInstr->program > 127) + if (pMidiInstr->prog < 0 || pMidiInstr->prog > 127) return LSCP_FAILED; if (pszEngineName == NULL || pszFileName == NULL) return LSCP_FAILED; @@ -1684,7 +2313,7 @@ fVolume = 1.0f; sprintf(szQuery, "MAP MIDI_INSTRUMENT %d %d %d %s '%s' %d %g", - pMidiInstr->bank_msb, pMidiInstr->bank_lsb, pMidiInstr->program, + pMidiInstr->map, pMidiInstr->bank, pMidiInstr->prog, pszEngineName, pszFileName, iInstrIndex, fVolume); switch (load_mode) { @@ -1713,7 +2342,7 @@ /** * Remove an entry from the MIDI instrument map: - * UNMAP MIDI_INSTRUMENT + * UNMAP MIDI_INSTRUMENT * * @param pClient Pointer to client instance structure. * @param pMidiInstr MIDI instrument bank and program parameter key. @@ -1724,15 +2353,15 @@ { char szQuery[LSCP_BUFSIZ]; - if (pMidiInstr->bank_msb < 0 || pMidiInstr->bank_msb > 127) + if (pMidiInstr->map < 0) return LSCP_FAILED; - if (pMidiInstr->bank_lsb < 0 || pMidiInstr->bank_lsb > 127) + if (pMidiInstr->bank < 0 || pMidiInstr->bank > 16383) return LSCP_FAILED; - if (pMidiInstr->program < 0 || pMidiInstr->program > 127) + if (pMidiInstr->prog < 0 || pMidiInstr->prog > 127) return LSCP_FAILED; sprintf(szQuery, "UNMAP MIDI_INSTRUMENT %d %d %d\r\n", - pMidiInstr->bank_msb, pMidiInstr->bank_lsb, pMidiInstr->program); + pMidiInstr->map, pMidiInstr->bank, pMidiInstr->prog); return lscp_client_query(pClient, szQuery); } @@ -1740,21 +2369,35 @@ /** * Get the total count of MIDI instrument map entries: - * GET MIDI_INSTRUMENTS + * GET MIDI_INSTRUMENTS ALL| * * @param pClient Pointer to client instance structure. + * @param iMidiMap MIDI instrument map number, or @ref LSCP_MIDI_MAP_ALL . * * @returns The current total number of MIDI instrument map entries * on success, -1 otherwise. */ -int lscp_get_midi_instruments ( lscp_client_t *pClient ) +int lscp_get_midi_instruments ( lscp_client_t *pClient, int iMidiMap ) { int iInstruments = -1; + char szQuery[LSCP_BUFSIZ]; + + if (pClient == NULL) + return -1; // Lock this section up. lscp_mutex_lock(pClient->mutex); - if (lscp_client_call(pClient, "GET MIDI_INSTRUMENTS\r\n", 0) == LSCP_OK) + strcpy(szQuery, "GET MIDI_INSTRUMENTS "); + + if (iMidiMap < 0) + strcat(szQuery, "ALL"); + else + sprintf(szQuery + strlen(szQuery), "%d", iMidiMap); + + strcat(szQuery, "\r\n"); + + if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) iInstruments = atoi(lscp_client_get_result(pClient)); // Unlock this section down. @@ -1766,15 +2409,18 @@ /** * Getting indeces of all MIDI instrument map entries: - * LIST MIDI_INSTRUMENTS + * LIST MIDI_INSTRUMENTS ALL| * * @param pClient Pointer to client instance structure. + * @param iMidiMap MIDI instrument map number, or @ref LSCP_MIDI_MAP_ALL . * * @returns An array of @ref lscp_midi_instrument_t, terminated with the * {-1,-1,-1} triplet, NULL otherwise. */ -lscp_midi_instrument_t *lscp_list_midi_instruments ( lscp_client_t *pClient ) +lscp_midi_instrument_t *lscp_list_midi_instruments ( lscp_client_t *pClient, int iMidiMap ) { + char szQuery[LSCP_BUFSIZ]; + if (pClient == NULL) return NULL; @@ -1786,7 +2432,16 @@ pClient->midi_instruments = NULL; } - if (lscp_client_call(pClient, "LIST MIDI_INSTRUMENTS\r\n", 0) == LSCP_OK) + strcpy(szQuery, "LIST MIDI_INSTRUMENTS "); + + if (iMidiMap < 0) + strcat(szQuery, "ALL"); + else + sprintf(szQuery + strlen(szQuery), "%d", iMidiMap); + + strcat(szQuery, "\r\n"); + + if (lscp_client_call(pClient, szQuery, 0) == LSCP_OK) pClient->midi_instruments = lscp_midi_instruments_create(lscp_client_get_result(pClient)); // Unlock this section down. @@ -1798,7 +2453,7 @@ /** * Getting information about a MIDI instrument map entry: - * GET MIDI_INSTRUMENT INFO + * GET MIDI_INSTRUMENT INFO * * @param pClient Pointer to client instance structure. * @param pMidiInstr MIDI instrument bank and program parameter key. @@ -1817,11 +2472,13 @@ char *pszToken; char *pch; - if (pMidiInstr->bank_msb < 0 || pMidiInstr->bank_msb > 127) + if (pClient == NULL) return NULL; - if (pMidiInstr->bank_lsb < 0 || pMidiInstr->bank_lsb > 127) + if (pMidiInstr->map < 0) return NULL; - if (pMidiInstr->program < 0 || pMidiInstr->program > 127) + if (pMidiInstr->bank < 0 || pMidiInstr->bank > 16383) + return NULL; + if (pMidiInstr->prog < 0 || pMidiInstr->prog > 127) return NULL; // Lock this section up. @@ -1831,7 +2488,7 @@ lscp_midi_instrument_info_reset(pInstrInfo); sprintf(szQuery, "GET MIDI_INSTRUMENT INFO %d %d %d\r\n", - pMidiInstr->bank_msb, pMidiInstr->bank_lsb, pMidiInstr->program); + pMidiInstr->map, pMidiInstr->bank, pMidiInstr->prog); if (lscp_client_call(pClient, szQuery, 1) == LSCP_OK) { pszResult = lscp_client_get_result(pClient); pszToken = lscp_strtok((char *) pszResult, pszSeps, &(pch)); @@ -1896,16 +2553,27 @@ /** * Clear the MIDI instrumnet map: - * CLEAR MIDI_INSTRUMENTS + * CLEAR MIDI_INSTRUMENTS ALL| * - * @param pClient Pointer to client instance structure. - * @param iSamplerChannel Sampler channel number. + * @param pClient Pointer to client instance structure. + * @param iMidiMap MIDI instrument map number, or @ref LSCP_MIDI_MAP_ALL . * * @returns LSCP_OK on success, LSCP_FAILED otherwise. */ -lscp_status_t lscp_clear_midi_instruments ( lscp_client_t *pClient ) +lscp_status_t lscp_clear_midi_instruments ( lscp_client_t *pClient, int iMidiMap ) { - return lscp_client_query(pClient, "CLEAR MIDI_INSTRUMENTS\r\n"); + char szQuery[LSCP_BUFSIZ]; + + strcpy(szQuery, "CLEAR MIDI_INSTRUMENTS "); + + if (iMidiMap < 0) + strcat(szQuery, "ALL"); + else + sprintf(szQuery + strlen(szQuery), "%d", iMidiMap); + + strcat(szQuery, "\r\n"); + + return lscp_client_query(pClient, szQuery); }