mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 06:51:54 +00:00
Add an 'audio.coreaudio.channel-map' setting to enable multi-channel output routing for CoreAudio.
This commit is contained in:
parent
49a3b410f0
commit
326d90e952
2 changed files with 99 additions and 1 deletions
|
@ -452,6 +452,27 @@ Developers:
|
||||||
Selects the CoreAudio device to use.
|
Selects the CoreAudio device to use.
|
||||||
</desc>
|
</desc>
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting>
|
||||||
|
<name>coreaudio.channel-map</name>
|
||||||
|
<type>str</type>
|
||||||
|
<def>0,1</def>
|
||||||
|
<desc>
|
||||||
|
This setting is a comma-separated integer list that maps CoreAudio channels
|
||||||
|
to output device channels. The value of each position in the list, up to the number of
|
||||||
|
output channels available on your device, is the zero-based index of the fluidsynth
|
||||||
|
output channel to route there. Additionally, the special value of -1 will turn off
|
||||||
|
an output.
|
||||||
|
|
||||||
|
For example, the default map for a single stereo output is "0,1". A value of "0,0" will
|
||||||
|
copy the left channel to the right, a value of "1,0" will flip left and right, and a
|
||||||
|
value of "-1,1" will play only the right channel.
|
||||||
|
|
||||||
|
With a six channel output device, and the synth.audio-channels and synth.audio-groups
|
||||||
|
settings both set to "2", a channel map of "-1,-1,0,1,2,3" will result in notes from odd
|
||||||
|
MIDI channels being sent to outputs 3 and 4, and even MIDI channels being send to
|
||||||
|
outputs 5 and 6.
|
||||||
|
</desc>
|
||||||
|
</setting>
|
||||||
<setting>
|
<setting>
|
||||||
<name>dart.device</name>
|
<name>dart.device</name>
|
||||||
<type>str</type>
|
<type>str</type>
|
||||||
|
|
|
@ -114,6 +114,75 @@ get_num_outputs(AudioDeviceID deviceID)
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_channel_map(AudioUnit outputUnit, int audio_channels, const char *map_string)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
long int number_of_channels;
|
||||||
|
int i, *channel_map;
|
||||||
|
UInt32 property_size;
|
||||||
|
Boolean writable = false;
|
||||||
|
|
||||||
|
status = AudioUnitGetPropertyInfo(outputUnit,
|
||||||
|
kAudioOutputUnitProperty_ChannelMap,
|
||||||
|
kAudioUnitScope_Output,
|
||||||
|
0,
|
||||||
|
&property_size, &writable);
|
||||||
|
if(status != noErr)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to get the channel map size. Status=%ld\n", (long int) status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
number_of_channels = property_size / sizeof(int);
|
||||||
|
if(!number_of_channels)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_map = FLUID_ARRAY(int, number_of_channels);
|
||||||
|
if(channel_map == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLUID_MEMSET(channel_map, 0, property_size);
|
||||||
|
|
||||||
|
status = AudioUnitGetProperty(outputUnit,
|
||||||
|
kAudioOutputUnitProperty_ChannelMap,
|
||||||
|
kAudioUnitScope_Output,
|
||||||
|
0,
|
||||||
|
channel_map, &property_size);
|
||||||
|
if(status != noErr)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to get the existing channel map. Status=%ld\n", (long int) status);
|
||||||
|
FLUID_FREE(channel_map);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fluid_settings_split_csv(map_string, channel_map, (int) number_of_channels);
|
||||||
|
for(i = 0; i < number_of_channels; i++)
|
||||||
|
{
|
||||||
|
if(channel_map[i] < -1 || channel_map[i] >= audio_channels)
|
||||||
|
{
|
||||||
|
channel_map[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = AudioUnitSetProperty(outputUnit,
|
||||||
|
kAudioOutputUnitProperty_ChannelMap,
|
||||||
|
kAudioUnitScope_Output,
|
||||||
|
0,
|
||||||
|
channel_map, property_size);
|
||||||
|
if(status != noErr)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to set the channel map. Status=%ld\n", (long int) status);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLUID_FREE(channel_map);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fluid_core_audio_driver_settings(fluid_settings_t *settings)
|
fluid_core_audio_driver_settings(fluid_settings_t *settings)
|
||||||
{
|
{
|
||||||
|
@ -125,6 +194,7 @@ fluid_core_audio_driver_settings(fluid_settings_t *settings)
|
||||||
pa.mElement = kAudioObjectPropertyElementMain;
|
pa.mElement = kAudioObjectPropertyElementMain;
|
||||||
|
|
||||||
fluid_settings_register_str(settings, "audio.coreaudio.device", "default", 0);
|
fluid_settings_register_str(settings, "audio.coreaudio.device", "default", 0);
|
||||||
|
fluid_settings_register_str(settings, "audio.coreaudio.channel-map", "", 0);
|
||||||
fluid_settings_add_option(settings, "audio.coreaudio.device", "default");
|
fluid_settings_add_option(settings, "audio.coreaudio.device", "default");
|
||||||
|
|
||||||
if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
|
if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
|
||||||
|
@ -169,7 +239,7 @@ new_fluid_core_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
|
||||||
fluid_audio_driver_t *
|
fluid_audio_driver_t *
|
||||||
new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
|
new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
|
||||||
{
|
{
|
||||||
char *devname = NULL;
|
char *devname = NULL, *channel_map = NULL;
|
||||||
fluid_core_audio_driver_t *dev = NULL;
|
fluid_core_audio_driver_t *dev = NULL;
|
||||||
int period_size, periods, audio_channels = 1;
|
int period_size, periods, audio_channels = 1;
|
||||||
double sample_rate;
|
double sample_rate;
|
||||||
|
@ -335,6 +405,13 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
|
||||||
goto error_recovery;
|
goto error_recovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(fluid_settings_dupstr(settings, "audio.coreaudio.channel-map", &channel_map) == FLUID_OK /* alloc channel map */
|
||||||
|
&& channel_map && strlen(channel_map) > 0)
|
||||||
|
{
|
||||||
|
set_channel_map(dev->outputUnit, audio_channels, channel_map);
|
||||||
|
}
|
||||||
|
FLUID_FREE(channel_map); /* free channel map */
|
||||||
|
|
||||||
status = AudioUnitSetProperty(dev->outputUnit,
|
status = AudioUnitSetProperty(dev->outputUnit,
|
||||||
kAudioUnitProperty_MaximumFramesPerSlice,
|
kAudioUnitProperty_MaximumFramesPerSlice,
|
||||||
kAudioUnitScope_Input,
|
kAudioUnitScope_Input,
|
||||||
|
|
Loading…
Reference in a new issue