xybrid/xybrid/audio/audioengine.h

108 lines
3.3 KiB
C++

#pragma once
#include <memory>
#include <list>
#include <vector>
#include <deque>
#include <unordered_map>
#include <atomic>
#include <QIODevice>
#include <QAudioOutput>
class QThread;
namespace Xybrid::Data {
class Project;
class Node;
}
namespace Xybrid::Audio {
template <typename T> struct PointerCompare {
bool operator()(T* a, T* b) const { return *a == *b; }
size_t operator()(T* a) const { return std::hash<T>()(*a); }
};
struct NoteInfo {
bool valid = false;
uint8_t port = 0;
uint16_t noteId = 0;
NoteInfo() = default;
NoteInfo(uint8_t p, uint16_t nId) { valid = true; port = p; noteId = nId; }
};
class AudioEngine : public QIODevice {
Q_OBJECT
explicit AudioEngine(QObject *parent = nullptr);
public:
enum PlaybackMode {
Stopped, // stopped
Playing, // playing track
Paused, // paused during playback
Previewing, // instrument live preview
Rendering, // rendering to file
};
private:
QThread* thread;
std::unique_ptr<QAudioOutput> output;
int sampleRate = 48000;
std::vector<float> buffer[2];
size_t bufPos = 0;
static const constexpr size_t tickBufSize = (1024*1024*5); // 5mb should be enough
std::unique_ptr<size_t[]> tickBuf;
std::atomic<size_t*> tickBufPtr;
size_t* tickBufEnd;
PlaybackMode mode = Stopped;
size_t tickId = 0;
std::shared_ptr<Data::Project> project;
std::deque<std::shared_ptr<Data::Node>> queue;
bool queueValid;
void buildQueue();
std::array<uint16_t, 256> portLastNoteId;
std::vector<NoteInfo> chTrack;
std::vector<NoteInfo> noteEndQueue;
std::unordered_map<std::string*, NoteInfo, PointerCompare<std::string>, PointerCompare<std::string>> nameTrack;
std::vector<uint8_t> buf; /// preallocated buffer for building commands
// playback timing and position
float tempo = 140.0;
int seqPos;
int curRow;
int curTick;
double tickAcc; // accumulator for tick remainder
void postInit();
void initAudio(bool startNow = false);
void deinitAudio();
void nextTick();
public:
static void init();
inline constexpr PlaybackMode playbackMode() const { return mode; }
inline constexpr const std::shared_ptr<Data::Project>& playingProject() const { return project; }
void play(std::shared_ptr<Data::Project>);
void stop();
inline void invalidateQueue(Data::Project* p) { if (p == project.get()) queueValid = false; }
void* tickAlloc(size_t size);
inline size_t curTickId() const { return tickId; }
inline size_t curTickSize() const { return buffer[0].size(); }
inline int curSampleRate() const { return sampleRate; }
// QIODevice functions
qint64 readData(char* data, qint64 maxlen) override;
qint64 writeData(const char*, qint64) override { return 0; }
qint64 bytesAvailable() const override { return 0; } // not actually used by QAudioOutput
volatile int note = 12*5;
signals:
void playbackModeChanged();
public slots:
};
extern AudioEngine* audioEngine;
}