-
-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b17dcf0
commit e142d4f
Showing
16 changed files
with
262 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#include <contour/Audio.h> | ||
|
||
#include <crispy/Note.h> | ||
#include <crispy/logstore.h> | ||
|
||
#include <qbuffer.h> | ||
#include <qthread.h> | ||
|
||
using namespace contour; | ||
|
||
Audio::Audio() | ||
{ | ||
QAudioFormat f; | ||
f.setSampleRate(44100); | ||
f.setChannelCount(1); | ||
f.setSampleSize(16); | ||
f.setCodec("audio/pcm"); | ||
f.setByteOrder(QAudioFormat::LittleEndian); | ||
f.setSampleType(QAudioFormat::SignedInt); | ||
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); | ||
if (!info.isFormatSupported(f)) | ||
{ | ||
errorlog()("Default output device doesn't support 16 Bit signed integer PCM"); | ||
return; | ||
} | ||
audio = std::make_unique<QAudioOutput>(f); | ||
audio->moveToThread(&soundThread_); | ||
connect(audio.get(), &QAudioOutput::stateChanged, this, &Audio::handleStateChanged); | ||
qRegisterMetaType<std::vector<int>>(); | ||
connect(this, &Audio::play, this, &Audio::handlePlayback, Qt::ConnectionType::QueuedConnection); | ||
soundThread_.start(); | ||
} | ||
|
||
Audio::~Audio() | ||
{ | ||
soundThread_.quit(); | ||
soundThread_.wait(); | ||
} | ||
|
||
void Audio::fillBuffer(int volume, int duration, crispy::span<int> notes) | ||
{ | ||
for (auto i: notes) | ||
{ | ||
auto b = crispy::createNote(volume, duration, static_cast<crispy::Note>(i)); | ||
byteArray_.append(reinterpret_cast<const char*>(b.data()), static_cast<int>(2 * b.size())); | ||
} | ||
} | ||
|
||
void Audio::handlePlayback(int volume, int duration, std::vector<int> notes) | ||
{ | ||
if (audio->state() == QAudio::State::ActiveState) | ||
{ | ||
fillBuffer(volume, duration, crispy::span(notes.data(), notes.size())); | ||
return; | ||
} | ||
fillBuffer(volume, duration, crispy::span(notes.data(), notes.size())); | ||
audioBuffer_.setBuffer(&byteArray_); | ||
audioBuffer_.open(QIODevice::ReadWrite); | ||
if (audio) | ||
audio->start(&audioBuffer_); | ||
} | ||
|
||
void Audio::handleStateChanged(QAudio::State state) | ||
{ | ||
switch (state) | ||
{ | ||
case QAudio::IdleState: | ||
audio->stop(); | ||
audioBuffer_.close(); | ||
byteArray_.clear(); | ||
break; | ||
|
||
case QAudio::StoppedState: | ||
if (audio->error() != QAudio::NoError) | ||
{ | ||
errorlog()("Audio playback stopped: {}", audio->error()); | ||
} | ||
break; | ||
default: break; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#pragma once | ||
|
||
#include <crispy/span.h> | ||
|
||
#include <memory> | ||
|
||
#include <qbuffer.h> | ||
#include <qthread.h> | ||
|
||
#include <QtMultimedia/QAudioOutput> | ||
namespace contour | ||
{ | ||
class Audio: public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
Audio(); | ||
~Audio() override; | ||
public Q_SLOTS: | ||
signals: | ||
void play(int volume, int duration, std::vector<int> notes); | ||
private slots: | ||
void handleStateChanged(QAudio::State state); | ||
void handlePlayback(int volume, int duration, std::vector<int> notes); | ||
|
||
private: | ||
void fillBuffer(int volume, int duration, crispy::span<int> notes); | ||
QByteArray byteArray_; | ||
QBuffer audioBuffer_; | ||
QThread soundThread_; | ||
std::unique_ptr<QAudioOutput> audio; | ||
}; | ||
} // namespace contour |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,8 @@ set(crispy_SOURCES | |
escape.h | ||
indexed.h | ||
logstore.h | ||
Note.h | ||
Note.cpp | ||
overloaded.h | ||
reference.h | ||
ring.h | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include <crispy/Note.h> | ||
#include <crispy/assert.h> | ||
|
||
#include <gsl/gsl_assert> | ||
|
||
#include <cmath> | ||
#include <vector> | ||
|
||
using namespace crispy; | ||
|
||
namespace | ||
{ | ||
constexpr double SAMPLE_RATE = 44100; | ||
constexpr double square_wave(double x) noexcept | ||
{ | ||
x = std::fmod(x, 2); | ||
return std::isgreater(x, 1) ? -1 : 1; | ||
} | ||
|
||
auto createNote(double volume, double duration, double frequency) noexcept | ||
{ | ||
duration = duration * 1 / 32.0; | ||
volume /= 7; | ||
std::vector<std::int16_t> buffer; | ||
buffer.reserve(static_cast<size_t>(std::ceil(duration * SAMPLE_RATE))); | ||
for (double i = 0; i < duration * SAMPLE_RATE; ++i) | ||
{ | ||
auto sample = static_cast<int16_t>(0x7fff * volume * square_wave(frequency / SAMPLE_RATE * i * 2)); | ||
buffer.push_back(sample); | ||
} | ||
return buffer; | ||
} | ||
|
||
} // namespace | ||
std::vector<std::int16_t> crispy::createNote(double volume, int duration, Note note_) noexcept | ||
{ | ||
Ensures(static_cast<int>(note_) >= 0 && static_cast<int>(note_) < 26); | ||
switch (note_) | ||
{ | ||
case Note::A5: return ::createNote(volume, duration, 880.0); break; | ||
case Note::A6: return ::createNote(volume, duration, 1760.0); break; | ||
case Note::A_SHARP_5: return ::createNote(volume, duration, 932.3275); break; | ||
case Note::A_SHARP_6: return ::createNote(volume, duration, 1864.655); break; | ||
case Note::C_SHARP_5: return ::createNote(volume, duration, 554.3653); break; | ||
case Note::C_SHARP_6: return ::createNote(volume, duration, 1108.731); break; | ||
case Note::D_SHARP_5: return ::createNote(volume, duration, 622.2540); break; | ||
case Note::D_SHARP_6: return ::createNote(volume, duration, 1244.508); break; | ||
case Note::F_SHARP_5: return ::createNote(volume, duration, 739.9909); break; | ||
case Note::F_SHARP_6: return ::createNote(volume, duration, 1479.978); break; | ||
case Note::G_SHARP_5: return ::createNote(volume, duration, 830.6094); break; | ||
case Note::G_SHARP_6: return ::createNote(volume, duration, 1661.219); break; | ||
case Note::B5: return ::createNote(volume, duration, 987.7666); break; | ||
case Note::B6: return ::createNote(volume, duration, 1975.533); break; | ||
case Note::C5: return ::createNote(volume, duration, 523.2511); break; | ||
case Note::C6: return ::createNote(volume, duration, 1046.502); break; | ||
case Note::C7: return ::createNote(volume, duration, 2093.005); break; | ||
case Note::D5: return ::createNote(volume, duration, 587.3295); break; | ||
case Note::D6: return ::createNote(volume, duration, 1174.659); break; | ||
case Note::E5: return ::createNote(volume, duration, 659.2551); break; | ||
case Note::E6: return ::createNote(volume, duration, 1318.510); break; | ||
case Note::F5: return ::createNote(volume, duration, 698.4565); break; | ||
case Note::F6: return ::createNote(volume, duration, 1396.913); break; | ||
case Note::G5: return ::createNote(volume, duration, 783.9909); break; | ||
case Note::G6: return ::createNote(volume, duration, 1567.982); break; | ||
case Note::SILENT: return ::createNote(volume, duration, 0); break; | ||
} | ||
crispy::unreachable(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#pragma once | ||
#include <array> | ||
#include <cstdint> | ||
#include <vector> | ||
namespace crispy | ||
{ | ||
enum class Note | ||
{ | ||
SILENT = 0, | ||
C5, | ||
C_SHARP_5, | ||
D5, | ||
D_SHARP_5, | ||
E5, | ||
F5, | ||
F_SHARP_5, | ||
G5, | ||
G_SHARP_5, | ||
A5, | ||
A_SHARP_5, | ||
B5, | ||
C6, | ||
C_SHARP_6, | ||
D6, | ||
D_SHARP_6, | ||
E6, | ||
F6, | ||
F_SHARP_6, | ||
G6, | ||
G_SHARP_6, | ||
A6, | ||
A_SHARP_6, | ||
B6, | ||
C7 | ||
}; | ||
std::array<std::int16_t, 26> intitializeNotes() noexcept; | ||
std::vector<std::int16_t> createNote(double volume, int duration, Note note_) noexcept; | ||
|
||
} // namespace crispy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.