summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/sound/sound_module.cpp
blob: 5dc13eb3246e6d26d970735f6883560a5fd87c25 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// license:BSD-3-Clause
// copyright-holders:O. Galibert


#include "emu.h"
#include "sound_module.h"

void sound_module::abuffer::get(int16_t *data, uint32_t samples)
{
	uint32_t pos = 0;
	while(pos != samples) {
		if(m_buffers.empty()) {
			while(pos != samples) {
				memcpy(data, m_last_sample.data(), m_channels*2);
				data += m_channels;
				pos ++;				
			}
			break;
		}

		auto &buf = m_buffers.front();
		if(buf.m_data.empty()) {
			m_buffers.erase(m_buffers.begin());
			continue;
		}

		uint32_t avail = buf.m_data.size() / m_channels - buf.m_cpos;
		if(avail > samples - pos) {
			avail = samples - pos;
			memcpy(data, buf.m_data.data() + buf.m_cpos * m_channels, avail * 2 * m_channels);
			buf.m_cpos += avail;
			break;
		}

		memcpy(data, buf.m_data.data() + buf.m_cpos * m_channels, avail * 2 * m_channels);
		m_buffers.erase(m_buffers.begin());
		pos += avail;
		data += avail * m_channels;
	}			
}

void sound_module::abuffer::push(const int16_t *data, uint32_t samples)
{
	m_buffers.resize(m_buffers.size() + 1);
	auto &buf = m_buffers.back();
	buf.m_cpos = 0;
	buf.m_data.resize(samples * m_channels);
	memcpy(buf.m_data.data(), data, samples * 2 * m_channels);
	memcpy(m_last_sample.data(), data + (samples-1) * m_channels, 2 * m_channels);

	if(m_buffers.size() > 10)
		// If there are way too many buffers, drop some so only 10 are left (roughly 0.2s)
		m_buffers.erase(m_buffers.begin(), m_buffers.begin() + m_buffers.size() - 10);

	else if(m_buffers.size() >= 5)
		// If there are too many buffers, remove five samples per buffer
		// to slowly resync to reduce latency (4 seconds to
		// compensate one buffer, roughly)
		buf.m_cpos = 5;
}