mackron / miniaudio

Audio playback and capture library written in C, in a single source file.
https://miniaud.io
Other
4.07k stars 361 forks source link

Sound effects cannot be repeated? #517

Closed paulross80 closed 2 years ago

paulross80 commented 2 years ago

Hello, I'm making a C++ game under Linux, kernel 5.15 LTS Everything is initialized correctly. I've noticed that when the player fires the gun, the sound plays, but if the enemy is also shooting, the sound of their gun is not heard (it is the same ma_sound object). The sound is played by both entities, but the new sound starts only when the previous finished playing. I'm reading the documentation again, and the reddit, but I cannot find an example of repeating sounds. Here is my initialization code:

` // Initialize the audio context // Use default backend priorities audioContextInitResult = ma_context_init(nullptr, 0U, nullptr, &audioContext);

if (audioContextInitResult != MA_SUCCESS)
    // "Cannot create audio context!"

// Enumerate playback devices
ma_device_info* playbackDevicesInfo;
ma_uint32 playbackDevicesCount;

if (ma_context_get_devices(&audioContext, &playbackDevicesInfo, &playbackDevicesCount, nullptr, nullptr) != MA_SUCCESS)
{
    ma_context_uninit(&audioContext);
    // "Cannot enumerate audio playback devices!"
}

// for (ma_uint32 device = 0U; device < playbackDevicesCount; device++) // fmt::print(" - audio device: {}, name: ${}$, default? {}\n", device, playbackDevicesInfo[device].name, playbackDevicesInfo[device].isDefault);

// Playback device configuration
ma_device_config audioDeviceConfig = ma_device_config_init(ma_device_type_playback);

// Choose specific device (optional)
// ma_device_id depends on the selected backend
// (may be a number, or a string, or whatever)
audioDeviceConfig.playback.pDeviceID = &playbackDevicesInfo[deviceIndex].id;
// Set to ma_format_unknown to use the device's native format
audioDeviceConfig.playback.format = ma_format_f32;
// Set to 0 to use the device's native channel count
audioDeviceConfig.playback.channels = channels;
// Set to 0 to use the device's native sample rate
audioDeviceConfig.sampleRate = sampleRate;
// This function will be called when miniaudio needs more data
audioDeviceConfig.dataCallback = audioCallback;
// User data can be accessed from the device object
audioDeviceConfig.pUserData = &audioEngine;

// Initialize the audio device (using context)
if (ma_device_init(&audioContext, &audioDeviceConfig, &audioDevice) != MA_SUCCESS)
{
    // "Cannot initialize audio device #{} ({})", deviceIndex, playbackDevicesInfo[deviceIndex].name
}

// Audio engine configuration
auto audioEngineConfig = ma_engine_config_init();
// Use the selected playback device
// NOTE: if you specify a device, you must manually call ma_engine_read_pcm_frames from the callback!
audioEngineConfig.pDevice = &audioDevice;
// You can specify a custom resource manager here!
// audioEngineConfig.pResourceManager = &myCustomResourceManager;

// This creates an engine instance which will initialize a device and
// a resource manager (unless you specified your own)
// The engine itself is also a node graph
// First parameter can be a pointer to a ma_engine_config struct or nullptr
if (ma_engine_init(&audioEngineConfig, &audioEngine) != MA_SUCCESS)
    // "Cannot initialize audio engine for the selected playback device!"

// Audio Engine:
// - The master volume of the engine can be controlled with ma_engine_set_volume(engine, float) which
//   takes a linear scale, with 0 resulting in silence and anything above 1 resulting in amplification
ma_engine_set_volume(&audioEngine, m_masterVolume);
// - Configure listeners, up to MA_ENGINE_MAX_LISTENERS
//   audioEngineConfig.listenerCount = 2U;
// - Position listener in 3D space:
//   ma_engine_listener_set_position(&engine, listenerIndex, worldPosX, worldPosY, worldPosZ);
//   ma_engine_listener_set_direction(&engine, listenerIndex, forwardX, forwardY, forwardZ);
//   ma_engine_listener_set_world_up(&engine, listenerIndex, 0, 1, 0);
//   ma_engine_listener_set_cone(&engine, listenerIndex, innerAngleInRadians, outerAngleInRadians, outerGain);

// To get the resource manager instance that the engine created for us:
// auto resManager = ma_engine_get_resource_manager(&m_audioEngine);

// A sound group is just a sound without a data source
if (ma_sound_group_init(&audioEngine, 0U, nullptr, &soundGroup) != MA_SUCCESS)
    // "Cannot create sound group!"

// Set sound group volume
ma_sound_group_set_volume(&soundGroup, volume);

` Is it possible to repeat sounds?

wini3d commented 2 years ago

had the same or related issue earlier and this is quite common, you should use ma_sound_seek_to_pcm_frame and set it to 0 to repeat the same sound resource without creating new ones. https://github.com/mackron/miniaudio/issues/516

mackron commented 2 years ago

Moving this to the discussion section.

You need a separate ma_sound object for every instance of the sound you want to play simultaneously. The resource manager will ensure the sound data is only loaded once, but keep in mind the reference counting system that automatically unloads sounds (section 6.2.2 in the documentation): https://miniaud.io/docs/manual/#ResourceManagement

A common technique is to load all of your sounds initially at load time and store a cache of ma_sound objects. Then whenever you need to play a sound, use ma_sound_init_copy().