108 lines
3.3 KiB
C++
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;
|
|
}
|