2014-02-10 02:10:30 +01:00
/**************************************************************************/
/* audio_server.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "audio_server.h"
2020-02-07 21:01:03 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2020-02-27 03:30:20 +01:00
# include "core/debugger/engine_debugger.h"
2021-08-27 19:28:23 +02:00
# include "core/error/error_macros.h"
2021-06-11 14:51:48 +02:00
# include "core/io/file_access.h"
2018-09-11 18:13:45 +02:00
# include "core/io/resource_loader.h"
2021-08-27 19:28:23 +02:00
# include "core/math/audio_frame.h"
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
2021-08-27 19:28:23 +02:00
# include "core/string/string_name.h"
# include "core/templates/pair.h"
2022-07-23 16:34:36 +02:00
# include "scene/resources/audio_stream_wav.h"
2023-08-07 17:33:07 +02:00
# include "scene/scene_string_names.h"
2017-09-13 18:34:22 +02:00
# include "servers/audio/audio_driver_dummy.h"
2017-01-23 00:39:53 +01:00
# include "servers/audio/effects/audio_effect_compressor.h"
2017-01-25 18:30:40 +01:00
2021-08-27 19:28:23 +02:00
# include <cstring>
2020-02-07 21:01:03 +01:00
# ifdef TOOLS_ENABLED
2017-01-25 18:30:40 +01:00
# define MARK_EDITED set_edited(true);
# else
# define MARK_EDITED
# endif
2017-01-23 00:39:53 +01:00
2020-04-02 01:20:12 +02:00
AudioDriver * AudioDriver : : singleton = nullptr ;
2017-01-15 20:06:14 +01:00
AudioDriver * AudioDriver : : get_singleton ( ) {
return singleton ;
}
void AudioDriver : : set_singleton ( ) {
singleton = this ;
2014-02-10 02:10:30 +01:00
}
2017-01-15 20:06:14 +01:00
void AudioDriver : : audio_server_process ( int p_frames , int32_t * p_buffer , bool p_update_mix_time ) {
2020-05-14 16:41:43 +02:00
if ( p_update_mix_time ) {
2017-01-15 20:06:14 +01:00
update_mix_time ( p_frames ) ;
2020-05-14 16:41:43 +02:00
}
2017-01-21 23:00:25 +01:00
2020-05-14 16:41:43 +02:00
if ( AudioServer : : get_singleton ( ) ) {
2017-01-21 23:00:25 +01:00
AudioServer : : get_singleton ( ) - > _driver_process ( p_frames , p_buffer ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-01-15 20:06:14 +01:00
void AudioDriver : : update_mix_time ( int p_frames ) {
2019-04-27 17:22:47 +02:00
_last_mix_frames = p_frames ;
2020-05-14 16:41:43 +02:00
if ( OS : : get_singleton ( ) ) {
2017-08-01 23:09:52 +02:00
_last_mix_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-01-15 20:06:14 +01:00
}
2014-02-10 02:10:30 +01:00
2021-01-09 02:29:49 +01:00
double AudioDriver : : get_time_since_last_mix ( ) {
lock ( ) ;
uint64_t last_mix_time = _last_mix_time ;
unlock ( ) ;
return ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - last_mix_time ) / 1000000.0 ;
2019-04-27 19:05:16 +02:00
}
2021-01-09 02:29:49 +01:00
double AudioDriver : : get_time_to_next_mix ( ) {
lock ( ) ;
uint64_t last_mix_time = _last_mix_time ;
uint64_t last_mix_frames = _last_mix_frames ;
unlock ( ) ;
double total = ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - last_mix_time ) / 1000000.0 ;
double mix_buffer = last_mix_frames / ( double ) get_mix_rate ( ) ;
2019-04-27 17:22:47 +02:00
return mix_buffer - total ;
2017-01-15 20:06:14 +01:00
}
2020-01-20 13:11:47 +01:00
void AudioDriver : : input_buffer_init ( int driver_buffer_frames ) {
const int input_buffer_channels = 2 ;
input_buffer . resize ( driver_buffer_frames * input_buffer_channels * 4 ) ;
input_position = 0 ;
input_size = 0 ;
2018-10-19 21:32:03 +02:00
}
2020-01-20 13:11:47 +01:00
void AudioDriver : : input_buffer_write ( int32_t sample ) {
if ( ( int ) input_position < input_buffer . size ( ) ) {
input_buffer . write [ input_position + + ] = sample ;
if ( ( int ) input_position > = input_buffer . size ( ) ) {
input_position = 0 ;
2019-03-02 19:01:26 +01:00
}
2020-01-20 13:11:47 +01:00
if ( ( int ) input_size < input_buffer . size ( ) ) {
input_size + + ;
2019-03-02 19:01:26 +01:00
}
} else {
2019-11-07 09:44:15 +01:00
WARN_PRINT ( " input_buffer_write: Invalid input_position= " + itos ( input_position ) + " input_buffer.size()= " + itos ( input_buffer . size ( ) ) ) ;
2018-07-27 20:09:03 +02:00
}
}
2022-12-10 07:39:14 +01:00
int AudioDriver : : _get_configured_mix_rate ( ) {
StringName audio_driver_setting = " audio/driver/mix_rate " ;
int mix_rate = GLOBAL_GET ( audio_driver_setting ) ;
2024-04-18 16:50:34 +02:00
# ifdef WEB_ENABLED
// `0` is an acceptable value (resorts to the browser's default).
return MAX ( 0 , mix_rate ) ;
# else // !WEB_ENABLED
2022-12-10 07:39:14 +01:00
// In the case of invalid mix rate, let's default to a sensible value..
if ( mix_rate < = 0 ) {
WARN_PRINT ( vformat ( " Invalid mix rate of %d, consider reassigning setting \' %s \' . \n Defaulting mix rate to value %d. " ,
mix_rate , audio_driver_setting , AudioDriverManager : : DEFAULT_MIX_RATE ) ) ;
mix_rate = AudioDriverManager : : DEFAULT_MIX_RATE ;
}
return mix_rate ;
2024-04-18 16:50:34 +02:00
# endif
2022-12-10 07:39:14 +01:00
}
2017-08-22 23:27:17 +02:00
AudioDriver : : SpeakerMode AudioDriver : : get_speaker_mode_by_total_channels ( int p_channels ) const {
switch ( p_channels ) {
2020-05-10 13:00:47 +02:00
case 4 :
return SPEAKER_SURROUND_31 ;
case 6 :
return SPEAKER_SURROUND_51 ;
case 8 :
return SPEAKER_SURROUND_71 ;
2017-08-22 23:27:17 +02:00
}
// Default to STEREO
return SPEAKER_MODE_STEREO ;
}
int AudioDriver : : get_total_channels_by_speaker_mode ( AudioDriver : : SpeakerMode p_mode ) const {
switch ( p_mode ) {
2020-05-10 13:00:47 +02:00
case SPEAKER_MODE_STEREO :
return 2 ;
case SPEAKER_SURROUND_31 :
return 4 ;
case SPEAKER_SURROUND_51 :
return 6 ;
case SPEAKER_SURROUND_71 :
return 8 ;
2017-08-22 23:27:17 +02:00
}
ERR_FAIL_V ( 2 ) ;
}
2022-11-24 15:41:40 +01:00
PackedStringArray AudioDriver : : get_output_device_list ( ) {
2022-08-05 03:41:48 +02:00
PackedStringArray list ;
2018-02-27 08:54:56 +01:00
2018-07-04 03:08:43 +02:00
list . push_back ( " Default " ) ;
2018-02-27 08:54:56 +01:00
2018-07-04 03:08:43 +02:00
return list ;
2018-02-27 08:54:56 +01:00
}
2022-11-24 15:41:40 +01:00
String AudioDriver : : get_output_device ( ) {
2018-07-04 03:08:43 +02:00
return " Default " ;
2018-02-27 08:54:56 +01:00
}
2022-11-24 15:41:40 +01:00
PackedStringArray AudioDriver : : get_input_device_list ( ) {
2022-08-05 03:41:48 +02:00
PackedStringArray list ;
2018-03-25 05:43:51 +02:00
list . push_back ( " Default " ) ;
return list ;
}
2024-04-18 16:50:34 +02:00
void AudioDriver : : start_sample_playback ( const Ref < AudioSamplePlayback > & p_playback ) {
if ( p_playback . is_valid ( ) ) {
if ( p_playback - > stream . is_valid ( ) ) {
WARN_PRINT_ED ( vformat ( R " (Trying to play stream (%s) as a sample (%s), but the driver doesn't support sample playback.) " , p_playback - > get_instance_id ( ) , p_playback - > stream - > get_instance_id ( ) ) ) ;
} else {
WARN_PRINT_ED ( vformat ( R " (Trying to play stream (%s) as a null sample, but the driver doesn't support sample playback.) " , p_playback - > get_instance_id ( ) ) ) ;
}
} else {
WARN_PRINT_ED ( " Trying to play a null sample playback from a driver that don't support sample playback. " ) ;
}
}
2017-09-13 18:34:22 +02:00
AudioDriverDummy AudioDriverManager : : dummy_driver ;
2018-08-13 23:11:24 +02:00
AudioDriver * AudioDriverManager : : drivers [ MAX_DRIVERS ] = {
& AudioDriverManager : : dummy_driver ,
} ;
int AudioDriverManager : : driver_count = 1 ;
2017-01-15 20:06:14 +01:00
void AudioDriverManager : : add_driver ( AudioDriver * p_driver ) {
ERR_FAIL_COND ( driver_count > = MAX_DRIVERS ) ;
2018-08-13 23:11:24 +02:00
drivers [ driver_count - 1 ] = p_driver ;
// Last driver is always our dummy driver
drivers [ driver_count + + ] = & AudioDriverManager : : dummy_driver ;
2017-01-15 20:06:14 +01:00
}
int AudioDriverManager : : get_driver_count ( ) {
return driver_count ;
}
2017-09-13 18:34:22 +02:00
void AudioDriverManager : : initialize ( int p_driver ) {
2021-02-17 17:44:49 +01:00
GLOBAL_DEF_RST ( " audio/driver/enable_input " , false ) ;
2023-11-10 16:55:48 +01:00
GLOBAL_DEF_RST ( PropertyInfo ( Variant : : INT , " audio/driver/mix_rate " , PROPERTY_HINT_RANGE , " 11025,192000,1,or_greater,suffix:Hz " ) , DEFAULT_MIX_RATE ) ;
GLOBAL_DEF_RST ( PropertyInfo ( Variant : : INT , " audio/driver/mix_rate.web " , PROPERTY_HINT_RANGE , " 0,192000,1,or_greater,suffix:Hz " ) , 0 ) ; // Safer default output_latency for web (use browser default).
2020-05-18 02:31:38 +02:00
2017-09-13 18:34:22 +02:00
int failed_driver = - 1 ;
// Check if there is a selected driver
if ( p_driver > = 0 & & p_driver < driver_count ) {
if ( drivers [ p_driver ] - > init ( ) = = OK ) {
drivers [ p_driver ] - > set_singleton ( ) ;
return ;
} else {
failed_driver = p_driver ;
}
}
// No selected driver, try them all in order
for ( int i = 0 ; i < driver_count ; i + + ) {
// Don't re-init the driver if it failed above
if ( i = = failed_driver ) {
continue ;
}
if ( drivers [ i ] - > init ( ) = = OK ) {
drivers [ i ] - > set_singleton ( ) ;
2018-08-25 09:46:36 +02:00
break ;
2017-09-13 18:34:22 +02:00
}
}
2018-08-25 09:46:36 +02:00
2018-09-27 13:11:41 +02:00
if ( driver_count > 1 & & String ( AudioDriver : : get_singleton ( ) - > get_name ( ) ) = = " Dummy " ) {
2018-08-25 09:46:36 +02:00
WARN_PRINT ( " All audio drivers failed, falling back to the dummy driver. " ) ;
}
2017-09-13 18:34:22 +02:00
}
2017-01-15 20:06:14 +01:00
AudioDriver * AudioDriverManager : : get_driver ( int p_driver ) {
2020-04-02 01:20:12 +02:00
ERR_FAIL_INDEX_V ( p_driver , driver_count , nullptr ) ;
2017-01-15 20:06:14 +01:00
return drivers [ p_driver ] ;
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
2017-01-21 23:00:25 +01:00
void AudioServer : : _driver_process ( int p_frames , int32_t * p_buffer ) {
2021-08-27 19:28:23 +02:00
mix_count + + ;
2017-01-21 23:00:25 +01:00
int todo = p_frames ;
2018-06-21 02:02:02 +02:00
# ifdef DEBUG_ENABLED
uint64_t prof_ticks = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
# endif
2018-03-18 02:43:32 +01:00
if ( channel_count ! = get_channel_count ( ) ) {
2022-11-24 15:41:40 +01:00
// Amount of channels changed due to a output_device change
2018-03-18 02:43:32 +01:00
// reinitialize the buses channels and buffers
init_channels_and_buffers ( ) ;
}
2021-04-24 17:06:28 +02:00
ERR_FAIL_COND_MSG ( buses . is_empty ( ) & & todo , " AudioServer bus count is less than 1. " ) ;
2017-01-21 23:00:25 +01:00
while ( todo ) {
if ( to_mix = = 0 ) {
_mix_step ( ) ;
}
int to_copy = MIN ( to_mix , todo ) ;
Bus * master = buses [ 0 ] ;
int from = buffer_size - to_mix ;
int from_buf = p_frames - todo ;
//master master, send to output
int cs = master - > channels . size ( ) ;
2024-01-26 10:11:13 +01:00
// Take away 1 from the stride, as we are manually incrementing by 1 for stereo.
uintptr_t stride_minus_one = ( cs * 2 ) - 1 ;
2017-01-21 23:00:25 +01:00
for ( int k = 0 ; k < cs ; k + + ) {
2024-01-26 10:11:13 +01:00
// The destination start for data will be the same in all cases.
int32_t * dest = & p_buffer [ from_buf * ( cs * 2 ) + ( k * 2 ) ] ;
2017-01-21 23:00:25 +01:00
if ( master - > channels [ k ] . active ) {
2017-11-25 04:07:54 +01:00
const AudioFrame * buf = master - > channels [ k ] . buffer . ptr ( ) ;
2017-01-21 23:00:25 +01:00
for ( int j = 0 ; j < to_copy ; j + + ) {
2024-01-09 15:01:12 +01:00
float l = CLAMP ( buf [ from + j ] . left , - 1.0 , 1.0 ) ;
2017-01-21 23:00:25 +01:00
int32_t vl = l * ( ( 1 < < 20 ) - 1 ) ;
2019-03-05 21:32:18 +01:00
int32_t vl2 = ( vl < 0 ? - 1 : 1 ) * ( ABS ( vl ) < < 11 ) ;
2024-01-26 10:11:13 +01:00
* dest = vl2 ;
dest + + ;
2017-01-21 23:00:25 +01:00
2024-01-09 15:01:12 +01:00
float r = CLAMP ( buf [ from + j ] . right , - 1.0 , 1.0 ) ;
2017-01-21 23:00:25 +01:00
int32_t vr = r * ( ( 1 < < 20 ) - 1 ) ;
2019-03-05 21:32:18 +01:00
int32_t vr2 = ( vr < 0 ? - 1 : 1 ) * ( ABS ( vr ) < < 11 ) ;
2024-01-26 10:11:13 +01:00
* dest = vr2 ;
dest + = stride_minus_one ;
2017-01-21 23:00:25 +01:00
}
} else {
2024-01-26 10:11:13 +01:00
// Bizarrely, profiling indicates that detecting the common case of cs == 1,
// k == 0, and using memset is SLOWER than setting them individually.
// Perhaps it gets optimized to a faster instruction than memset.
2017-01-21 23:00:25 +01:00
for ( int j = 0 ; j < to_copy ; j + + ) {
2024-01-26 10:11:13 +01:00
* dest = 0 ;
dest + + ;
* dest = 0 ;
dest + = stride_minus_one ;
2017-01-21 23:00:25 +01:00
}
}
}
todo - = to_copy ;
to_mix - = to_copy ;
}
2018-07-17 03:43:47 +02:00
2018-06-21 02:02:02 +02:00
# ifdef DEBUG_ENABLED
2024-02-06 04:29:44 +01:00
prof_time . add ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - prof_ticks ) ;
2018-06-21 02:02:02 +02:00
# endif
2017-01-21 23:00:25 +01:00
}
void AudioServer : : _mix_step ( ) {
2017-08-18 23:19:12 +02:00
bool solo_mode = false ;
2017-01-21 23:00:25 +01:00
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
Bus * bus = buses [ i ] ;
bus - > index_cache = i ; //might be moved around by editor, so..
for ( int k = 0 ; k < bus - > channels . size ( ) ; k + + ) {
2018-07-25 03:11:03 +02:00
bus - > channels . write [ k ] . used = false ;
2017-01-21 23:00:25 +01:00
}
2017-08-18 23:19:12 +02:00
if ( bus - > solo ) {
//solo chain
solo_mode = true ;
bus - > soloed = true ;
do {
if ( bus ! = buses [ 0 ] ) {
//everything has a send save for master bus
if ( ! bus_map . has ( bus - > send ) ) {
bus = buses [ 0 ] ; //send to master
} else {
2017-09-07 21:48:50 +02:00
int prev_index_cache = bus - > index_cache ;
2017-08-18 23:19:12 +02:00
bus = bus_map [ bus - > send ] ;
2017-09-07 21:48:50 +02:00
if ( prev_index_cache > = bus - > index_cache ) { //invalid, send to master
2017-08-18 23:19:12 +02:00
bus = buses [ 0 ] ;
}
}
bus - > soloed = true ;
} else {
2020-04-02 01:20:12 +02:00
bus = nullptr ;
2017-08-18 23:19:12 +02:00
}
} while ( bus ) ;
} else {
bus - > soloed = false ;
}
2017-01-21 23:00:25 +01:00
}
2021-08-27 19:28:23 +02:00
for ( CallbackItem * ci : mix_callback_list ) {
ci - > callback ( ci - > userdata ) ;
}
for ( AudioStreamPlaybackListNode * playback : playback_list ) {
// Paused streams are no-ops. Don't even mix audio from the stream playback.
if ( playback - > state . load ( ) = = AudioStreamPlaybackListNode : : PAUSED ) {
continue ;
}
2024-04-18 16:50:34 +02:00
if ( playback - > stream_playback - > get_is_sample ( ) ) {
continue ;
}
2021-08-27 19:28:23 +02:00
bool fading_out = playback - > state . load ( ) = = AudioStreamPlaybackListNode : : FADE_OUT_TO_DELETION | | playback - > state . load ( ) = = AudioStreamPlaybackListNode : : FADE_OUT_TO_PAUSE ;
AudioFrame * buf = mix_buffer . ptrw ( ) ;
// Copy the lookeahead buffer into the mix buffer.
for ( int i = 0 ; i < LOOKAHEAD_BUFFER_SIZE ; i + + ) {
buf [ i ] = playback - > lookahead [ i ] ;
}
// Mix the audio stream
unsigned int mixed_frames = playback - > stream_playback - > mix ( & buf [ LOOKAHEAD_BUFFER_SIZE ] , playback - > pitch_scale . get ( ) , buffer_size ) ;
2022-07-21 01:00:58 +02:00
if ( tag_used_audio_streams & & playback - > stream_playback - > is_playing ( ) ) {
playback - > stream_playback - > tag_used_streams ( ) ;
}
2021-08-27 19:28:23 +02:00
if ( mixed_frames ! = buffer_size ) {
// We know we have at least the size of our lookahead buffer for fade-out purposes.
2021-08-28 06:51:03 +02:00
float fadeout_base = 0.94 ;
2021-08-27 19:28:23 +02:00
float fadeout_coefficient = 1 ;
2021-08-28 06:51:03 +02:00
static_assert ( LOOKAHEAD_BUFFER_SIZE = = 64 , " Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE. " ) ;
// 0.94 ^ 64 = 0.01906. There might still be a pop but it'll be way better than if we didn't do this.
2021-08-27 19:28:23 +02:00
for ( unsigned int idx = mixed_frames ; idx < buffer_size ; idx + + ) {
fadeout_coefficient * = fadeout_base ;
buf [ idx ] * = fadeout_coefficient ;
}
AudioStreamPlaybackListNode : : PlaybackState new_state ;
new_state = AudioStreamPlaybackListNode : : AWAITING_DELETION ;
playback - > state . store ( new_state ) ;
} else {
// Move the last little bit of what we just mixed into our lookahead buffer.
for ( int i = 0 ; i < LOOKAHEAD_BUFFER_SIZE ; i + + ) {
playback - > lookahead [ i ] = buf [ buffer_size + i ] ;
}
}
2021-08-28 06:51:03 +02:00
AudioStreamPlaybackBusDetails * ptr = playback - > bus_details . load ( ) ;
2023-09-09 17:04:18 +02:00
ERR_FAIL_NULL ( ptr ) ;
2021-08-27 19:28:23 +02:00
// By putting null into the bus details pointers, we're taking ownership of their memory for the duration of this mix.
2021-08-28 06:51:03 +02:00
AudioStreamPlaybackBusDetails bus_details = * ptr ;
2021-08-27 19:28:23 +02:00
// Mix to any active buses.
for ( int idx = 0 ; idx < MAX_BUSES_PER_PLAYBACK ; idx + + ) {
2021-08-28 06:51:03 +02:00
if ( ! bus_details . bus_active [ idx ] ) {
2021-08-27 19:28:23 +02:00
continue ;
}
2021-08-28 06:51:03 +02:00
int bus_idx = thread_find_bus_index ( bus_details . bus [ idx ] ) ;
2021-08-27 19:28:23 +02:00
int prev_bus_idx = - 1 ;
for ( int search_idx = 0 ; search_idx < MAX_BUSES_PER_PLAYBACK ; search_idx + + ) {
2021-08-28 06:51:03 +02:00
if ( ! playback - > prev_bus_details - > bus_active [ search_idx ] ) {
2021-08-27 19:28:23 +02:00
continue ;
}
2021-08-28 06:51:03 +02:00
if ( playback - > prev_bus_details - > bus [ search_idx ] . hash ( ) = = bus_details . bus [ idx ] . hash ( ) ) {
2021-08-27 19:28:23 +02:00
prev_bus_idx = search_idx ;
}
}
for ( int channel_idx = 0 ; channel_idx < channel_count ; channel_idx + + ) {
AudioFrame * channel_buf = thread_get_channel_mix_buffer ( bus_idx , channel_idx ) ;
if ( fading_out ) {
2021-08-28 06:51:03 +02:00
bus_details . volume [ idx ] [ channel_idx ] = AudioFrame ( 0 , 0 ) ;
2021-08-27 19:28:23 +02:00
}
2021-08-28 06:51:03 +02:00
AudioFrame channel_vol = bus_details . volume [ idx ] [ channel_idx ] ;
2021-08-27 19:28:23 +02:00
AudioFrame prev_channel_vol = AudioFrame ( 0 , 0 ) ;
if ( prev_bus_idx ! = - 1 ) {
2021-08-28 06:51:03 +02:00
prev_channel_vol = playback - > prev_bus_details - > volume [ prev_bus_idx ] [ channel_idx ] ;
2021-08-27 19:28:23 +02:00
}
_mix_step_for_channel ( channel_buf , buf , prev_channel_vol , channel_vol , playback - > attenuation_filter_cutoff_hz . get ( ) , playback - > highshelf_gain . get ( ) , & playback - > filter_process [ channel_idx * 2 ] , & playback - > filter_process [ channel_idx * 2 + 1 ] ) ;
}
}
// Now go through and fade-out any buses that were being played to previously that we missed by going through current data.
for ( int idx = 0 ; idx < MAX_BUSES_PER_PLAYBACK ; idx + + ) {
2021-08-28 06:51:03 +02:00
if ( ! playback - > prev_bus_details - > bus_active [ idx ] ) {
2021-08-27 19:28:23 +02:00
continue ;
}
2021-08-28 06:51:03 +02:00
int bus_idx = thread_find_bus_index ( playback - > prev_bus_details - > bus [ idx ] ) ;
2021-08-27 19:28:23 +02:00
int current_bus_idx = - 1 ;
for ( int search_idx = 0 ; search_idx < MAX_BUSES_PER_PLAYBACK ; search_idx + + ) {
2021-08-28 06:51:03 +02:00
if ( bus_details . bus [ search_idx ] = = playback - > prev_bus_details - > bus [ idx ] ) {
2021-08-27 19:28:23 +02:00
current_bus_idx = search_idx ;
}
}
if ( current_bus_idx ! = - 1 ) {
// If we found a corresponding bus in the current bus assignments, we've already mixed to this bus.
continue ;
}
for ( int channel_idx = 0 ; channel_idx < channel_count ; channel_idx + + ) {
AudioFrame * channel_buf = thread_get_channel_mix_buffer ( bus_idx , channel_idx ) ;
2021-08-28 06:51:03 +02:00
AudioFrame prev_channel_vol = playback - > prev_bus_details - > volume [ idx ] [ channel_idx ] ;
2021-08-27 19:28:23 +02:00
// Fade out to silence
_mix_step_for_channel ( channel_buf , buf , prev_channel_vol , AudioFrame ( 0 , 0 ) , playback - > attenuation_filter_cutoff_hz . get ( ) , playback - > highshelf_gain . get ( ) , & playback - > filter_process [ channel_idx * 2 ] , & playback - > filter_process [ channel_idx * 2 + 1 ] ) ;
}
}
// Copy the bus details we mixed with to the previous bus details to maintain volume ramps.
2021-08-28 06:51:03 +02:00
std : : copy ( std : : begin ( bus_details . bus_active ) , std : : end ( bus_details . bus_active ) , std : : begin ( playback - > prev_bus_details - > bus_active ) ) ;
std : : copy ( std : : begin ( bus_details . bus ) , std : : end ( bus_details . bus ) , std : : begin ( playback - > prev_bus_details - > bus ) ) ;
2021-08-27 19:28:23 +02:00
for ( int bus_idx = 0 ; bus_idx < MAX_BUSES_PER_PLAYBACK ; bus_idx + + ) {
2021-08-28 06:51:03 +02:00
std : : copy ( std : : begin ( bus_details . volume [ bus_idx ] ) , std : : end ( bus_details . volume [ bus_idx ] ) , std : : begin ( playback - > prev_bus_details - > volume [ bus_idx ] ) ) ;
2021-08-27 19:28:23 +02:00
}
2017-01-21 23:00:25 +01:00
2021-08-27 19:28:23 +02:00
switch ( playback - > state . load ( ) ) {
case AudioStreamPlaybackListNode : : AWAITING_DELETION :
case AudioStreamPlaybackListNode : : FADE_OUT_TO_DELETION :
playback_list . erase ( playback , [ ] ( AudioStreamPlaybackListNode * p ) {
2022-12-18 01:57:16 +01:00
delete p - > prev_bus_details ;
delete p - > bus_details ;
2021-08-27 19:28:23 +02:00
p - > stream_playback . unref ( ) ;
delete p ;
} ) ;
break ;
case AudioStreamPlaybackListNode : : FADE_OUT_TO_PAUSE : {
// Pause the stream.
AudioStreamPlaybackListNode : : PlaybackState old_state , new_state ;
do {
old_state = playback - > state . load ( ) ;
new_state = AudioStreamPlaybackListNode : : PAUSED ;
} while ( ! playback - > state . compare_exchange_strong ( /* expected= */ old_state , new_state ) ) ;
} break ;
case AudioStreamPlaybackListNode : : PLAYING :
case AudioStreamPlaybackListNode : : PAUSED :
// No-op!
break ;
}
2017-01-21 23:00:25 +01:00
}
for ( int i = buses . size ( ) - 1 ; i > = 0 ; i - - ) {
//go bus by bus
Bus * bus = buses [ i ] ;
for ( int k = 0 ; k < bus - > channels . size ( ) ; k + + ) {
if ( bus - > channels [ k ] . active & & ! bus - > channels [ k ] . used ) {
//buffer was not used, but it's still active, so it must be cleaned
2018-07-25 03:11:03 +02:00
AudioFrame * buf = bus - > channels . write [ k ] . buffer . ptrw ( ) ;
2017-01-21 23:00:25 +01:00
for ( uint32_t j = 0 ; j < buffer_size ; j + + ) {
buf [ j ] = AudioFrame ( 0 , 0 ) ;
}
}
}
//process effects
2017-08-18 23:19:12 +02:00
if ( ! bus - > bypass ) {
for ( int j = 0 ; j < bus - > effects . size ( ) ; j + + ) {
2020-05-14 16:41:43 +02:00
if ( ! bus - > effects [ j ] . enabled ) {
2017-08-18 23:19:12 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-01-21 23:00:25 +01:00
2018-06-21 02:02:02 +02:00
# ifdef DEBUG_ENABLED
uint64_t ticks = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
# endif
2017-08-18 23:19:12 +02:00
for ( int k = 0 ; k < bus - > channels . size ( ) ; k + + ) {
2020-05-14 16:41:43 +02:00
if ( ! ( bus - > channels [ k ] . active | | bus - > channels [ k ] . effect_instances [ j ] - > process_silence ( ) ) ) {
2017-08-18 23:19:12 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-07-25 03:11:03 +02:00
bus - > channels . write [ k ] . effect_instances . write [ j ] - > process ( bus - > channels [ k ] . buffer . ptr ( ) , temp_buffer . write [ k ] . ptrw ( ) , buffer_size ) ;
2017-08-18 23:19:12 +02:00
}
2017-01-21 23:00:25 +01:00
2017-08-18 23:19:12 +02:00
//swap buffers, so internal buffer always has the right data
for ( int k = 0 ; k < bus - > channels . size ( ) ; k + + ) {
2020-05-14 16:41:43 +02:00
if ( ! ( buses [ i ] - > channels [ k ] . active | | bus - > channels [ k ] . effect_instances [ j ] - > process_silence ( ) ) ) {
2017-08-18 23:19:12 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-07-25 03:11:03 +02:00
SWAP ( bus - > channels . write [ k ] . buffer , temp_buffer . write [ k ] ) ;
2017-08-18 23:19:12 +02:00
}
2018-06-21 02:02:02 +02:00
# ifdef DEBUG_ENABLED
2018-07-25 03:11:03 +02:00
bus - > effects . write [ j ] . prof_time + = OS : : get_singleton ( ) - > get_ticks_usec ( ) - ticks ;
2018-06-21 02:02:02 +02:00
# endif
2017-01-21 23:00:25 +01:00
}
}
//process send
2020-04-02 01:20:12 +02:00
Bus * send = nullptr ;
2017-01-21 23:00:25 +01:00
if ( i > 0 ) {
//everything has a send save for master bus
if ( ! bus_map . has ( bus - > send ) ) {
send = buses [ 0 ] ;
} else {
send = bus_map [ bus - > send ] ;
if ( send - > index_cache > = bus - > index_cache ) { //invalid, send to master
send = buses [ 0 ] ;
}
}
}
for ( int k = 0 ; k < bus - > channels . size ( ) ; k + + ) {
2020-05-14 16:41:43 +02:00
if ( ! bus - > channels [ k ] . active ) {
2021-02-02 11:25:40 +01:00
bus - > channels . write [ k ] . peak_volume = AudioFrame ( AUDIO_MIN_PEAK_DB , AUDIO_MIN_PEAK_DB ) ;
2017-01-21 23:00:25 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-01-21 23:00:25 +01:00
2018-07-25 03:11:03 +02:00
AudioFrame * buf = bus - > channels . write [ k ] . buffer . ptrw ( ) ;
2017-01-21 23:00:25 +01:00
AudioFrame peak = AudioFrame ( 0 , 0 ) ;
2017-08-18 23:19:12 +02:00
2022-08-13 17:45:42 +02:00
float volume = Math : : db_to_linear ( bus - > volume_db ) ;
2017-08-18 23:19:12 +02:00
if ( solo_mode ) {
if ( ! bus - > soloed ) {
volume = 0.0 ;
}
} else {
if ( bus - > mute ) {
volume = 0.0 ;
}
}
//apply volume and compute peak
2017-01-21 23:00:25 +01:00
for ( uint32_t j = 0 ; j < buffer_size ; j + + ) {
2017-08-18 23:19:12 +02:00
buf [ j ] * = volume ;
2024-01-09 15:01:12 +01:00
float l = ABS ( buf [ j ] . left ) ;
if ( l > peak . left ) {
peak . left = l ;
2017-01-21 23:00:25 +01:00
}
2024-01-09 15:01:12 +01:00
float r = ABS ( buf [ j ] . right ) ;
if ( r > peak . right ) {
peak . right = r ;
2017-01-21 23:00:25 +01:00
}
}
2024-01-09 15:01:12 +01:00
bus - > channels . write [ k ] . peak_volume = AudioFrame ( Math : : linear_to_db ( peak . left + AUDIO_PEAK_OFFSET ) , Math : : linear_to_db ( peak . right + AUDIO_PEAK_OFFSET ) ) ;
2017-01-21 23:00:25 +01:00
if ( ! bus - > channels [ k ] . used ) {
//see if any audio is contained, because channel was not used
2024-01-09 15:01:12 +01:00
if ( MAX ( peak . right , peak . left ) > Math : : db_to_linear ( channel_disable_threshold_db ) ) {
2018-07-25 03:11:03 +02:00
bus - > channels . write [ k ] . last_mix_with_audio = mix_frames ;
2017-01-21 23:00:25 +01:00
} else if ( mix_frames - bus - > channels [ k ] . last_mix_with_audio > channel_disable_frames ) {
2018-07-25 03:11:03 +02:00
bus - > channels . write [ k ] . active = false ;
2017-03-24 21:45:31 +01:00
continue ; //went inactive, don't mix.
2017-01-21 23:00:25 +01:00
}
}
if ( send ) {
//if not master bus, send
AudioFrame * target_buf = thread_get_channel_mix_buffer ( send - > index_cache , k ) ;
for ( uint32_t j = 0 ; j < buffer_size ; j + + ) {
target_buf [ j ] + = buf [ j ] ;
}
}
}
}
mix_frames + = buffer_size ;
to_mix = buffer_size ;
}
2021-08-27 19:28:23 +02:00
void AudioServer : : _mix_step_for_channel ( AudioFrame * p_out_buf , AudioFrame * p_source_buf , AudioFrame p_vol_start , AudioFrame p_vol_final , float p_attenuation_filter_cutoff_hz , float p_highshelf_gain , AudioFilterSW : : Processor * p_processor_l , AudioFilterSW : : Processor * p_processor_r ) {
if ( p_highshelf_gain ! = 0 ) {
AudioFilterSW filter ;
filter . set_mode ( AudioFilterSW : : HIGHSHELF ) ;
filter . set_sampling_rate ( AudioServer : : get_singleton ( ) - > get_mix_rate ( ) ) ;
filter . set_cutoff ( p_attenuation_filter_cutoff_hz ) ;
filter . set_resonance ( 1 ) ;
filter . set_stages ( 1 ) ;
filter . set_gain ( p_highshelf_gain ) ;
2023-09-09 17:04:18 +02:00
ERR_FAIL_NULL ( p_processor_l ) ;
ERR_FAIL_NULL ( p_processor_r ) ;
2021-08-27 19:28:23 +02:00
2024-01-09 15:01:12 +01:00
bool is_just_started = p_vol_start . left = = 0 & & p_vol_start . right = = 0 ;
2021-08-27 19:28:23 +02:00
p_processor_l - > set_filter ( & filter , /* clear_history= */ is_just_started ) ;
p_processor_l - > update_coeffs ( buffer_size ) ;
p_processor_r - > set_filter ( & filter , /* clear_history= */ is_just_started ) ;
p_processor_r - > update_coeffs ( buffer_size ) ;
for ( unsigned int frame_idx = 0 ; frame_idx < buffer_size ; frame_idx + + ) {
// Make this buffer size invariant if buffer_size ever becomes a project setting.
float lerp_param = ( float ) frame_idx / buffer_size ;
AudioFrame vol = p_vol_final * lerp_param + ( 1 - lerp_param ) * p_vol_start ;
AudioFrame mixed = vol * p_source_buf [ frame_idx ] ;
2024-01-09 15:01:12 +01:00
p_processor_l - > process_one_interp ( mixed . left ) ;
p_processor_r - > process_one_interp ( mixed . right ) ;
2021-08-27 19:28:23 +02:00
p_out_buf [ frame_idx ] + = mixed ;
}
} else {
for ( unsigned int frame_idx = 0 ; frame_idx < buffer_size ; frame_idx + + ) {
// Make this buffer size invariant if buffer_size ever becomes a project setting.
float lerp_param = ( float ) frame_idx / buffer_size ;
p_out_buf [ frame_idx ] + = ( p_vol_final * lerp_param + ( 1 - lerp_param ) * p_vol_start ) * p_source_buf [ frame_idx ] ;
}
}
}
AudioServer : : AudioStreamPlaybackListNode * AudioServer : : _find_playback_list_node ( Ref < AudioStreamPlayback > p_playback ) {
for ( AudioStreamPlaybackListNode * playback_list_node : playback_list ) {
if ( playback_list_node - > stream_playback = = p_playback ) {
return playback_list_node ;
}
}
return nullptr ;
}
2018-11-13 22:16:33 +01:00
bool AudioServer : : thread_has_channel_mix_buffer ( int p_bus , int p_buffer ) const {
2020-05-14 16:41:43 +02:00
if ( p_bus < 0 | | p_bus > = buses . size ( ) ) {
2018-11-13 22:16:33 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
if ( p_buffer < 0 | | p_buffer > = buses [ p_bus ] - > channels . size ( ) ) {
2018-11-13 22:16:33 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-11-13 22:16:33 +01:00
return true ;
}
2017-01-21 23:00:25 +01:00
AudioFrame * AudioServer : : thread_get_channel_mix_buffer ( int p_bus , int p_buffer ) {
2020-04-02 01:20:12 +02:00
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , nullptr ) ;
ERR_FAIL_INDEX_V ( p_buffer , buses [ p_bus ] - > channels . size ( ) , nullptr ) ;
2017-01-21 23:00:25 +01:00
2018-07-25 03:11:03 +02:00
AudioFrame * data = buses . write [ p_bus ] - > channels . write [ p_buffer ] . buffer . ptrw ( ) ;
2017-01-21 23:00:25 +01:00
if ( ! buses [ p_bus ] - > channels [ p_buffer ] . used ) {
2018-07-25 03:11:03 +02:00
buses . write [ p_bus ] - > channels . write [ p_buffer ] . used = true ;
buses . write [ p_bus ] - > channels . write [ p_buffer ] . active = true ;
buses . write [ p_bus ] - > channels . write [ p_buffer ] . last_mix_with_audio = mix_frames ;
2017-01-21 23:00:25 +01:00
for ( uint32_t i = 0 ; i < buffer_size ; i + + ) {
data [ i ] = AudioFrame ( 0 , 0 ) ;
}
}
return data ;
}
int AudioServer : : thread_get_mix_buffer_size ( ) const {
return buffer_size ;
}
int AudioServer : : thread_find_bus_index ( const StringName & p_name ) {
if ( bus_map . has ( p_name ) ) {
return bus_map [ p_name ] - > index_cache ;
} else {
return 0 ;
}
}
2017-01-15 20:06:14 +01:00
void AudioServer : : set_bus_count ( int p_count ) {
ERR_FAIL_COND ( p_count < 1 ) ;
ERR_FAIL_INDEX ( p_count , 256 ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-15 20:06:14 +01:00
lock ( ) ;
2017-01-21 23:00:25 +01:00
int cb = buses . size ( ) ;
if ( p_count < buses . size ( ) ) {
for ( int i = p_count ; i < buses . size ( ) ; i + + ) {
bus_map . erase ( buses [ i ] - > name ) ;
memdelete ( buses [ i ] ) ;
}
}
2017-01-15 20:06:14 +01:00
buses . resize ( p_count ) ;
2017-01-21 23:00:25 +01:00
for ( int i = cb ; i < buses . size ( ) ; i + + ) {
String attempt = " New Bus " ;
int attempts = 1 ;
while ( true ) {
bool name_free = true ;
for ( int j = 0 ; j < i ; j + + ) {
if ( buses [ j ] - > name = = attempt ) {
name_free = false ;
break ;
}
}
if ( ! name_free ) {
attempts + + ;
attempt = " New Bus " + itos ( attempts ) ;
} else {
break ;
}
}
2018-07-25 03:11:03 +02:00
buses . write [ i ] = memnew ( Bus ) ;
buses . write [ i ] - > channels . resize ( channel_count ) ;
2018-03-18 02:43:32 +01:00
for ( int j = 0 ; j < channel_count ; j + + ) {
2018-07-25 03:11:03 +02:00
buses . write [ i ] - > channels . write [ j ] . buffer . resize ( buffer_size ) ;
2017-01-21 23:00:25 +01:00
}
buses [ i ] - > name = attempt ;
buses [ i ] - > solo = false ;
buses [ i ] - > mute = false ;
buses [ i ] - > bypass = false ;
buses [ i ] - > volume_db = 0 ;
if ( i > 0 ) {
2023-09-04 17:01:33 +02:00
buses [ i ] - > send = SceneStringName ( Master ) ;
2017-01-21 23:00:25 +01:00
}
bus_map [ attempt ] = buses [ i ] ;
}
2017-01-15 20:06:14 +01:00
unlock ( ) ;
2017-01-21 23:00:25 +01:00
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_count ( p_count ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " bus_layout_changed " ) ) ;
2017-01-15 20:06:14 +01:00
}
2017-01-24 03:12:08 +01:00
void AudioServer : : remove_bus ( int p_index ) {
ERR_FAIL_INDEX ( p_index , buses . size ( ) ) ;
ERR_FAIL_COND ( p_index = = 0 ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-24 03:12:08 +01:00
lock ( ) ;
bus_map . erase ( buses [ p_index ] - > name ) ;
memdelete ( buses [ p_index ] ) ;
2021-07-04 00:17:03 +02:00
buses . remove_at ( p_index ) ;
2017-01-24 03:12:08 +01:00
unlock ( ) ;
2018-02-23 23:42:57 +01:00
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > remove_sample_bus ( p_index ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " bus_layout_changed " ) ) ;
2017-01-24 03:12:08 +01:00
}
void AudioServer : : add_bus ( int p_at_pos ) {
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-24 03:12:08 +01:00
if ( p_at_pos > = buses . size ( ) ) {
p_at_pos = - 1 ;
} else if ( p_at_pos = = 0 ) {
2020-05-14 16:41:43 +02:00
if ( buses . size ( ) > 1 ) {
2017-01-24 03:12:08 +01:00
p_at_pos = 1 ;
2020-05-14 16:41:43 +02:00
} else {
2017-01-24 03:12:08 +01:00
p_at_pos = - 1 ;
2020-05-14 16:41:43 +02:00
}
2017-01-24 03:12:08 +01:00
}
String attempt = " New Bus " ;
int attempts = 1 ;
while ( true ) {
bool name_free = true ;
for ( int j = 0 ; j < buses . size ( ) ; j + + ) {
if ( buses [ j ] - > name = = attempt ) {
name_free = false ;
break ;
}
}
if ( ! name_free ) {
attempts + + ;
attempt = " New Bus " + itos ( attempts ) ;
} else {
break ;
}
}
Bus * bus = memnew ( Bus ) ;
2018-03-18 02:43:32 +01:00
bus - > channels . resize ( channel_count ) ;
for ( int j = 0 ; j < channel_count ; j + + ) {
2018-07-25 03:11:03 +02:00
bus - > channels . write [ j ] . buffer . resize ( buffer_size ) ;
2017-01-24 03:12:08 +01:00
}
bus - > name = attempt ;
bus - > solo = false ;
bus - > mute = false ;
bus - > bypass = false ;
bus - > volume_db = 0 ;
bus_map [ attempt ] = bus ;
2020-05-14 16:41:43 +02:00
if ( p_at_pos = = - 1 ) {
2017-01-24 03:12:08 +01:00
buses . push_back ( bus ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-01-24 03:12:08 +01:00
buses . insert ( p_at_pos , bus ) ;
2020-05-14 16:41:43 +02:00
}
2018-02-23 23:42:57 +01:00
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > add_sample_bus ( p_at_pos ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " bus_layout_changed " ) ) ;
2017-01-24 03:12:08 +01:00
}
void AudioServer : : move_bus ( int p_bus , int p_to_pos ) {
ERR_FAIL_COND ( p_bus < 1 | | p_bus > = buses . size ( ) ) ;
ERR_FAIL_COND ( p_to_pos ! = - 1 & & ( p_to_pos < 1 | | p_to_pos > buses . size ( ) ) ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2020-05-14 16:41:43 +02:00
if ( p_bus = = p_to_pos ) {
2017-01-24 03:12:08 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-01-24 03:12:08 +01:00
Bus * bus = buses [ p_bus ] ;
2021-07-04 00:17:03 +02:00
buses . remove_at ( p_bus ) ;
2017-01-24 03:12:08 +01:00
if ( p_to_pos = = - 1 ) {
buses . push_back ( bus ) ;
} else if ( p_to_pos < p_bus ) {
buses . insert ( p_to_pos , bus ) ;
} else {
buses . insert ( p_to_pos - 1 , bus ) ;
}
2018-02-23 23:42:57 +01:00
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > move_sample_bus ( p_bus , p_to_pos ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " bus_layout_changed " ) ) ;
2017-01-24 03:12:08 +01:00
}
2017-01-15 20:06:14 +01:00
int AudioServer : : get_bus_count ( ) const {
return buses . size ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-21 23:00:25 +01:00
void AudioServer : : set_bus_name ( int p_bus , const String & p_name ) {
2017-01-15 20:06:14 +01:00
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( p_bus = = 0 & & p_name ! = " Master " ) {
2023-09-14 12:39:23 +02:00
return ; // Bus 0 is always "Master".
2020-05-14 16:41:43 +02:00
}
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-21 23:00:25 +01:00
lock ( ) ;
2017-01-15 20:06:14 +01:00
2023-09-14 12:39:23 +02:00
StringName old_name = buses [ p_bus ] - > name ;
if ( old_name = = p_name ) {
2017-01-21 23:00:25 +01:00
unlock ( ) ;
return ;
}
2017-01-15 20:06:14 +01:00
2017-01-21 23:00:25 +01:00
String attempt = p_name ;
int attempts = 1 ;
2017-01-15 20:06:14 +01:00
2017-01-21 23:00:25 +01:00
while ( true ) {
bool name_free = true ;
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
if ( buses [ i ] - > name = = attempt ) {
name_free = false ;
break ;
}
}
if ( name_free ) {
break ;
}
attempts + + ;
attempt = p_name + " " + itos ( attempts ) ;
}
2023-09-14 12:39:23 +02:00
bus_map . erase ( old_name ) ;
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > name = attempt ;
bus_map [ attempt ] = buses [ p_bus ] ;
unlock ( ) ;
2023-09-14 12:39:23 +02:00
emit_signal ( SNAME ( " bus_renamed " ) , p_bus , old_name , attempt ) ;
2017-01-15 20:06:14 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-15 20:06:14 +01:00
String AudioServer : : get_bus_name ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , String ( ) ) ;
2017-01-21 23:00:25 +01:00
return buses [ p_bus ] - > name ;
2017-01-15 20:06:14 +01:00
}
2016-01-21 14:40:35 +01:00
2017-07-10 22:51:29 +02:00
int AudioServer : : get_bus_index ( const StringName & p_bus_name ) const {
for ( int i = 0 ; i < buses . size ( ) ; + + i ) {
if ( buses [ i ] - > name = = p_bus_name ) {
return i ;
}
}
return - 1 ;
}
2017-01-15 20:06:14 +01:00
void AudioServer : : set_bus_volume_db ( int p_bus , float p_volume_db ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > volume_db = p_volume_db ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_volume_db ( p_bus , p_volume_db ) ;
2017-01-15 20:06:14 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-15 20:06:14 +01:00
float AudioServer : : get_bus_volume_db ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , 0 ) ;
2017-01-21 23:00:25 +01:00
return buses [ p_bus ] - > volume_db ;
}
2018-12-07 17:38:40 +01:00
int AudioServer : : get_bus_channels ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , 0 ) ;
return buses [ p_bus ] - > channels . size ( ) ;
}
2017-01-21 23:00:25 +01:00
void AudioServer : : set_bus_send ( int p_bus , const StringName & p_send ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > send = p_send ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_send ( p_bus , p_send ) ;
2017-01-21 23:00:25 +01:00
}
StringName AudioServer : : get_bus_send ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , StringName ( ) ) ;
return buses [ p_bus ] - > send ;
}
void AudioServer : : set_bus_solo ( int p_bus , bool p_enable ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > solo = p_enable ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_solo ( p_bus , p_enable ) ;
2017-01-21 23:00:25 +01:00
}
bool AudioServer : : is_bus_solo ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , false ) ;
return buses [ p_bus ] - > solo ;
}
void AudioServer : : set_bus_mute ( int p_bus , bool p_enable ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > mute = p_enable ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_mute ( p_bus , p_enable ) ;
2017-01-21 23:00:25 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-21 23:00:25 +01:00
bool AudioServer : : is_bus_mute ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , false ) ;
return buses [ p_bus ] - > mute ;
}
void AudioServer : : set_bus_bypass_effects ( int p_bus , bool p_enable ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2016-01-21 14:40:35 +01:00
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > bypass = p_enable ;
2017-01-15 20:06:14 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-21 23:00:25 +01:00
bool AudioServer : : is_bus_bypassing_effects ( int p_bus ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , false ) ;
return buses [ p_bus ] - > bypass ;
}
void AudioServer : : _update_bus_effects ( int p_bus ) {
for ( int i = 0 ; i < buses [ p_bus ] - > channels . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
buses . write [ p_bus ] - > channels . write [ i ] . effect_instances . resize ( buses [ p_bus ] - > effects . size ( ) ) ;
2017-01-21 23:00:25 +01:00
for ( int j = 0 ; j < buses [ p_bus ] - > effects . size ( ) ; j + + ) {
2021-06-18 00:03:09 +02:00
Ref < AudioEffectInstance > fx = buses . write [ p_bus ] - > effects . write [ j ] . effect - > instantiate ( ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < AudioEffectCompressorInstance > ( * fx ) ) {
Object : : cast_to < AudioEffectCompressorInstance > ( * fx ) - > set_current_channel ( i ) ;
2017-01-23 00:39:53 +01:00
}
2018-07-25 03:11:03 +02:00
buses . write [ p_bus ] - > channels . write [ i ] . effect_instances . write [ j ] = fx ;
2017-01-21 23:00:25 +01:00
}
}
}
2017-01-15 20:06:14 +01:00
void AudioServer : : add_bus_effect ( int p_bus , const Ref < AudioEffect > & p_effect , int p_at_pos ) {
ERR_FAIL_COND ( p_effect . is_null ( ) ) ;
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2016-01-21 14:40:35 +01:00
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-15 20:06:14 +01:00
lock ( ) ;
2016-01-21 14:40:35 +01:00
2017-01-15 20:06:14 +01:00
Bus : : Effect fx ;
fx . effect = p_effect ;
2021-06-18 00:03:09 +02:00
//fx.instance=p_effect->instantiate();
2017-01-15 20:06:14 +01:00
fx . enabled = true ;
2018-06-21 02:02:02 +02:00
# ifdef DEBUG_ENABLED
fx . prof_time = 0 ;
# endif
2016-01-21 14:40:35 +01:00
2017-01-21 23:00:25 +01:00
if ( p_at_pos > = buses [ p_bus ] - > effects . size ( ) | | p_at_pos < 0 ) {
buses [ p_bus ] - > effects . push_back ( fx ) ;
2017-01-15 20:06:14 +01:00
} else {
2017-01-21 23:00:25 +01:00
buses [ p_bus ] - > effects . insert ( p_at_pos , fx ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-21 23:00:25 +01:00
_update_bus_effects ( p_bus ) ;
2017-01-15 20:06:14 +01:00
unlock ( ) ;
}
void AudioServer : : remove_bus_effect ( int p_bus , int p_effect ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-15 20:06:14 +01:00
lock ( ) ;
2014-02-10 02:10:30 +01:00
2021-07-04 00:17:03 +02:00
buses [ p_bus ] - > effects . remove_at ( p_effect ) ;
2017-01-21 23:00:25 +01:00
_update_bus_effects ( p_bus ) ;
2014-02-10 02:10:30 +01:00
2017-01-15 20:06:14 +01:00
unlock ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-15 20:06:14 +01:00
int AudioServer : : get_bus_effect_count ( int p_bus ) {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , 0 ) ;
2017-01-21 23:00:25 +01:00
return buses [ p_bus ] - > effects . size ( ) ;
2017-01-15 20:06:14 +01:00
}
2019-04-10 17:57:03 +02:00
Ref < AudioEffectInstance > AudioServer : : get_bus_effect_instance ( int p_bus , int p_effect , int p_channel ) {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , Ref < AudioEffectInstance > ( ) ) ;
ERR_FAIL_INDEX_V ( p_effect , buses [ p_bus ] - > effects . size ( ) , Ref < AudioEffectInstance > ( ) ) ;
ERR_FAIL_INDEX_V ( p_channel , buses [ p_bus ] - > channels . size ( ) , Ref < AudioEffectInstance > ( ) ) ;
return buses [ p_bus ] - > channels [ p_channel ] . effect_instances [ p_effect ] ;
}
2017-01-15 20:06:14 +01:00
Ref < AudioEffect > AudioServer : : get_bus_effect ( int p_bus , int p_effect ) {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , Ref < AudioEffect > ( ) ) ;
2017-01-21 23:00:25 +01:00
ERR_FAIL_INDEX_V ( p_effect , buses [ p_bus ] - > effects . size ( ) , Ref < AudioEffect > ( ) ) ;
2017-01-15 20:06:14 +01:00
2017-01-21 23:00:25 +01:00
return buses [ p_bus ] - > effects [ p_effect ] . effect ;
2017-01-15 20:06:14 +01:00
}
void AudioServer : : swap_bus_effects ( int p_bus , int p_effect , int p_by_effect ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2017-01-21 23:00:25 +01:00
ERR_FAIL_INDEX ( p_effect , buses [ p_bus ] - > effects . size ( ) ) ;
ERR_FAIL_INDEX ( p_by_effect , buses [ p_bus ] - > effects . size ( ) ) ;
2017-01-15 20:06:14 +01:00
2017-01-25 18:30:40 +01:00
MARK_EDITED
2017-01-15 20:06:14 +01:00
lock ( ) ;
2018-07-25 03:11:03 +02:00
SWAP ( buses . write [ p_bus ] - > effects . write [ p_effect ] , buses . write [ p_bus ] - > effects . write [ p_by_effect ] ) ;
2017-01-21 23:00:25 +01:00
_update_bus_effects ( p_bus ) ;
2017-01-15 20:06:14 +01:00
unlock ( ) ;
}
void AudioServer : : set_bus_effect_enabled ( int p_bus , int p_effect , bool p_enabled ) {
ERR_FAIL_INDEX ( p_bus , buses . size ( ) ) ;
2017-01-21 23:00:25 +01:00
ERR_FAIL_INDEX ( p_effect , buses [ p_bus ] - > effects . size ( ) ) ;
2017-01-25 18:30:40 +01:00
MARK_EDITED
2018-07-25 03:11:03 +02:00
buses . write [ p_bus ] - > effects . write [ p_effect ] . enabled = p_enabled ;
2017-01-15 20:06:14 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-15 20:06:14 +01:00
bool AudioServer : : is_bus_effect_enabled ( int p_bus , int p_effect ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , false ) ;
2017-01-21 23:00:25 +01:00
ERR_FAIL_INDEX_V ( p_effect , buses [ p_bus ] - > effects . size ( ) , false ) ;
return buses [ p_bus ] - > effects [ p_effect ] . enabled ;
}
float AudioServer : : get_bus_peak_volume_left_db ( int p_bus , int p_channel ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , 0 ) ;
ERR_FAIL_INDEX_V ( p_channel , buses [ p_bus ] - > channels . size ( ) , 0 ) ;
2024-01-09 15:01:12 +01:00
return buses [ p_bus ] - > channels [ p_channel ] . peak_volume . left ;
2017-01-21 23:00:25 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-21 23:00:25 +01:00
float AudioServer : : get_bus_peak_volume_right_db ( int p_bus , int p_channel ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , 0 ) ;
ERR_FAIL_INDEX_V ( p_channel , buses [ p_bus ] - > channels . size ( ) , 0 ) ;
2024-01-09 15:01:12 +01:00
return buses [ p_bus ] - > channels [ p_channel ] . peak_volume . right ;
2017-01-21 23:00:25 +01:00
}
bool AudioServer : : is_bus_channel_active ( int p_bus , int p_channel ) const {
ERR_FAIL_INDEX_V ( p_bus , buses . size ( ) , false ) ;
ERR_FAIL_INDEX_V ( p_channel , buses [ p_bus ] - > channels . size ( ) , false ) ;
return buses [ p_bus ] - > channels [ p_channel ] . active ;
2017-01-15 20:06:14 +01:00
}
2014-02-10 02:10:30 +01:00
2020-05-07 18:46:33 +02:00
void AudioServer : : set_playback_speed_scale ( float p_scale ) {
2020-11-05 12:44:53 +01:00
ERR_FAIL_COND ( p_scale < = 0 ) ;
2020-05-07 18:46:33 +02:00
playback_speed_scale = p_scale ;
2019-06-03 01:01:42 +02:00
}
2020-05-14 14:29:06 +02:00
2020-05-07 18:46:33 +02:00
float AudioServer : : get_playback_speed_scale ( ) const {
return playback_speed_scale ;
2019-06-03 01:01:42 +02:00
}
2021-08-01 21:47:20 +02:00
void AudioServer : : start_playback_stream ( Ref < AudioStreamPlayback > p_playback , const StringName & p_bus , Vector < AudioFrame > p_volume_db_vector , float p_start_time , float p_pitch_scale ) {
2021-08-27 19:28:23 +02:00
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , Vector < AudioFrame > > map ;
2021-08-27 19:28:23 +02:00
map [ p_bus ] = p_volume_db_vector ;
2021-10-10 18:20:56 +02:00
start_playback_stream ( p_playback , map , p_start_time , p_pitch_scale ) ;
2021-08-27 19:28:23 +02:00
}
2021-08-01 21:47:20 +02:00
void AudioServer : : start_playback_stream ( Ref < AudioStreamPlayback > p_playback , const HashMap < StringName , Vector < AudioFrame > > & p_bus_volumes , float p_start_time , float p_pitch_scale , float p_highshelf_gain , float p_attenuation_cutoff_hz ) {
2021-08-27 19:28:23 +02:00
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
AudioStreamPlaybackListNode * playback_node = new AudioStreamPlaybackListNode ( ) ;
playback_node - > stream_playback = p_playback ;
playback_node - > stream_playback - > start ( p_start_time ) ;
AudioStreamPlaybackBusDetails * new_bus_details = new AudioStreamPlaybackBusDetails ( ) ;
int idx = 0 ;
for ( KeyValue < StringName , Vector < AudioFrame > > pair : p_bus_volumes ) {
2021-10-18 15:52:01 +02:00
if ( pair . value . size ( ) < channel_count | | pair . value . size ( ) ! = MAX_CHANNELS_PER_BUS ) {
delete new_bus_details ;
ERR_FAIL ( ) ;
}
2021-08-27 19:28:23 +02:00
new_bus_details - > bus_active [ idx ] = true ;
new_bus_details - > bus [ idx ] = pair . key ;
for ( int channel_idx = 0 ; channel_idx < MAX_CHANNELS_PER_BUS ; channel_idx + + ) {
new_bus_details - > volume [ idx ] [ channel_idx ] = pair . value [ channel_idx ] ;
}
2023-12-28 18:00:37 +01:00
idx + + ;
2021-08-27 19:28:23 +02:00
}
playback_node - > bus_details = new_bus_details ;
playback_node - > prev_bus_details = new AudioStreamPlaybackBusDetails ( ) ;
2021-08-28 06:51:03 +02:00
playback_node - > pitch_scale . set ( p_pitch_scale ) ;
playback_node - > highshelf_gain . set ( p_highshelf_gain ) ;
playback_node - > attenuation_filter_cutoff_hz . set ( p_attenuation_cutoff_hz ) ;
2021-08-27 19:28:23 +02:00
memset ( playback_node - > prev_bus_details - > volume , 0 , sizeof ( playback_node - > prev_bus_details - > volume ) ) ;
for ( AudioFrame & frame : playback_node - > lookahead ) {
frame = AudioFrame ( 0 , 0 ) ;
}
playback_node - > state . store ( AudioStreamPlaybackListNode : : PLAYING ) ;
playback_list . insert ( playback_node ) ;
}
void AudioServer : : stop_playback_stream ( Ref < AudioStreamPlayback > p_playback ) {
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
2024-07-12 16:49:59 +02:00
// Handle sample playback.
if ( p_playback - > get_is_sample ( ) & & p_playback - > get_sample_playback ( ) . is_valid ( ) ) {
AudioServer : : get_singleton ( ) - > stop_sample_playback ( p_playback - > get_sample_playback ( ) ) ;
return ;
}
2021-08-27 19:28:23 +02:00
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return ;
}
AudioStreamPlaybackListNode : : PlaybackState new_state , old_state ;
do {
old_state = playback_node - > state . load ( ) ;
2021-08-28 06:51:03 +02:00
if ( old_state = = AudioStreamPlaybackListNode : : AWAITING_DELETION ) {
break ; // Don't fade out again.
}
2021-08-27 19:28:23 +02:00
new_state = AudioStreamPlaybackListNode : : FADE_OUT_TO_DELETION ;
} while ( ! playback_node - > state . compare_exchange_strong ( old_state , new_state ) ) ;
}
2021-08-01 21:47:20 +02:00
void AudioServer : : set_playback_bus_exclusive ( Ref < AudioStreamPlayback > p_playback , const StringName & p_bus , Vector < AudioFrame > p_volumes ) {
2021-08-27 19:28:23 +02:00
ERR_FAIL_COND ( p_volumes . size ( ) ! = MAX_CHANNELS_PER_BUS ) ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , Vector < AudioFrame > > map ;
2021-08-27 19:28:23 +02:00
map [ p_bus ] = p_volumes ;
set_playback_bus_volumes_linear ( p_playback , map ) ;
}
2021-08-01 21:47:20 +02:00
void AudioServer : : set_playback_bus_volumes_linear ( Ref < AudioStreamPlayback > p_playback , const HashMap < StringName , Vector < AudioFrame > > & p_bus_volumes ) {
2021-08-27 19:28:23 +02:00
ERR_FAIL_COND ( p_bus_volumes . size ( ) > MAX_BUSES_PER_PLAYBACK ) ;
2024-04-18 16:50:34 +02:00
// Samples.
if ( p_playback - > get_is_sample ( ) & & p_playback - > get_sample_playback ( ) . is_valid ( ) ) {
Ref < AudioSamplePlayback > sample_playback = p_playback - > get_sample_playback ( ) ;
AudioDriver : : get_singleton ( ) - > set_sample_playback_bus_volumes_linear ( sample_playback , p_bus_volumes ) ;
return ;
}
2021-08-27 19:28:23 +02:00
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return ;
}
AudioStreamPlaybackBusDetails * old_bus_details , * new_bus_details = new AudioStreamPlaybackBusDetails ( ) ;
int idx = 0 ;
for ( KeyValue < StringName , Vector < AudioFrame > > pair : p_bus_volumes ) {
2021-08-28 06:51:03 +02:00
if ( idx > = MAX_BUSES_PER_PLAYBACK ) {
break ;
}
2021-08-27 19:28:23 +02:00
ERR_FAIL_COND ( pair . value . size ( ) < channel_count ) ;
ERR_FAIL_COND ( pair . value . size ( ) ! = MAX_CHANNELS_PER_BUS ) ;
new_bus_details - > bus_active [ idx ] = true ;
new_bus_details - > bus [ idx ] = pair . key ;
for ( int channel_idx = 0 ; channel_idx < MAX_CHANNELS_PER_BUS ; channel_idx + + ) {
new_bus_details - > volume [ idx ] [ channel_idx ] = pair . value [ channel_idx ] ;
}
2021-08-28 06:51:03 +02:00
idx + + ;
2021-08-27 19:28:23 +02:00
}
do {
old_bus_details = playback_node - > bus_details . load ( ) ;
} while ( ! playback_node - > bus_details . compare_exchange_strong ( old_bus_details , new_bus_details ) ) ;
bus_details_graveyard . insert ( old_bus_details ) ;
}
void AudioServer : : set_playback_all_bus_volumes_linear ( Ref < AudioStreamPlayback > p_playback , Vector < AudioFrame > p_volumes ) {
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
ERR_FAIL_COND ( p_volumes . size ( ) ! = MAX_CHANNELS_PER_BUS ) ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , Vector < AudioFrame > > map ;
2021-08-27 19:28:23 +02:00
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return ;
}
for ( int bus_idx = 0 ; bus_idx < MAX_BUSES_PER_PLAYBACK ; bus_idx + + ) {
if ( playback_node - > bus_details . load ( ) - > bus_active [ bus_idx ] ) {
map [ playback_node - > bus_details . load ( ) - > bus [ bus_idx ] ] = p_volumes ;
}
}
set_playback_bus_volumes_linear ( p_playback , map ) ;
}
void AudioServer : : set_playback_pitch_scale ( Ref < AudioStreamPlayback > p_playback , float p_pitch_scale ) {
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
2024-04-18 16:50:34 +02:00
// Samples.
if ( p_playback - > get_is_sample ( ) & & p_playback - > get_sample_playback ( ) . is_valid ( ) ) {
Ref < AudioSamplePlayback > sample_playback = p_playback - > get_sample_playback ( ) ;
AudioServer : : get_singleton ( ) - > update_sample_playback_pitch_scale ( sample_playback , p_pitch_scale ) ;
return ;
}
2021-08-27 19:28:23 +02:00
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return ;
}
playback_node - > pitch_scale . set ( p_pitch_scale ) ;
}
void AudioServer : : set_playback_paused ( Ref < AudioStreamPlayback > p_playback , bool p_paused ) {
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return ;
}
AudioStreamPlaybackListNode : : PlaybackState new_state , old_state ;
do {
old_state = playback_node - > state . load ( ) ;
new_state = p_paused ? AudioStreamPlaybackListNode : : FADE_OUT_TO_PAUSE : AudioStreamPlaybackListNode : : PLAYING ;
2021-08-28 06:51:03 +02:00
if ( ! p_paused & & old_state = = AudioStreamPlaybackListNode : : PLAYING ) {
return ; // No-op.
}
if ( p_paused & & ( old_state = = AudioStreamPlaybackListNode : : PAUSED | | old_state = = AudioStreamPlaybackListNode : : FADE_OUT_TO_PAUSE ) ) {
return ; // No-op.
}
2021-08-27 19:28:23 +02:00
} while ( ! playback_node - > state . compare_exchange_strong ( old_state , new_state ) ) ;
}
void AudioServer : : set_playback_highshelf_params ( Ref < AudioStreamPlayback > p_playback , float p_gain , float p_attenuation_cutoff_hz ) {
ERR_FAIL_COND ( p_playback . is_null ( ) ) ;
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return ;
}
playback_node - > attenuation_filter_cutoff_hz . set ( p_attenuation_cutoff_hz ) ;
playback_node - > highshelf_gain . set ( p_gain ) ;
}
bool AudioServer : : is_playback_active ( Ref < AudioStreamPlayback > p_playback ) {
ERR_FAIL_COND_V ( p_playback . is_null ( ) , false ) ;
2024-07-12 16:49:59 +02:00
if ( p_playback - > get_is_sample ( ) & & p_playback - > get_sample_playback ( ) . is_valid ( ) ) {
return sample_playback_list . has ( p_playback - > get_sample_playback ( ) ) ;
}
2021-08-27 19:28:23 +02:00
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return false ;
}
return playback_node - > state . load ( ) = = AudioStreamPlaybackListNode : : PLAYING ;
}
float AudioServer : : get_playback_position ( Ref < AudioStreamPlayback > p_playback ) {
ERR_FAIL_COND_V ( p_playback . is_null ( ) , 0 ) ;
2024-08-06 15:46:37 +02:00
// Samples.
if ( p_playback - > get_is_sample ( ) & & p_playback - > get_sample_playback ( ) . is_valid ( ) ) {
Ref < AudioSamplePlayback > sample_playback = p_playback - > get_sample_playback ( ) ;
return AudioServer : : get_singleton ( ) - > get_sample_playback_position ( sample_playback ) ;
}
2021-08-27 19:28:23 +02:00
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return 0 ;
}
return playback_node - > stream_playback - > get_playback_position ( ) ;
}
bool AudioServer : : is_playback_paused ( Ref < AudioStreamPlayback > p_playback ) {
ERR_FAIL_COND_V ( p_playback . is_null ( ) , false ) ;
AudioStreamPlaybackListNode * playback_node = _find_playback_list_node ( p_playback ) ;
if ( ! playback_node ) {
return false ;
}
return playback_node - > state . load ( ) = = AudioStreamPlaybackListNode : : PAUSED | | playback_node - > state . load ( ) = = AudioStreamPlaybackListNode : : FADE_OUT_TO_PAUSE ;
}
uint64_t AudioServer : : get_mix_count ( ) const {
return mix_count ;
}
2022-07-21 01:00:58 +02:00
uint64_t AudioServer : : get_mixed_frames ( ) const {
return mix_frames ;
}
2021-08-27 19:28:23 +02:00
void AudioServer : : notify_listener_changed ( ) {
for ( CallbackItem * ci : listener_changed_callback_list ) {
ci - > callback ( ci - > userdata ) ;
}
}
2018-03-18 02:43:32 +01:00
void AudioServer : : init_channels_and_buffers ( ) {
channel_count = get_channel_count ( ) ;
temp_buffer . resize ( channel_count ) ;
2021-08-27 19:28:23 +02:00
mix_buffer . resize ( buffer_size + LOOKAHEAD_BUFFER_SIZE ) ;
2018-03-18 02:43:32 +01:00
for ( int i = 0 ; i < temp_buffer . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
temp_buffer . write [ i ] . resize ( buffer_size ) ;
2018-03-18 02:43:32 +01:00
}
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
buses [ i ] - > channels . resize ( channel_count ) ;
for ( int j = 0 ; j < channel_count ; j + + ) {
2018-07-25 03:11:03 +02:00
buses . write [ i ] - > channels . write [ j ] . buffer . resize ( buffer_size ) ;
2018-03-18 02:43:32 +01:00
}
2022-04-01 16:01:22 +02:00
_update_bus_effects ( i ) ;
2018-03-18 02:43:32 +01:00
}
}
2017-01-15 20:06:14 +01:00
void AudioServer : : init ( ) {
2021-02-17 17:44:49 +01:00
channel_disable_threshold_db = GLOBAL_DEF_RST ( " audio/buses/channel_disable_threshold_db " , - 60.0 ) ;
2022-11-08 19:53:22 +01:00
channel_disable_frames = float ( GLOBAL_DEF_RST ( PropertyInfo ( Variant : : FLOAT , " audio/buses/channel_disable_time " , PROPERTY_HINT_RANGE , " 0,5,0.01,or_greater " ) , 2.0 ) ) * get_mix_rate ( ) ;
2021-08-27 19:28:23 +02:00
buffer_size = 512 ; //hardcoded for now
2017-08-22 23:27:17 +02:00
2018-03-18 02:43:32 +01:00
init_channels_and_buffers ( ) ;
2017-01-21 23:00:25 +01:00
mix_count = 0 ;
2017-01-15 20:06:14 +01:00
set_bus_count ( 1 ) ;
set_bus_name ( 0 , " Master " ) ;
2017-01-21 23:00:25 +01:00
2020-05-14 16:41:43 +02:00
if ( AudioDriver : : get_singleton ( ) ) {
2017-01-21 23:00:25 +01:00
AudioDriver : : get_singleton ( ) - > start ( ) ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_count ( 1 ) ;
2020-05-14 16:41:43 +02:00
}
2017-08-22 23:27:17 +02:00
2017-01-25 18:30:40 +01:00
# ifdef TOOLS_ENABLED
set_edited ( false ) ; //avoid editors from thinking this was edited
# endif
2017-09-14 22:45:02 +02:00
2021-02-17 17:44:49 +01:00
GLOBAL_DEF_RST ( " audio/video/video_delay_compensation_ms " , 0 ) ;
2017-01-15 20:06:14 +01:00
}
2017-01-25 18:30:40 +01:00
2018-06-21 02:02:02 +02:00
void AudioServer : : update ( ) {
# ifdef DEBUG_ENABLED
2020-02-27 03:30:20 +01:00
if ( EngineDebugger : : is_profiling ( " servers " ) ) {
2018-06-21 02:02:02 +02:00
// Driver time includes server time + effects times
// Server time includes effects times
uint64_t driver_time = AudioDriver : : get_singleton ( ) - > get_profiling_time ( ) ;
2024-02-06 04:29:44 +01:00
uint64_t server_time = prof_time . get ( ) ;
2018-06-21 02:02:02 +02:00
2019-02-13 09:23:29 +01:00
// Subtract the server time from the driver time
2020-05-14 16:41:43 +02:00
if ( driver_time > server_time ) {
2018-06-21 02:02:02 +02:00
driver_time - = server_time ;
2020-05-14 16:41:43 +02:00
}
2018-06-21 02:02:02 +02:00
Array values ;
for ( int i = buses . size ( ) - 1 ; i > = 0 ; i - - ) {
Bus * bus = buses [ i ] ;
2020-05-14 16:41:43 +02:00
if ( bus - > bypass ) {
2018-06-21 02:02:02 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-06-21 02:02:02 +02:00
for ( int j = 0 ; j < bus - > effects . size ( ) ; j + + ) {
2020-05-14 16:41:43 +02:00
if ( ! bus - > effects [ j ] . enabled ) {
2018-06-21 02:02:02 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-06-21 02:02:02 +02:00
values . push_back ( String ( bus - > name ) + bus - > effects [ j ] . effect - > get_name ( ) ) ;
values . push_back ( USEC_TO_SEC ( bus - > effects [ j ] . prof_time ) ) ;
2019-02-13 09:23:29 +01:00
// Subtract the effect time from the driver and server times
2020-05-14 16:41:43 +02:00
if ( driver_time > bus - > effects [ j ] . prof_time ) {
2018-06-21 02:02:02 +02:00
driver_time - = bus - > effects [ j ] . prof_time ;
2020-05-14 16:41:43 +02:00
}
if ( server_time > bus - > effects [ j ] . prof_time ) {
2018-06-21 02:02:02 +02:00
server_time - = bus - > effects [ j ] . prof_time ;
2020-05-14 16:41:43 +02:00
}
2018-06-21 02:02:02 +02:00
}
}
values . push_back ( " audio_server " ) ;
values . push_back ( USEC_TO_SEC ( server_time ) ) ;
values . push_back ( " audio_driver " ) ;
values . push_back ( USEC_TO_SEC ( driver_time ) ) ;
2020-02-27 03:30:20 +01:00
values . push_front ( " audio_thread " ) ;
EngineDebugger : : profiler_add_frame_data ( " servers " , values ) ;
2018-06-21 02:02:02 +02:00
}
// Reset profiling times
for ( int i = buses . size ( ) - 1 ; i > = 0 ; i - - ) {
Bus * bus = buses [ i ] ;
2020-05-14 16:41:43 +02:00
if ( bus - > bypass ) {
2018-06-21 02:02:02 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-06-21 02:02:02 +02:00
for ( int j = 0 ; j < bus - > effects . size ( ) ; j + + ) {
2020-05-14 16:41:43 +02:00
if ( ! bus - > effects [ j ] . enabled ) {
2018-06-21 02:02:02 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-06-21 02:02:02 +02:00
2018-07-25 03:11:03 +02:00
bus - > effects . write [ j ] . prof_time = 0 ;
2018-06-21 02:02:02 +02:00
}
}
AudioDriver : : get_singleton ( ) - > reset_profiling_time ( ) ;
2024-02-06 04:29:44 +01:00
prof_time . set ( 0 ) ;
2018-06-21 02:02:02 +02:00
# endif
2018-10-10 15:58:29 +02:00
2021-08-27 19:28:23 +02:00
for ( CallbackItem * ci : update_callback_list ) {
ci - > callback ( ci - > userdata ) ;
2018-10-10 15:58:29 +02:00
}
2021-08-27 19:28:23 +02:00
mix_callback_list . maybe_cleanup ( ) ;
update_callback_list . maybe_cleanup ( ) ;
listener_changed_callback_list . maybe_cleanup ( ) ;
playback_list . maybe_cleanup ( ) ;
2021-08-28 06:51:03 +02:00
for ( AudioStreamPlaybackBusDetails * bus_details : bus_details_graveyard_frame_old ) {
bus_details_graveyard_frame_old . erase ( bus_details , [ ] ( AudioStreamPlaybackBusDetails * d ) { delete d ; } ) ;
}
2021-08-27 19:28:23 +02:00
for ( AudioStreamPlaybackBusDetails * bus_details : bus_details_graveyard ) {
2021-08-28 06:51:03 +02:00
bus_details_graveyard_frame_old . insert ( bus_details ) ;
bus_details_graveyard . erase ( bus_details ) ;
2021-08-27 19:28:23 +02:00
}
bus_details_graveyard . maybe_cleanup ( ) ;
2021-08-28 06:51:03 +02:00
bus_details_graveyard_frame_old . maybe_cleanup ( ) ;
2018-06-21 02:02:02 +02:00
}
2017-01-25 18:30:40 +01:00
void AudioServer : : load_default_bus_layout ( ) {
2022-10-18 16:43:37 +02:00
String layout_path = GLOBAL_GET ( " audio/buses/default_bus_layout " ) ;
2019-04-05 17:19:25 +02:00
if ( ResourceLoader : : exists ( layout_path ) ) {
Ref < AudioBusLayout > default_layout = ResourceLoader : : load ( layout_path ) ;
2017-01-25 18:30:40 +01:00
if ( default_layout . is_valid ( ) ) {
set_bus_layout ( default_layout ) ;
}
}
}
2017-01-15 20:06:14 +01:00
void AudioServer : : finish ( ) {
2017-12-29 11:22:56 +01:00
for ( int i = 0 ; i < AudioDriverManager : : get_driver_count ( ) ; i + + ) {
AudioDriverManager : : get_driver ( i ) - > finish ( ) ;
}
2017-01-21 23:00:25 +01:00
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
memdelete ( buses [ i ] ) ;
}
2017-01-15 20:06:14 +01:00
buses . clear ( ) ;
}
2017-08-02 16:45:19 +02:00
2017-01-15 20:06:14 +01:00
/* MISC config */
2014-02-10 02:10:30 +01:00
2017-01-15 20:06:14 +01:00
void AudioServer : : lock ( ) {
AudioDriver : : get_singleton ( ) - > lock ( ) ;
}
2020-05-14 14:29:06 +02:00
2017-01-15 20:06:14 +01:00
void AudioServer : : unlock ( ) {
AudioDriver : : get_singleton ( ) - > unlock ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-01-15 20:06:14 +01:00
AudioServer : : SpeakerMode AudioServer : : get_speaker_mode ( ) const {
return ( AudioServer : : SpeakerMode ) AudioDriver : : get_singleton ( ) - > get_speaker_mode ( ) ;
}
2020-05-14 14:29:06 +02:00
2017-01-15 20:06:14 +01:00
float AudioServer : : get_mix_rate ( ) const {
return AudioDriver : : get_singleton ( ) - > get_mix_rate ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-01-15 20:06:14 +01:00
float AudioServer : : read_output_peak_db ( ) const {
return 0 ;
}
2014-02-10 02:10:30 +01:00
2017-01-15 20:06:14 +01:00
AudioServer * AudioServer : : get_singleton ( ) {
return singleton ;
}
2014-02-10 02:10:30 +01:00
2019-04-27 17:22:47 +02:00
double AudioServer : : get_output_latency ( ) const {
return AudioDriver : : get_singleton ( ) - > get_latency ( ) ;
2017-01-15 20:06:14 +01:00
}
2014-02-10 02:10:30 +01:00
2019-04-27 17:22:47 +02:00
double AudioServer : : get_time_to_next_mix ( ) const {
return AudioDriver : : get_singleton ( ) - > get_time_to_next_mix ( ) ;
2017-01-15 20:06:14 +01:00
}
2014-02-10 02:10:30 +01:00
2019-04-27 19:05:16 +02:00
double AudioServer : : get_time_since_last_mix ( ) const {
return AudioDriver : : get_singleton ( ) - > get_time_since_last_mix ( ) ;
}
2020-04-02 01:20:12 +02:00
AudioServer * AudioServer : : singleton = nullptr ;
2017-01-21 23:00:25 +01:00
2021-08-27 19:28:23 +02:00
void AudioServer : : add_update_callback ( AudioCallback p_callback , void * p_userdata ) {
CallbackItem * ci = new CallbackItem ( ) ;
ci - > callback = p_callback ;
ci - > userdata = p_userdata ;
update_callback_list . insert ( ci ) ;
2017-01-21 23:00:25 +01:00
}
2021-08-27 19:28:23 +02:00
void AudioServer : : remove_update_callback ( AudioCallback p_callback , void * p_userdata ) {
for ( CallbackItem * ci : update_callback_list ) {
if ( ci - > callback = = p_callback & & ci - > userdata = = p_userdata ) {
update_callback_list . erase ( ci , [ ] ( CallbackItem * c ) { delete c ; } ) ;
}
}
2017-01-21 23:00:25 +01:00
}
2021-08-27 19:28:23 +02:00
void AudioServer : : add_mix_callback ( AudioCallback p_callback , void * p_userdata ) {
CallbackItem * ci = new CallbackItem ( ) ;
ci - > callback = p_callback ;
ci - > userdata = p_userdata ;
mix_callback_list . insert ( ci ) ;
2018-10-10 15:58:29 +02:00
}
2021-08-27 19:28:23 +02:00
void AudioServer : : remove_mix_callback ( AudioCallback p_callback , void * p_userdata ) {
for ( CallbackItem * ci : mix_callback_list ) {
if ( ci - > callback = = p_callback & & ci - > userdata = = p_userdata ) {
mix_callback_list . erase ( ci , [ ] ( CallbackItem * c ) { delete c ; } ) ;
}
}
}
void AudioServer : : add_listener_changed_callback ( AudioCallback p_callback , void * p_userdata ) {
CallbackItem * ci = new CallbackItem ( ) ;
ci - > callback = p_callback ;
ci - > userdata = p_userdata ;
listener_changed_callback_list . insert ( ci ) ;
}
void AudioServer : : remove_listener_changed_callback ( AudioCallback p_callback , void * p_userdata ) {
for ( CallbackItem * ci : listener_changed_callback_list ) {
if ( ci - > callback = = p_callback & & ci - > userdata = = p_userdata ) {
listener_changed_callback_list . erase ( ci , [ ] ( CallbackItem * c ) { delete c ; } ) ;
}
}
2018-10-10 15:58:29 +02:00
}
2017-03-13 16:45:27 +01:00
void AudioServer : : set_bus_layout ( const Ref < AudioBusLayout > & p_bus_layout ) {
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND ( p_bus_layout . is_null ( ) | | p_bus_layout - > buses . is_empty ( ) ) ;
2017-01-25 18:30:40 +01:00
lock ( ) ;
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
memdelete ( buses [ i ] ) ;
}
2017-03-13 16:45:27 +01:00
buses . resize ( p_bus_layout - > buses . size ( ) ) ;
2017-01-25 18:30:40 +01:00
bus_map . clear ( ) ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_count ( buses . size ( ) ) ;
2017-03-13 16:45:27 +01:00
for ( int i = 0 ; i < p_bus_layout - > buses . size ( ) ; i + + ) {
2017-01-25 18:30:40 +01:00
Bus * bus = memnew ( Bus ) ;
if ( i = = 0 ) {
2023-09-04 17:01:33 +02:00
bus - > name = SceneStringName ( Master ) ;
2017-01-25 18:30:40 +01:00
} else {
2017-03-13 16:45:27 +01:00
bus - > name = p_bus_layout - > buses [ i ] . name ;
bus - > send = p_bus_layout - > buses [ i ] . send ;
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_send ( i , bus - > send ) ;
2017-01-25 18:30:40 +01:00
}
2017-03-13 16:45:27 +01:00
bus - > solo = p_bus_layout - > buses [ i ] . solo ;
bus - > mute = p_bus_layout - > buses [ i ] . mute ;
bus - > bypass = p_bus_layout - > buses [ i ] . bypass ;
bus - > volume_db = p_bus_layout - > buses [ i ] . volume_db ;
2017-01-25 18:30:40 +01:00
2024-04-18 16:50:34 +02:00
AudioDriver : : get_singleton ( ) - > set_sample_bus_solo ( i , bus - > solo ) ;
AudioDriver : : get_singleton ( ) - > set_sample_bus_mute ( i , bus - > mute ) ;
AudioDriver : : get_singleton ( ) - > set_sample_bus_volume_db ( i , bus - > volume_db ) ;
2017-03-13 16:45:27 +01:00
for ( int j = 0 ; j < p_bus_layout - > buses [ i ] . effects . size ( ) ; j + + ) {
Ref < AudioEffect > fx = p_bus_layout - > buses [ i ] . effects [ j ] . effect ;
2017-01-25 18:30:40 +01:00
if ( fx . is_valid ( ) ) {
Bus : : Effect bfx ;
bfx . effect = fx ;
2017-03-13 16:45:27 +01:00
bfx . enabled = p_bus_layout - > buses [ i ] . effects [ j ] . enabled ;
2021-12-22 08:15:12 +01:00
# ifdef DEBUG_ENABLED
2021-05-25 17:03:12 +02:00
bfx . prof_time = 0 ;
# endif
2017-01-25 18:30:40 +01:00
bus - > effects . push_back ( bfx ) ;
}
}
bus_map [ bus - > name ] = bus ;
2018-07-25 03:11:03 +02:00
buses . write [ i ] = bus ;
2017-01-25 18:30:40 +01:00
2018-03-18 02:43:32 +01:00
buses [ i ] - > channels . resize ( channel_count ) ;
for ( int j = 0 ; j < channel_count ; j + + ) {
2018-07-25 03:11:03 +02:00
buses . write [ i ] - > channels . write [ j ] . buffer . resize ( buffer_size ) ;
2017-01-25 18:30:40 +01:00
}
_update_bus_effects ( i ) ;
}
# ifdef TOOLS_ENABLED
set_edited ( false ) ;
# endif
unlock ( ) ;
2024-04-18 16:50:34 +02:00
// Samples bus sync.
2017-01-25 18:30:40 +01:00
}
Ref < AudioBusLayout > AudioServer : : generate_bus_layout ( ) const {
Ref < AudioBusLayout > state ;
2021-06-18 00:03:09 +02:00
state . instantiate ( ) ;
2017-01-25 18:30:40 +01:00
state - > buses . resize ( buses . size ( ) ) ;
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
state - > buses . write [ i ] . name = buses [ i ] - > name ;
state - > buses . write [ i ] . send = buses [ i ] - > send ;
state - > buses . write [ i ] . mute = buses [ i ] - > mute ;
state - > buses . write [ i ] . solo = buses [ i ] - > solo ;
state - > buses . write [ i ] . bypass = buses [ i ] - > bypass ;
state - > buses . write [ i ] . volume_db = buses [ i ] - > volume_db ;
2017-01-25 18:30:40 +01:00
for ( int j = 0 ; j < buses [ i ] - > effects . size ( ) ; j + + ) {
AudioBusLayout : : Bus : : Effect fx ;
fx . effect = buses [ i ] - > effects [ j ] . effect ;
fx . enabled = buses [ i ] - > effects [ j ] . enabled ;
2018-07-25 03:11:03 +02:00
state - > buses . write [ i ] . effects . push_back ( fx ) ;
2017-01-25 18:30:40 +01:00
}
}
return state ;
}
2022-11-24 15:41:40 +01:00
PackedStringArray AudioServer : : get_output_device_list ( ) {
return AudioDriver : : get_singleton ( ) - > get_output_device_list ( ) ;
2018-03-25 05:43:51 +02:00
}
2022-11-24 15:41:40 +01:00
String AudioServer : : get_output_device ( ) {
return AudioDriver : : get_singleton ( ) - > get_output_device ( ) ;
2018-03-25 05:43:51 +02:00
}
2023-02-08 16:40:15 +01:00
void AudioServer : : set_output_device ( const String & p_name ) {
AudioDriver : : get_singleton ( ) - > set_output_device ( p_name ) ;
2018-03-25 05:43:51 +02:00
}
2022-11-24 15:41:40 +01:00
PackedStringArray AudioServer : : get_input_device_list ( ) {
return AudioDriver : : get_singleton ( ) - > get_input_device_list ( ) ;
2018-02-27 08:54:56 +01:00
}
2022-11-24 15:41:40 +01:00
String AudioServer : : get_input_device ( ) {
return AudioDriver : : get_singleton ( ) - > get_input_device ( ) ;
2018-02-27 08:54:56 +01:00
}
2022-11-24 15:41:40 +01:00
void AudioServer : : set_input_device ( const String & p_name ) {
AudioDriver : : get_singleton ( ) - > set_input_device ( p_name ) ;
2018-02-27 08:54:56 +01:00
}
2022-07-21 01:00:58 +02:00
void AudioServer : : set_enable_tagging_used_audio_streams ( bool p_enable ) {
tag_used_audio_streams = p_enable ;
}
2024-01-04 00:20:55 +01:00
# ifdef TOOLS_ENABLED
void AudioServer : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
const String pf = p_function ;
if ( ( p_idx = = 0 & & pf = = " get_bus_index " ) | | ( p_idx = = 1 & & pf = = " set_bus_send " ) ) {
for ( const AudioServer : : Bus * E : buses ) {
r_options - > push_back ( String ( E - > name ) . quote ( ) ) ;
}
}
Object : : get_argument_options ( p_function , p_idx , r_options ) ;
}
# endif
2024-04-18 16:50:34 +02:00
AudioServer : : PlaybackType AudioServer : : get_default_playback_type ( ) const {
int playback_type = GLOBAL_GET ( " audio/general/default_playback_type " ) ;
ERR_FAIL_COND_V_MSG (
playback_type < 0 | | playback_type > = PlaybackType : : PLAYBACK_TYPE_MAX ,
PlaybackType : : PLAYBACK_TYPE_STREAM ,
vformat ( R " (Project settings value (%s) for " audio / general / default_playback_type " is not supported) " , playback_type ) ) ;
switch ( playback_type ) {
case 1 : {
return PlaybackType : : PLAYBACK_TYPE_SAMPLE ;
} break ;
case 0 :
default : {
return PlaybackType : : PLAYBACK_TYPE_STREAM ;
} break ;
}
}
bool AudioServer : : is_stream_registered_as_sample ( const Ref < AudioStream > & p_stream ) {
ERR_FAIL_COND_V_MSG ( p_stream . is_null ( ) , false , " Parameter p_stream is null. " ) ;
return AudioDriver : : get_singleton ( ) - > is_stream_registered_as_sample ( p_stream ) ;
}
void AudioServer : : register_stream_as_sample ( const Ref < AudioStream > & p_stream ) {
ERR_FAIL_COND_MSG ( p_stream . is_null ( ) , " Parameter p_stream is null. " ) ;
ERR_FAIL_COND_MSG ( ! ( p_stream - > can_be_sampled ( ) ) , " Parameter p_stream cannot be sampled. " ) ;
Ref < AudioSample > sample = p_stream - > generate_sample ( ) ;
register_sample ( sample ) ;
}
void AudioServer : : unregister_stream_as_sample ( const Ref < AudioStream > & p_stream ) {
ERR_FAIL_COND_MSG ( p_stream . is_null ( ) , " Parameter p_stream is null. " ) ;
ERR_FAIL_COND_MSG ( ! ( p_stream - > can_be_sampled ( ) ) , " Parameter p_stream cannot be sampled. " ) ;
Ref < AudioSample > sample = p_stream - > generate_sample ( ) ;
unregister_sample ( sample ) ;
}
void AudioServer : : register_sample ( const Ref < AudioSample > & p_sample ) {
ERR_FAIL_COND_MSG ( p_sample . is_null ( ) , " Parameter p_sample is null. " ) ;
ERR_FAIL_COND_MSG ( p_sample - > stream . is_null ( ) , " Parameter p_sample->stream is null. " ) ;
ERR_FAIL_COND_MSG ( ! ( p_sample - > stream - > can_be_sampled ( ) ) , " Parameter p_stream cannot be sampled. " ) ;
AudioDriver : : get_singleton ( ) - > register_sample ( p_sample ) ;
}
void AudioServer : : unregister_sample ( const Ref < AudioSample > & p_sample ) {
ERR_FAIL_COND_MSG ( p_sample . is_null ( ) , " Parameter p_sample is null. " ) ;
ERR_FAIL_COND_MSG ( p_sample - > stream . is_null ( ) , " Parameter p_sample->stream is null. " ) ;
AudioDriver : : get_singleton ( ) - > unregister_sample ( p_sample ) ;
}
void AudioServer : : start_sample_playback ( const Ref < AudioSamplePlayback > & p_playback ) {
ERR_FAIL_COND_MSG ( p_playback . is_null ( ) , " Parameter p_playback is null. " ) ;
AudioDriver : : get_singleton ( ) - > start_sample_playback ( p_playback ) ;
2024-07-12 16:49:59 +02:00
sample_playback_list . ordered_insert ( p_playback ) ;
2024-04-18 16:50:34 +02:00
}
void AudioServer : : stop_sample_playback ( const Ref < AudioSamplePlayback > & p_playback ) {
ERR_FAIL_COND_MSG ( p_playback . is_null ( ) , " Parameter p_playback is null. " ) ;
AudioDriver : : get_singleton ( ) - > stop_sample_playback ( p_playback ) ;
2024-07-12 16:49:59 +02:00
sample_playback_list . erase ( p_playback ) ;
2024-04-18 16:50:34 +02:00
}
void AudioServer : : set_sample_playback_pause ( const Ref < AudioSamplePlayback > & p_playback , bool p_paused ) {
ERR_FAIL_COND_MSG ( p_playback . is_null ( ) , " Parameter p_playback is null. " ) ;
AudioDriver : : get_singleton ( ) - > set_sample_playback_pause ( p_playback , p_paused ) ;
}
bool AudioServer : : is_sample_playback_active ( const Ref < AudioSamplePlayback > & p_playback ) {
ERR_FAIL_COND_V_MSG ( p_playback . is_null ( ) , false , " Parameter p_playback is null. " ) ;
return AudioDriver : : get_singleton ( ) - > is_sample_playback_active ( p_playback ) ;
}
2024-08-06 15:46:37 +02:00
double AudioServer : : get_sample_playback_position ( const Ref < AudioSamplePlayback > & p_playback ) {
ERR_FAIL_COND_V_MSG ( p_playback . is_null ( ) , false , " Parameter p_playback is null. " ) ;
return AudioDriver : : get_singleton ( ) - > get_sample_playback_position ( p_playback ) ;
}
2024-04-18 16:50:34 +02:00
void AudioServer : : update_sample_playback_pitch_scale ( const Ref < AudioSamplePlayback > & p_playback , float p_pitch_scale ) {
ERR_FAIL_COND_MSG ( p_playback . is_null ( ) , " Parameter p_playback is null. " ) ;
return AudioDriver : : get_singleton ( ) - > update_sample_playback_pitch_scale ( p_playback , p_pitch_scale ) ;
}
2017-01-21 23:00:25 +01:00
void AudioServer : : _bind_methods ( ) {
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_count " , " amount " ) , & AudioServer : : set_bus_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_bus_count " ) , & AudioServer : : get_bus_count ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " remove_bus " , " index " ) , & AudioServer : : remove_bus ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_bus " , " at_position " ) , & AudioServer : : add_bus , DEFVAL ( - 1 ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " move_bus " , " index " , " to_index " ) , & AudioServer : : move_bus ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_name " , " bus_idx " , " name " ) , & AudioServer : : set_bus_name ) ;
ClassDB : : bind_method ( D_METHOD ( " get_bus_name " , " bus_idx " ) , & AudioServer : : get_bus_name ) ;
2017-07-10 22:51:29 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_bus_index " , " bus_name " ) , & AudioServer : : get_bus_index ) ;
2017-01-24 03:12:08 +01:00
2018-12-07 17:38:40 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_bus_channels " , " bus_idx " ) , & AudioServer : : get_bus_channels ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_volume_db " , " bus_idx " , " volume_db " ) , & AudioServer : : set_bus_volume_db ) ;
ClassDB : : bind_method ( D_METHOD ( " get_bus_volume_db " , " bus_idx " ) , & AudioServer : : get_bus_volume_db ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_send " , " bus_idx " , " send " ) , & AudioServer : : set_bus_send ) ;
ClassDB : : bind_method ( D_METHOD ( " get_bus_send " , " bus_idx " ) , & AudioServer : : get_bus_send ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_solo " , " bus_idx " , " enable " ) , & AudioServer : : set_bus_solo ) ;
ClassDB : : bind_method ( D_METHOD ( " is_bus_solo " , " bus_idx " ) , & AudioServer : : is_bus_solo ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_mute " , " bus_idx " , " enable " ) , & AudioServer : : set_bus_mute ) ;
ClassDB : : bind_method ( D_METHOD ( " is_bus_mute " , " bus_idx " ) , & AudioServer : : is_bus_mute ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_bypass_effects " , " bus_idx " , " enable " ) , & AudioServer : : set_bus_bypass_effects ) ;
ClassDB : : bind_method ( D_METHOD ( " is_bus_bypassing_effects " , " bus_idx " ) , & AudioServer : : is_bus_bypassing_effects ) ;
2017-01-21 23:00:25 +01:00
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_bus_effect " , " bus_idx " , " effect " , " at_position " ) , & AudioServer : : add_bus_effect , DEFVAL ( - 1 ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " remove_bus_effect " , " bus_idx " , " effect_idx " ) , & AudioServer : : remove_bus_effect ) ;
2017-01-21 23:00:25 +01:00
2017-07-18 21:03:34 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_bus_effect_count " , " bus_idx " ) , & AudioServer : : get_bus_effect_count ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_bus_effect " , " bus_idx " , " effect_idx " ) , & AudioServer : : get_bus_effect ) ;
2019-04-10 17:57:03 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_bus_effect_instance " , " bus_idx " , " effect_idx " , " channel " ) , & AudioServer : : get_bus_effect_instance , DEFVAL ( 0 ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " swap_bus_effects " , " bus_idx " , " effect_idx " , " by_effect_idx " ) , & AudioServer : : swap_bus_effects ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_effect_enabled " , " bus_idx " , " effect_idx " , " enabled " ) , & AudioServer : : set_bus_effect_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_bus_effect_enabled " , " bus_idx " , " effect_idx " ) , & AudioServer : : is_bus_effect_enabled ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_bus_peak_volume_left_db " , " bus_idx " , " channel " ) , & AudioServer : : get_bus_peak_volume_left_db ) ;
ClassDB : : bind_method ( D_METHOD ( " get_bus_peak_volume_right_db " , " bus_idx " , " channel " ) , & AudioServer : : get_bus_peak_volume_right_db ) ;
2017-01-21 23:00:25 +01:00
2020-05-07 18:46:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_playback_speed_scale " , " scale " ) , & AudioServer : : set_playback_speed_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_playback_speed_scale " ) , & AudioServer : : get_playback_speed_scale ) ;
2019-06-03 01:01:42 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " lock " ) , & AudioServer : : lock ) ;
ClassDB : : bind_method ( D_METHOD ( " unlock " ) , & AudioServer : : unlock ) ;
2017-01-21 23:00:25 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_speaker_mode " ) , & AudioServer : : get_speaker_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_mix_rate " ) , & AudioServer : : get_mix_rate ) ;
2023-02-08 16:40:15 +01:00
2022-11-24 15:41:40 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_output_device_list " ) , & AudioServer : : get_output_device_list ) ;
ClassDB : : bind_method ( D_METHOD ( " get_output_device " ) , & AudioServer : : get_output_device ) ;
2023-02-08 16:40:15 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_output_device " , " name " ) , & AudioServer : : set_output_device ) ;
2017-01-21 23:00:25 +01:00
2019-04-27 17:22:47 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_time_to_next_mix " ) , & AudioServer : : get_time_to_next_mix ) ;
2019-04-27 19:05:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_time_since_last_mix " ) , & AudioServer : : get_time_since_last_mix ) ;
2019-04-27 17:22:47 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_output_latency " ) , & AudioServer : : get_output_latency ) ;
2022-11-24 15:41:40 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_input_device_list " ) , & AudioServer : : get_input_device_list ) ;
ClassDB : : bind_method ( D_METHOD ( " get_input_device " ) , & AudioServer : : get_input_device ) ;
ClassDB : : bind_method ( D_METHOD ( " set_input_device " , " name " ) , & AudioServer : : set_input_device ) ;
2018-07-25 20:35:52 +02:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_bus_layout " , " bus_layout " ) , & AudioServer : : set_bus_layout ) ;
ClassDB : : bind_method ( D_METHOD ( " generate_bus_layout " ) , & AudioServer : : generate_bus_layout ) ;
2017-01-21 23:00:25 +01:00
2022-07-21 01:00:58 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_enable_tagging_used_audio_streams " , " enable " ) , & AudioServer : : set_enable_tagging_used_audio_streams ) ;
2024-04-18 16:50:34 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_stream_registered_as_sample " , " stream " ) , & AudioServer : : is_stream_registered_as_sample ) ;
ClassDB : : bind_method ( D_METHOD ( " register_stream_as_sample " , " stream " ) , & AudioServer : : register_stream_as_sample ) ;
2019-06-03 01:01:42 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " bus_count " ) , " set_bus_count " , " get_bus_count " ) ;
2022-11-24 15:41:40 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " output_device " ) , " set_output_device " , " get_output_device " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " input_device " ) , " set_input_device " , " get_input_device " ) ;
2022-02-14 18:09:09 +01:00
// The default value may be set to an empty string by the platform-specific audio driver.
// Override for class reference generation purposes.
2022-11-24 15:41:40 +01:00
ADD_PROPERTY_DEFAULT ( " input_device " , " Default " ) ;
2020-05-07 18:46:33 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " playback_speed_scale " ) , " set_playback_speed_scale " , " get_playback_speed_scale " ) ;
2019-06-03 01:01:42 +02:00
2017-01-21 23:00:25 +01:00
ADD_SIGNAL ( MethodInfo ( " bus_layout_changed " ) ) ;
2023-09-14 12:39:23 +02:00
ADD_SIGNAL ( MethodInfo ( " bus_renamed " , PropertyInfo ( Variant : : INT , " bus_index " ) , PropertyInfo ( Variant : : STRING_NAME , " old_name " ) , PropertyInfo ( Variant : : STRING_NAME , " new_name " ) ) ) ;
2017-09-12 21:09:06 +02:00
BIND_ENUM_CONSTANT ( SPEAKER_MODE_STEREO ) ;
2018-10-09 02:33:51 +02:00
BIND_ENUM_CONSTANT ( SPEAKER_SURROUND_31 ) ;
2017-09-12 21:09:06 +02:00
BIND_ENUM_CONSTANT ( SPEAKER_SURROUND_51 ) ;
BIND_ENUM_CONSTANT ( SPEAKER_SURROUND_71 ) ;
2024-04-18 16:50:34 +02:00
BIND_ENUM_CONSTANT ( PLAYBACK_TYPE_DEFAULT ) ;
BIND_ENUM_CONSTANT ( PLAYBACK_TYPE_STREAM ) ;
BIND_ENUM_CONSTANT ( PLAYBACK_TYPE_SAMPLE ) ;
BIND_ENUM_CONSTANT ( PLAYBACK_TYPE_MAX ) ;
2017-01-21 23:00:25 +01:00
}
2017-01-15 20:06:14 +01:00
2014-02-10 02:10:30 +01:00
AudioServer : : AudioServer ( ) {
singleton = this ;
}
AudioServer : : ~ AudioServer ( ) {
2020-04-02 01:20:12 +02:00
singleton = nullptr ;
2014-02-10 02:10:30 +01:00
}
2017-01-15 20:06:14 +01:00
2017-01-25 18:30:40 +01:00
/////////////////////////////////
bool AudioBusLayout : : _set ( const StringName & p_name , const Variant & p_value ) {
String s = p_name ;
if ( s . begins_with ( " bus/ " ) ) {
int index = s . get_slice ( " / " , 1 ) . to_int ( ) ;
if ( buses . size ( ) < = index ) {
buses . resize ( index + 1 ) ;
}
2018-07-25 03:11:03 +02:00
Bus & bus = buses . write [ index ] ;
2017-01-25 18:30:40 +01:00
String what = s . get_slice ( " / " , 2 ) ;
2017-03-05 16:44:50 +01:00
2017-01-25 18:30:40 +01:00
if ( what = = " name " ) {
bus . name = p_value ;
} else if ( what = = " solo " ) {
bus . solo = p_value ;
} else if ( what = = " mute " ) {
bus . mute = p_value ;
} else if ( what = = " bypass_fx " ) {
bus . bypass = p_value ;
} else if ( what = = " volume_db " ) {
bus . volume_db = p_value ;
} else if ( what = = " send " ) {
bus . send = p_value ;
} else if ( what = = " effect " ) {
int which = s . get_slice ( " / " , 3 ) . to_int ( ) ;
if ( bus . effects . size ( ) < = which ) {
bus . effects . resize ( which + 1 ) ;
}
2018-07-25 03:11:03 +02:00
Bus : : Effect & fx = bus . effects . write [ which ] ;
2017-01-25 18:30:40 +01:00
String fxwhat = s . get_slice ( " / " , 4 ) ;
if ( fxwhat = = " effect " ) {
fx . effect = p_value ;
} else if ( fxwhat = = " enabled " ) {
fx . enabled = p_value ;
} else {
return false ;
}
return true ;
} else {
return false ;
}
return true ;
}
return false ;
}
bool AudioBusLayout : : _get ( const StringName & p_name , Variant & r_ret ) const {
String s = p_name ;
if ( s . begins_with ( " bus/ " ) ) {
int index = s . get_slice ( " / " , 1 ) . to_int ( ) ;
2020-05-14 16:41:43 +02:00
if ( index < 0 | | index > = buses . size ( ) ) {
2017-01-25 18:30:40 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2017-01-25 18:30:40 +01:00
const Bus & bus = buses [ index ] ;
String what = s . get_slice ( " / " , 2 ) ;
2017-03-05 16:44:50 +01:00
2017-01-25 18:30:40 +01:00
if ( what = = " name " ) {
r_ret = bus . name ;
} else if ( what = = " solo " ) {
r_ret = bus . solo ;
} else if ( what = = " mute " ) {
r_ret = bus . mute ;
} else if ( what = = " bypass_fx " ) {
r_ret = bus . bypass ;
} else if ( what = = " volume_db " ) {
r_ret = bus . volume_db ;
} else if ( what = = " send " ) {
r_ret = bus . send ;
} else if ( what = = " effect " ) {
int which = s . get_slice ( " / " , 3 ) . to_int ( ) ;
if ( which < 0 | | which > = bus . effects . size ( ) ) {
return false ;
}
const Bus : : Effect & fx = bus . effects [ which ] ;
String fxwhat = s . get_slice ( " / " , 4 ) ;
if ( fxwhat = = " effect " ) {
r_ret = fx . effect ;
} else if ( fxwhat = = " enabled " ) {
r_ret = fx . enabled ;
} else {
return false ;
}
return true ;
} else {
return false ;
}
return true ;
}
return false ;
}
2020-05-14 14:29:06 +02:00
2017-01-25 18:30:40 +01:00
void AudioBusLayout : : _get_property_list ( List < PropertyInfo > * p_list ) const {
for ( int i = 0 ; i < buses . size ( ) ; i + + ) {
2021-11-03 23:06:17 +01:00
p_list - > push_back ( PropertyInfo ( Variant : : STRING , " bus/ " + itos ( i ) + " /name " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " bus/ " + itos ( i ) + " /solo " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " bus/ " + itos ( i ) + " /mute " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " bus/ " + itos ( i ) + " /bypass_fx " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : FLOAT , " bus/ " + itos ( i ) + " /volume_db " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : FLOAT , " bus/ " + itos ( i ) + " /send " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
2017-01-25 18:30:40 +01:00
for ( int j = 0 ; j < buses [ i ] . effects . size ( ) ; j + + ) {
2021-11-03 23:06:17 +01:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " bus/ " + itos ( i ) + " /effect/ " + itos ( j ) + " /effect " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " bus/ " + itos ( i ) + " /effect/ " + itos ( j ) + " /enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
2017-01-25 18:30:40 +01:00
}
}
}
AudioBusLayout : : AudioBusLayout ( ) {
buses . resize ( 1 ) ;
2023-09-04 17:01:33 +02:00
buses . write [ 0 ] . name = SceneStringName ( Master ) ;
2017-01-25 18:30:40 +01:00
}