191 lines
4.5 KiB
C++
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();
|
|
}
|