reimplement sample import using ffmpeg
parent
3d678c173b
commit
ffc7be1783
5
notes
5
notes
|
@ -32,8 +32,9 @@ parameters {
|
|||
|
||||
TODO {
|
||||
immediate frontburner {
|
||||
reimplement sample import to IPC from standalone ffmpeg since QAudioDecoder is partially broken on arch and completely broken on macOS
|
||||
ffprobe -v quiet -show_streams -select_streams a -of json testOut.mp3
|
||||
- reimplement sample import to IPC from standalone ffmpeg since QAudioDecoder is partially broken on arch and completely broken on macOS
|
||||
# ffprobe -v quiet -show_streams -select_streams a -of json testOut.mp3
|
||||
# ffmpeg -i input.flv -f f32le -acodec pcm_f32le -
|
||||
|
||||
distortion effect
|
||||
single-selection sampler
|
||||
|
|
|
@ -9,11 +9,18 @@ using namespace Xybrid::Data;
|
|||
#include <QCborMap>
|
||||
#include <QCborArray>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <QAudioDecoder>
|
||||
#include <QAudioFormat>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDataStream>
|
||||
|
||||
#include <QEventLoop>
|
||||
|
||||
#define qs QStringLiteral
|
||||
|
@ -88,6 +95,7 @@ bool Sample::changeUuid(QUuid newUuid) {
|
|||
|
||||
void Sample::newUuid() { changeUuid(QUuid::createUuid()); }
|
||||
|
||||
#ifdef OLD_SAMPLE_IMPORT
|
||||
namespace {
|
||||
bool blah [[maybe_unused]];
|
||||
template<typename T> void insertbuf(std::shared_ptr<Sample> smp, const T* data, size_t len, size_t channels) {
|
||||
|
@ -154,6 +162,63 @@ std::shared_ptr<Sample> Sample::fromFile(QString fileName) {
|
|||
|
||||
return smp;
|
||||
}
|
||||
#else
|
||||
std::shared_ptr<Sample> Sample::fromFile(QString fileName) {
|
||||
QJsonObject info;
|
||||
{
|
||||
// get stream info
|
||||
QProcess probe;
|
||||
QStringList param;
|
||||
param << "-v" << "quiet" << "-show_streams" << "-select_streams" << "a" << "-of" << "json";
|
||||
param << fileName;
|
||||
probe.start("ffprobe", param);
|
||||
probe.waitForFinished();
|
||||
|
||||
auto doc = QJsonDocument::fromJson(probe.readAllStandardOutput());
|
||||
info = doc.object()["streams"].toArray().first().toObject();
|
||||
}
|
||||
if (!info.contains("sample_rate") || !info.contains("channels")) return nullptr; // no/invalid audio streams
|
||||
|
||||
int channels = info["channels"].toInt();
|
||||
int sampleRate = info["sample_rate"].toString().toInt(); // for some reason ffprobe stores this as a string??
|
||||
|
||||
auto smp = std::make_shared<Sample>();
|
||||
smp->sampleRate = sampleRate;
|
||||
|
||||
// grab raw pcm_f32le via ffmpeg
|
||||
QByteArray raw;
|
||||
{
|
||||
QProcess dec;
|
||||
QStringList param;
|
||||
param << "-i" << fileName << "-f" << "f32le" << "-acodec" << "pcm_f32le" << "-";
|
||||
dec.start("ffmpeg", param);
|
||||
dec.waitForFinished();
|
||||
raw = dec.readAllStandardOutput();
|
||||
}
|
||||
// pre-size sample data buffers
|
||||
auto len = static_cast<size_t>((raw.length() / channels) / 4);
|
||||
smp->data[0].reserve(len);
|
||||
if (channels > 1) smp->data[1].reserve(len);
|
||||
|
||||
// read raw bytes into channels
|
||||
QDataStream r(&raw, QIODevice::ReadOnly);
|
||||
size_t chs = static_cast<size_t>(channels);
|
||||
size_t ch = chs;
|
||||
float f;
|
||||
while (!r.atEnd()) {
|
||||
r.readRawData(reinterpret_cast<char*>(&f), sizeof(f));
|
||||
ch = (ch+1) % chs;
|
||||
if (ch < 2) smp->data[ch].push_back(f);
|
||||
}
|
||||
|
||||
// add info
|
||||
smp->uuid = QUuid::createUuid();
|
||||
smp->name = QFileInfo(fileName).baseName();
|
||||
|
||||
return smp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
bool exporting = false;
|
||||
|
|
Loading…
Reference in New Issue