Changeset - r26535:bbf17c1357f1
[Not reviewed]
master
0 1 0
Jonathan G Rennison - 22 months ago 2022-11-07 21:19:06
j.g.rennison@gmail.com
Fix: Data races on MixerChannel active states
1 file changed with 24 insertions and 24 deletions:
0 comments (0 inline, 0 general)
src/mixer.cpp
Show inline comments
 
@@ -7,22 +7,21 @@
 

	
 
/** @file mixer.cpp Mixing of sound samples. */
 

	
 
#include "stdafx.h"
 
#include <math.h>
 
#include <mutex>
 
#include <atomic>
 
#include "core/math_func.hpp"
 
#include "framerate_type.h"
 
#include "settings_type.h"
 

	
 
#include "safeguards.h"
 
#include "mixer.h"
 

	
 
struct MixerChannel {
 
	bool active;
 

	
 
	/* pointer to allocated buffer memory */
 
	int8 *memory;
 

	
 
	/* current position in memory */
 
	uint32 pos;
 
	uint32 frac_pos;
 
@@ -33,12 +32,13 @@ struct MixerChannel {
 
	int volume_left;
 
	int volume_right;
 

	
 
	bool is16bit;
 
};
 

	
 
static std::atomic<uint8> _active_channels;
 
static MixerChannel _channels[8];
 
static uint32 _play_rate = 11025;
 
static uint32 _max_size = UINT_MAX;
 
static MxStreamCallback _music_stream = nullptr;
 
static std::mutex _music_stream_mutex;
 

	
 
@@ -132,28 +132,26 @@ static void mix_int8_to_int16(MixerChann
 
	}
 

	
 
	sc->frac_pos = frac_pos;
 
	sc->pos = b - sc->memory;
 
}
 

	
 
static void MxCloseChannel(MixerChannel *mc)
 
static void MxCloseChannel(uint8 channel_index)
 
{
 
	mc->active = false;
 
	_active_channels.fetch_and(~(1 << channel_index), std::memory_order_release);
 
}
 

	
 
void MxMixSamples(void *buffer, uint samples)
 
{
 
	PerformanceMeasurer framerate(PFE_SOUND);
 
	static uint last_samples = 0;
 
	if (samples != last_samples) {
 
		framerate.SetExpectedRate((double)_play_rate / samples);
 
		last_samples = samples;
 
	}
 

	
 
	MixerChannel *mc;
 

	
 
	/* Clear the buffer */
 
	memset(buffer, 0, sizeof(int16) * 2 * samples);
 

	
 
	{
 
		std::lock_guard<std::mutex> lock{ _music_stream_mutex };
 
		/* Fetch music if a sampled stream is available */
 
@@ -166,35 +164,36 @@ void MxMixSamples(void *buffer, uint sam
 
	 * get back into range. */
 
	uint8 effect_vol = (_settings_client.music.effect_vol *
 
	                    _settings_client.music.effect_vol *
 
	                    _settings_client.music.effect_vol) / (127 * 127);
 

	
 
	/* Mix each channel */
 
	for (mc = _channels; mc != endof(_channels); mc++) {
 
		if (mc->active) {
 
			if (mc->is16bit) {
 
				mix_int16(mc, (int16*)buffer, samples, effect_vol);
 
			} else {
 
				mix_int8_to_int16(mc, (int16*)buffer, samples, effect_vol);
 
			}
 
			if (mc->samples_left == 0) MxCloseChannel(mc);
 
	uint8 active = _active_channels.load(std::memory_order_acquire);
 
	for (uint8 idx : SetBitIterator(active)) {
 
		MixerChannel *mc = &_channels[idx];
 
		if (mc->is16bit) {
 
			mix_int16(mc, (int16*)buffer, samples, effect_vol);
 
		} else {
 
			mix_int8_to_int16(mc, (int16*)buffer, samples, effect_vol);
 
		}
 
		if (mc->samples_left == 0) MxCloseChannel(idx);
 
	}
 
}
 

	
 
MixerChannel *MxAllocateChannel()
 
{
 
	MixerChannel *mc;
 
	for (mc = _channels; mc != endof(_channels); mc++) {
 
		if (!mc->active) {
 
			free(mc->memory);
 
			mc->memory = nullptr;
 
			return mc;
 
		}
 
	}
 
	return nullptr;
 
	uint8 currently_active = _active_channels.load(std::memory_order_acquire);
 
	uint8 available = ~currently_active;
 
	if (available == 0) return nullptr;
 

	
 
	uint8 channel_index = FindFirstBit(available);
 

	
 
	MixerChannel *mc = &_channels[channel_index];
 
	free(mc->memory);
 
	mc->memory = nullptr;
 
	return mc;
 
}
 

	
 
void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
 
{
 
	mc->memory = mem;
 
	mc->frac_pos = 0;
 
@@ -228,13 +227,14 @@ void MxSetChannelVolume(MixerChannel *mc
 
	mc->volume_right = (uint)(sin(pan * M_PI / 2.0) * volume);
 
}
 

	
 

	
 
void MxActivateChannel(MixerChannel *mc)
 
{
 
	mc->active = true;
 
	uint8 channel_index = mc - _channels;
 
	_active_channels.fetch_or((1 << channel_index), std::memory_order_release);
 
}
 

	
 
/**
 
 * Set source of PCM music
 
 * @param music_callback Function that will be called to fill sample buffers with music data.
 
 * @return Sample rate of mixer, which the buffers supplied to the callback must be rendered at.
0 comments (0 inline, 0 general)