android fix
This commit is contained in:
parent
2bc03b0143
commit
fde087c63d
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Enable auto-env through the sdkman_auto_env config
|
||||||
|
# Add key=value pairs of SDKs to use below
|
||||||
|
java=17-homebrew
|
||||||
|
gradle=9.2.1
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// src/AudioEngine.cpp
|
||||||
|
|
||||||
#include "AudioEngine.h"
|
#include "AudioEngine.h"
|
||||||
#include <QMediaDevices>
|
#include <QMediaDevices>
|
||||||
#include <QAudioDevice>
|
#include <QAudioDevice>
|
||||||
|
|
@ -7,6 +9,7 @@
|
||||||
#include <QAudioBuffer>
|
#include <QAudioBuffer>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
AudioEngine::AudioEngine(QObject* parent) : QObject(parent) {
|
AudioEngine::AudioEngine(QObject* parent) : QObject(parent) {
|
||||||
m_processors.push_back(new Processor(m_frameSize, m_sampleRate));
|
m_processors.push_back(new Processor(m_frameSize, m_sampleRate));
|
||||||
|
|
@ -60,7 +63,6 @@ void AudioEngine::loadTrack(const QString& filePath) {
|
||||||
} else {
|
} else {
|
||||||
delete m_fileSource;
|
delete m_fileSource;
|
||||||
m_fileSource = nullptr;
|
m_fileSource = nullptr;
|
||||||
// Fix: Handle content:// URIs correctly
|
|
||||||
if (filePath.startsWith("content://")) {
|
if (filePath.startsWith("content://")) {
|
||||||
m_decoder->setSource(QUrl(filePath));
|
m_decoder->setSource(QUrl(filePath));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -83,38 +85,18 @@ void AudioEngine::onBufferReady() {
|
||||||
QAudioBuffer buffer = m_decoder->read();
|
QAudioBuffer buffer = m_decoder->read();
|
||||||
if (!buffer.isValid()) return;
|
if (!buffer.isValid()) return;
|
||||||
|
|
||||||
// Fix: Explicit cast to int to avoid warning
|
|
||||||
const int frames = static_cast<int>(buffer.frameCount());
|
const int frames = static_cast<int>(buffer.frameCount());
|
||||||
const int channels = buffer.format().channelCount();
|
const int channels = buffer.format().channelCount();
|
||||||
auto sampleType = buffer.format().sampleFormat();
|
auto sampleType = buffer.format().sampleFormat();
|
||||||
|
|
||||||
|
// We store everything as Stereo Int16 to ensure compatibility with all sinks
|
||||||
if (sampleType == QAudioFormat::Int16) {
|
if (sampleType == QAudioFormat::Int16) {
|
||||||
const int16_t* src = buffer.constData<int16_t>();
|
const int16_t* src = buffer.constData<int16_t>();
|
||||||
if (!src) return;
|
if (!src) return;
|
||||||
|
|
||||||
for (int i = 0; i < frames; ++i) {
|
for (int i = 0; i < frames; ++i) {
|
||||||
float left = 0.0f;
|
int16_t left = 0;
|
||||||
float right = 0.0f;
|
int16_t right = 0;
|
||||||
|
|
||||||
if (channels == 1) {
|
|
||||||
left = src[i] / 32768.0f;
|
|
||||||
right = left;
|
|
||||||
} else if (channels >= 2) {
|
|
||||||
left = src[i * channels] / 32768.0f;
|
|
||||||
right = src[i * channels + 1] / 32768.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pcmData.append(reinterpret_cast<const char*>(&left), sizeof(float));
|
|
||||||
m_pcmData.append(reinterpret_cast<const char*>(&right), sizeof(float));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (sampleType == QAudioFormat::Float) {
|
|
||||||
const float* src = buffer.constData<float>();
|
|
||||||
if (!src) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < frames; ++i) {
|
|
||||||
float left = 0.0f;
|
|
||||||
float right = 0.0f;
|
|
||||||
|
|
||||||
if (channels == 1) {
|
if (channels == 1) {
|
||||||
left = src[i];
|
left = src[i];
|
||||||
|
|
@ -124,8 +106,35 @@ void AudioEngine::onBufferReady() {
|
||||||
right = src[i * channels + 1];
|
right = src[i * channels + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pcmData.append(reinterpret_cast<const char*>(&left), sizeof(float));
|
m_pcmData.append(reinterpret_cast<const char*>(&left), sizeof(int16_t));
|
||||||
m_pcmData.append(reinterpret_cast<const char*>(&right), sizeof(float));
|
m_pcmData.append(reinterpret_cast<const char*>(&right), sizeof(int16_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sampleType == QAudioFormat::Float) {
|
||||||
|
const float* src = buffer.constData<float>();
|
||||||
|
if (!src) return;
|
||||||
|
|
||||||
|
auto toInt16 = [](float x) -> int16_t {
|
||||||
|
return static_cast<int16_t>(std::clamp(x, -1.0f, 1.0f) * 32767.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < frames; ++i) {
|
||||||
|
float l = 0.0f;
|
||||||
|
float r = 0.0f;
|
||||||
|
|
||||||
|
if (channels == 1) {
|
||||||
|
l = src[i];
|
||||||
|
r = l;
|
||||||
|
} else if (channels >= 2) {
|
||||||
|
l = src[i * channels];
|
||||||
|
r = src[i * channels + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t left = toInt16(l);
|
||||||
|
int16_t right = toInt16(r);
|
||||||
|
|
||||||
|
m_pcmData.append(reinterpret_cast<const char*>(&left), sizeof(int16_t));
|
||||||
|
m_pcmData.append(reinterpret_cast<const char*>(&right), sizeof(int16_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +164,7 @@ void AudioEngine::play() {
|
||||||
QAudioFormat format;
|
QAudioFormat format;
|
||||||
format.setSampleRate(44100);
|
format.setSampleRate(44100);
|
||||||
format.setChannelCount(2);
|
format.setChannelCount(2);
|
||||||
format.setSampleFormat(QAudioFormat::Float);
|
format.setSampleFormat(QAudioFormat::Int16); // Universal format
|
||||||
|
|
||||||
QAudioDevice device = QMediaDevices::defaultAudioOutput();
|
QAudioDevice device = QMediaDevices::defaultAudioOutput();
|
||||||
if (device.isNull()) {
|
if (device.isNull()) {
|
||||||
|
|
@ -164,13 +173,12 @@ void AudioEngine::play() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device.isFormatSupported(format)) {
|
if (!device.isFormatSupported(format)) {
|
||||||
qWarning() << "AudioEngine: Float format not supported, using preferred format.";
|
qWarning() << "AudioEngine: Int16 format not supported, using preferred format.";
|
||||||
format = device.preferredFormat();
|
format = device.preferredFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sink = new QAudioSink(device, format, this);
|
m_sink = new QAudioSink(device, format, this);
|
||||||
|
|
||||||
|
|
||||||
connect(m_sink, &QAudioSink::stateChanged, this, [this](QAudio::State state){
|
connect(m_sink, &QAudioSink::stateChanged, this, [this](QAudio::State state){
|
||||||
if (state == QAudio::IdleState && m_sink->error() == QAudio::NoError) {
|
if (state == QAudio::IdleState && m_sink->error() == QAudio::NoError) {
|
||||||
if (m_buffer.bytesAvailable() == 0) {
|
if (m_buffer.bytesAvailable() == 0) {
|
||||||
|
|
@ -201,7 +209,8 @@ void AudioEngine::stop() {
|
||||||
void AudioEngine::seek(float position) {
|
void AudioEngine::seek(float position) {
|
||||||
if (m_pcmData.isEmpty()) return;
|
if (m_pcmData.isEmpty()) return;
|
||||||
qint64 pos = position * m_pcmData.size();
|
qint64 pos = position * m_pcmData.size();
|
||||||
pos -= pos % 8;
|
// Align to 4 bytes (2 channels * 2 bytes per sample)
|
||||||
|
pos -= pos % 4;
|
||||||
if (m_buffer.isOpen()) m_buffer.seek(pos);
|
if (m_buffer.isOpen()) m_buffer.seek(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,16 +226,17 @@ void AudioEngine::onProcessTimer() {
|
||||||
qint64 currentPos = m_buffer.pos();
|
qint64 currentPos = m_buffer.pos();
|
||||||
emit positionChanged((float)currentPos / m_pcmData.size());
|
emit positionChanged((float)currentPos / m_pcmData.size());
|
||||||
|
|
||||||
const float* samples = reinterpret_cast<const float*>(m_pcmData.constData());
|
// Convert Int16 back to Float for DSP
|
||||||
qint64 sampleIdx = currentPos / sizeof(float);
|
const int16_t* samples = reinterpret_cast<const int16_t*>(m_pcmData.constData());
|
||||||
qint64 totalSamples = m_pcmData.size() / sizeof(float);
|
qint64 sampleIdx = currentPos / sizeof(int16_t);
|
||||||
|
qint64 totalSamples = m_pcmData.size() / sizeof(int16_t);
|
||||||
|
|
||||||
if (sampleIdx + m_frameSize * 2 >= totalSamples) return;
|
if (sampleIdx + m_frameSize * 2 >= totalSamples) return;
|
||||||
|
|
||||||
std::vector<float> ch0(m_frameSize), ch1(m_frameSize);
|
std::vector<float> ch0(m_frameSize), ch1(m_frameSize);
|
||||||
for (int i = 0; i < m_frameSize; ++i) {
|
for (int i = 0; i < m_frameSize; ++i) {
|
||||||
ch0[i] = samples[sampleIdx + i*2];
|
ch0[i] = samples[sampleIdx + i*2] / 32768.0f;
|
||||||
ch1[i] = samples[sampleIdx + i*2 + 1];
|
ch1[i] = samples[sampleIdx + i*2 + 1] / 32768.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_processors[0]->pushData(ch0);
|
m_processors[0]->pushData(ch0);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue