Files
bytebeat/main.cpp
2025-06-22 21:55:21 +02:00

191 lines
4.5 KiB
C++

#include <QCoreApplication>
#include <QIODevice>
#include <QDebug>
/** Dont forget to set QT += core multimedia **/
#include <QtMultimedia/QAudioFormat>
#include <QtMultimedia/QAudioDeviceInfo>
#include <QtMultimedia/QAudioOutput>
/**
* @brief Interface class for all byte beat musicals
*/
template<typename SAMPLE_TYPE, int SAMPLE_RATE, bool STEREO>
class MusicDevice : public QIODevice
{
public:
explicit MusicDevice(QObject *parent = Q_NULLPTR) : QIODevice(parent) {}
virtual ~MusicDevice() {}
virtual SAMPLE_TYPE getSample() = 0;
virtual const QAudioFormat& getFormat() const
{
static QAudioFormat format;
format.setSampleRate(SAMPLE_RATE);
format.setChannelCount(STEREO ? 2 : 1);
format.setSampleSize(sizeof(SAMPLE_TYPE) * 8);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt); //TODO: make this depend on SAMPLE_TYPE
return format;
}
// qt specific implementation
bool open(OpenMode mode)
{
auto success = mode == QIODevice::ReadOnly;
if(success)
setOpenMode(mode);
else
qWarning() << "unsupported open mode" << mode;
return success;
}
void close()
{
setOpenMode(NotOpen);
}
bool isSequential() const
{
return true;
}
protected:
qint64 readData(char* data, qint64 maxSize)
{
for(qint64 i = 0; i < maxSize; i++)
data[i] = getSample();
return maxSize;
}
qint64 writeData(const char* data, qint64 maxSize)
{
Q_UNUSED(data)
Q_UNUSED(maxSize)
qWarning() << "read only device!";
return -1;
}
};
/**
* @brief Bitshift variations by Rob Miles
* https://www.youtube.com/watch?v=MqZgoNRERY8&t=1s
* http://txti.es/bitshiftvariationsincminor
*/
class BitshiftVariations : public MusicDevice<quint8, 8000, false>
{
public:
explicit BitshiftVariations(QObject *parent = Q_NULLPTR) : MusicDevice(parent) {}
virtual ~BitshiftVariations() {}
quint8 getSample() Q_DECL_OVERRIDE
{
int voice0 = g(i, 1, n = i >> 14, 12);
int voice1 = g(i, s = i >> 17, n ^ i >> 13, 10);
int voice2 = g(i, s / 3, n + ((i >> 11) % 3), 10);
int voice3 = g(i, s / 5, 8 + n - ((i >> 10) % 3), 9);
i++;
return voice0 + voice1 + voice2 + voice3;
}
private:
static int g(int i, int x, int t, int o)
{
return ((3 & x & (i * ((3 & i >> 16 ? "BY}6YB6%" : "Qj}6jQ6%")[t % 8] + 51) >> o)) << 4);
}
int i, n, s;
};
/**
* @brief Funky beat found in some forum
*/
class FunkyBeat : public MusicDevice<quint8, 8000, false>
{
public:
explicit FunkyBeat(QObject *parent = Q_NULLPTR) : MusicDevice(parent), a(0), f(true) {}
virtual ~FunkyBeat() {}
quint8 getSample() Q_DECL_OVERRIDE
{
if(f)
{
b = 99;
c = 99;
d = 99;
while(true)
{
if("+%7%+%7%5%4%2%457%0%0%754%2%+%%%5%542%457%0%0%042%2#+%!#0%+%$%%%"[a] > b)
d = d * 89 / 84;
if(b-- == 0)
break;
if("057+5420"[a / 8] > b)
c = c * 89 / 84;
}
s = 999 + 99 * (a & 2);
f = false;
}
quint8 sample =
s * (
(776 - d ?
s * d & 32767 :
b
) +
(a & 2 ?
s * c / 2 & 32767 :
b
)
) / 299999;
if(s-- == 0)
{
f = true;
a++;
a &= 63;
}
return sample;
}
private:
int a;
int b;
int c;
int d;
int s;
bool f;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
//MusicDevice<quint8, 8000, false> *source = new BitshiftVariations(&app);
MusicDevice<quint8, 8000, false> *source = new FunkyBeat(&app);
{
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(source->getFormat()))
{
qFatal("Your soundcard does not support the needed output format!");
return -1;
}
}
QAudioOutput *audioOutput = new QAudioOutput(source->getFormat(), &app);
source->open(QIODevice::ReadOnly);
audioOutput->start(source);
return app.exec();
}