1 /* Copyright (c) 2013-2015 Jeffrey Pfau
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "AudioDevice.h"
7 
8 #include "LogController.h"
9 
10 #include <mgba/core/blip_buf.h>
11 #include <mgba/core/core.h>
12 #include <mgba/core/thread.h>
13 #include <mgba/internal/gba/audio.h>
14 
15 using namespace QGBA;
16 
AudioDevice(QObject * parent)17 AudioDevice::AudioDevice(QObject* parent)
18 	: QIODevice(parent)
19 	, m_context(nullptr)
20 {
21 	setOpenMode(ReadOnly);
22 }
23 
setFormat(const QAudioFormat & format)24 void AudioDevice::setFormat(const QAudioFormat& format) {
25 	if (!m_context || !mCoreThreadIsActive(m_context)) {
26 		LOG(QT, INFO) << tr("Can't set format of context-less audio device");
27 		return;
28 	}
29 	double fauxClock = GBAAudioCalculateRatio(1, m_context->impl->sync.fpsTarget, 1);
30 	mCoreSyncLockAudio(&m_context->impl->sync);
31 	blip_set_rates(m_context->core->getAudioChannel(m_context->core, 0),
32 		           m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock);
33 	blip_set_rates(m_context->core->getAudioChannel(m_context->core, 1),
34 		           m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock);
35 	mCoreSyncUnlockAudio(&m_context->impl->sync);
36 }
37 
setInput(mCoreThread * input)38 void AudioDevice::setInput(mCoreThread* input) {
39 	m_context = input;
40 }
41 
readData(char * data,qint64 maxSize)42 qint64 AudioDevice::readData(char* data, qint64 maxSize) {
43 	if (!m_context->core) {
44 		LOG(QT, WARN) << tr("Audio device is missing its core");
45 		return 0;
46 	}
47 
48 	maxSize /= sizeof(GBAStereoSample);
49 	mCoreSyncLockAudio(&m_context->impl->sync);
50 	int available = std::min<qint64>({
51 		blip_samples_avail(m_context->core->getAudioChannel(m_context->core, 0)),
52 		maxSize,
53 		std::numeric_limits<int>::max()
54 	});
55 	blip_read_samples(m_context->core->getAudioChannel(m_context->core, 0), &reinterpret_cast<GBAStereoSample*>(data)->left, available, true);
56 	blip_read_samples(m_context->core->getAudioChannel(m_context->core, 1), &reinterpret_cast<GBAStereoSample*>(data)->right, available, true);
57 	mCoreSyncConsumeAudio(&m_context->impl->sync);
58 	return available * sizeof(GBAStereoSample);
59 }
60 
writeData(const char *,qint64)61 qint64 AudioDevice::writeData(const char*, qint64) {
62 	LOG(QT, WARN) << tr("Writing data to read-only audio device");
63 	return 0;
64 }
65