Skip to content

Commit

Permalink
update midi
Browse files Browse the repository at this point in the history
  • Loading branch information
CrSjimo committed Jul 6, 2024
1 parent b9f5104 commit 1129703
Show file tree
Hide file tree
Showing 23 changed files with 701 additions and 298 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,78 @@

#include <QList>

#include "SineWaveNoteSynthesizer.h"
#include "SineWaveNoteSynthesizer_p.h"
#include "NoteSynthesizer.h"
#include "NoteSynthesizer_p.h"

namespace talcs {
SineWaveNoteSynthesizer::SineWaveNoteSynthesizer() : SineWaveNoteSynthesizer(*new SineWaveNoteSynthesizerPrivate) {
NoteSynthesizer::NoteSynthesizer() : NoteSynthesizer(*new NoteSynthesizerPrivate) {

}

SineWaveNoteSynthesizer::SineWaveNoteSynthesizer(SineWaveNoteSynthesizerPrivate &d) : AudioSource(d) {
NoteSynthesizer::NoteSynthesizer(NoteSynthesizerPrivate &d) : AudioSource(d) {

}

SineWaveNoteSynthesizer::~SineWaveNoteSynthesizer() {
NoteSynthesizer::~NoteSynthesizer() {

}

bool SineWaveNoteSynthesizer::open(qint64 bufferSize, double sampleRate) {
Q_D(SineWaveNoteSynthesizer);
d->rate = std::pow(0.99, 20000.0 / sampleRate);
bool NoteSynthesizer::open(qint64 bufferSize, double sampleRate) {
Q_D(NoteSynthesizer);
return AudioSource::open(bufferSize, sampleRate);
}

void SineWaveNoteSynthesizer::close() {
void NoteSynthesizer::close() {
AudioSource::close();
}

qint64 SineWaveNoteSynthesizer::processReading(const AudioSourceReadData &readData) {
static const double PI = std::acos(-1);
Q_D(SineWaveNoteSynthesizer);
void NoteSynthesizer::setAttackRate(double rate) {
Q_D(NoteSynthesizer);
d->attackRate = rate;
}

double NoteSynthesizer::attackRate() const {
Q_D(const NoteSynthesizer);
return d->attackRate;
}

void NoteSynthesizer::setReleaseRate(double rate) {
Q_D(NoteSynthesizer);
d->releaseRate = rate;
}

double NoteSynthesizer::releaseRate() const {
Q_D(const NoteSynthesizer);
return d->releaseRate;
}


void NoteSynthesizer::setGenerator(NoteSynthesizer::Generator g) {
switch (g) {
case Sine:
setGenerator(NoteSynthesizerPrivate::GenerateSineWave());
break;
case Square:
setGenerator(NoteSynthesizerPrivate::GenerateSquareWave());
break;
case Triangle:
setGenerator(NoteSynthesizerPrivate::GenerateTriangleWave());
break;
case Sawtooth:
setGenerator(NoteSynthesizerPrivate::GenerateSawtoothWave());
break;
default:
Q_UNREACHABLE();
}
}

void NoteSynthesizer::setGenerator(const NoteSynthesizer::GeneratorFunction &g) {
Q_D(NoteSynthesizer);
d->generatorFunction = g;
}

qint64 NoteSynthesizer::processReading(const AudioSourceReadData &readData) {
Q_D(NoteSynthesizer);
QMutexLocker locker(&d->mutex);
for (int ch = 0; ch < readData.buffer->channelCount(); ch++) {
readData.buffer->clear(ch, readData.startPos, readData.length);
Expand All @@ -61,9 +104,9 @@ namespace talcs {
for (auto msg = d->detector->nextMessage(); ; msg = d->detector->nextMessage()) {
for (;currentPos < (msg.position != -1 ? msg.position : readData.length); currentPos++) {
for (auto &keyInfo : d->keys) {
double vel = keyInfo.nextVel(d->rate);
double vel = keyInfo.nextVel();
for (int ch = 0; ch < readData.buffer->channelCount(); ch++) {
readData.buffer->sampleAt(ch, readData.startPos + currentPos) += vel * std::sin(2.0 * PI * keyInfo.frequency / sampleRate() * double(keyInfo.x));
readData.buffer->sampleAt(ch, readData.startPos + currentPos) += static_cast<float>(vel * d->generatorFunction(keyInfo.frequency / sampleRate(), keyInfo.x));
}
}
d->keys.erase(std::remove_if(d->keys.begin(), d->keys.end(), [&](const auto &item) {
Expand All @@ -74,7 +117,7 @@ namespace talcs {
return qFuzzyCompare(item.frequency, msg.frequency);
});
if (msg.isNoteOn) {
d->keys.append({msg.frequency, msg.velocity, .0, 0, true});
d->keys.append({d, msg.frequency, msg.velocity, .0, 0, true});
} else {
if (it != d->keys.end())
it->isAttack = false;
Expand All @@ -85,14 +128,14 @@ namespace talcs {
return readData.length;
}

void SineWaveNoteSynthesizer::setDetector(SineWaveNoteSynthesizerDetector *detector) {
Q_D(SineWaveNoteSynthesizer);
void NoteSynthesizer::setDetector(NoteSynthesizerDetector *detector) {
Q_D(NoteSynthesizer);
QMutexLocker locker(&d->mutex);
d->detector = detector;
}

SineWaveNoteSynthesizerDetector *SineWaveNoteSynthesizer::detector() const {
Q_D(const SineWaveNoteSynthesizer);
NoteSynthesizerDetector *NoteSynthesizer::detector() const {
Q_D(const NoteSynthesizer);
return d->detector;
}
} // talcs
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,63 @@
* along with TALCS. If not, see <https://www.gnu.org/licenses/>. *
******************************************************************************/

#ifndef TALCS_SINEWAVENOTESYNTHESIZER_H
#define TALCS_SINEWAVENOTESYNTHESIZER_H
#ifndef TALCS_NOTESYNTHESIZER_H
#define TALCS_NOTESYNTHESIZER_H

#include <TalcsCore/AudioSource.h>

namespace talcs {

struct SineWaveNoteSynthesizerDetectorMessage {
struct NoteSynthesizerDetectorMessage {
qint64 position;
double frequency;
double velocity;
bool isNoteOn;
};

class SineWaveNoteSynthesizerDetector {
class NoteSynthesizerDetector {
public:
virtual void detectInterval(qint64 intervalLength) = 0;
virtual SineWaveNoteSynthesizerDetectorMessage nextMessage() = 0;
virtual NoteSynthesizerDetectorMessage nextMessage() = 0;
};

class SineWaveNoteSynthesizerPrivate;
class NoteSynthesizerPrivate;

class TALCSCORE_EXPORT SineWaveNoteSynthesizer : public AudioSource {
Q_DECLARE_PRIVATE(SineWaveNoteSynthesizer)
class TALCSCORE_EXPORT NoteSynthesizer : public AudioSource {
Q_DECLARE_PRIVATE(NoteSynthesizer)
public:
explicit SineWaveNoteSynthesizer();
~SineWaveNoteSynthesizer() override;
explicit NoteSynthesizer();
~NoteSynthesizer() override;

bool open(qint64 bufferSize, double sampleRate) override;
void close() override;

void setDetector(SineWaveNoteSynthesizerDetector *detector);
SineWaveNoteSynthesizerDetector *detector() const;
void setAttackRate(double rate);
double attackRate() const;
void setReleaseRate(double rate);
double releaseRate() const;

enum Generator {
Sine,
Square,
Triangle,
Sawtooth,
};

using GeneratorFunction = std::function<double(double, qint64)>;

void setGenerator(Generator);
void setGenerator(const GeneratorFunction &);

void setDetector(NoteSynthesizerDetector *detector);
NoteSynthesizerDetector *detector() const;

protected:
explicit SineWaveNoteSynthesizer(SineWaveNoteSynthesizerPrivate &d);
explicit NoteSynthesizer(NoteSynthesizerPrivate &d);
qint64 processReading(const AudioSourceReadData &readData) override;

};

}

#endif //TALCS_SINEWAVENOTESYNTHESIZER_H
#endif //TALCS_NOTESYNTHESIZER_H
Original file line number Diff line number Diff line change
Expand Up @@ -17,48 +17,93 @@
* along with TALCS. If not, see <https://www.gnu.org/licenses/>. *
******************************************************************************/

#ifndef TALCS_SINEWAVENOTESYNTHESIZER_P_H
#define TALCS_SINEWAVENOTESYNTHESIZER_P_H
#ifndef TALCS_NoteSynthesizer_P_H
#define TALCS_NoteSynthesizer_P_H

#include <QList>

#include <TalcsCore/SineWaveNoteSynthesizer.h>
#include <TalcsCore/NoteSynthesizer.h>
#include <TalcsCore/private/AudioSource_p.h>

namespace talcs {

class SineWaveNoteSynthesizerPrivate : public AudioSourcePrivate {
Q_DECLARE_PUBLIC(SineWaveNoteSynthesizer);
class NoteSynthesizerPrivate : public AudioSourcePrivate {
Q_DECLARE_PUBLIC(NoteSynthesizer);
public:
QMutex mutex;
SineWaveNoteSynthesizerDetector *detector = nullptr;
NoteSynthesizerDetector *detector = nullptr;

struct KeyInfo {
NoteSynthesizerPrivate *d;
double frequency;
double velFactor;
double vel;
qint64 x;
bool isAttack;
inline double nextVel(double rate_) {
inline double nextVel() {
double ret = vel;
if (isAttack && vel < velFactor) {
if (qFuzzyIsNull(vel))
vel = .005;
vel /= rate_;
vel /= d->attackRate;
if (vel > velFactor)
vel = velFactor;
} else {
vel *= rate_;
vel *= d->releaseRate;
if (vel < .005)
vel = .0;
}
x++;
return ret;
}
};
double rate = .0;
double attackRate = .005;
double releaseRate = 0;
QList<KeyInfo> keys;

struct GenerateSineWave {
inline double operator()(double f, qint64 x) {
static const double PI = std::acos(-1);
return std::sin(2.0 * PI * f * double(x));
}
};

struct GenerateSquareWave {
inline double operator()(double f, qint64 x) {
double period = 1.0 / f;
double t = fmod(x, period);
return (t < period / 2) ? 1.0 : -1.0;
}
};

struct GenerateTriangleWave {
inline double operator()(double f, qint64 x) {
double period = 1.0 / f;
double t = fmod(x, period);
double normalized_t = t / period;

if (normalized_t < 0.25) {
return 4.0 * normalized_t;
} else if (normalized_t < 0.75) {
return 2.0 - 4.0 * normalized_t;
} else {
return -4.0 + 4.0 * normalized_t;
}
}
};

struct GenerateSawtoothWave {
inline double operator()(double f, qint64 x) {
double period = 1.0 / f;
double t = fmod(x, period);
return 2.0 * (t / period) - 1.0;
}
};

NoteSynthesizer::GeneratorFunction generatorFunction = GenerateSineWave();

};

}

#endif //TALCS_SINEWAVENOTESYNTHESIZER_P_H
#endif //TALCS_NoteSynthesizer_P_H
Loading

0 comments on commit 1129703

Please sign in to comment.