First PPM experiment
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
all: main
|
||||
./main
|
||||
main: main.cpp sound_server.h sound_server.cpp Makefile
|
||||
g++ -std=c++11 -o main main.cpp sound_server.cpp `sdl-config --cflags --libs`
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <SDL/SDL.h>
|
||||
#include <iostream>
|
||||
#include "sound_server.h"
|
||||
|
||||
// Naive example of 1-bit audio mixing employing PPM technique
|
||||
// Adrian Scripca <benishor@gmail.com>
|
||||
|
||||
struct oscillator {
|
||||
void init(uint16_t sr) { samplerate = sr; }
|
||||
|
||||
void set_frequency(uint16_t frequency) {
|
||||
samples_per_cycle = samplerate / frequency;
|
||||
// phase = 0; // hard sync
|
||||
}
|
||||
|
||||
bool tick() {
|
||||
phase = (phase + 1) % samples_per_cycle;
|
||||
return phase < (samples_per_cycle / 2 * duty_cycle / 100);
|
||||
}
|
||||
|
||||
uint16_t samples_per_cycle;
|
||||
uint16_t duty_cycle = 4; // percentage
|
||||
uint32_t phase = 0;
|
||||
uint16_t samplerate;
|
||||
};
|
||||
|
||||
struct synth : sound_producer_1bit {
|
||||
explicit synth(uint16_t samplerate) {
|
||||
for (auto& o : oscs) {
|
||||
o.init(samplerate);
|
||||
}
|
||||
}
|
||||
|
||||
bool tick() override {
|
||||
return oscs[0].tick() | oscs[1].tick() | oscs[2].tick() | oscs[3].tick();
|
||||
}
|
||||
|
||||
void major_chord(float root) {
|
||||
oscs[0].set_frequency(root);
|
||||
oscs[1].set_frequency(root * 5.0f / 4.0f); // major third
|
||||
oscs[2].set_frequency(root * 3.0f / 2.0f); // perfect fifth
|
||||
oscs[3].set_frequency(root * 2.0f); // octave
|
||||
}
|
||||
|
||||
void minor_chord(float root) {
|
||||
oscs[0].set_frequency(root);
|
||||
oscs[1].set_frequency(root * 6.0f / 5.0f); // minor third
|
||||
oscs[2].set_frequency(root * 3.0f / 2.0f); // perfect fifth
|
||||
oscs[3].set_frequency(root * 2.0f); // octave
|
||||
}
|
||||
|
||||
oscillator oscs[4];
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::cout << "1bit PPM technique example" << std::endl;
|
||||
// setup
|
||||
const uint16_t SampleRate = 44100;
|
||||
|
||||
synth instrument{SampleRate};
|
||||
sound_server_1bit sound_server{SampleRate, instrument};
|
||||
|
||||
// fool around. Gmaj, Cmaj, Emaj (la bamba)
|
||||
instrument.major_chord(98);
|
||||
SDL_Delay(1000);
|
||||
|
||||
instrument.major_chord(130.81);
|
||||
SDL_Delay(1000);
|
||||
|
||||
instrument.major_chord(146.83);
|
||||
SDL_Delay(1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "sound_server.h"
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void audio_callback(void* param, uint8_t* stream, int len) {
|
||||
sound_producer_1bit* producer = reinterpret_cast<sound_producer_1bit*>(param);
|
||||
for (int i = 0; i < len; i++) {
|
||||
*stream++ = producer->tick() ? 255 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
sound_server_1bit::sound_server_1bit(uint16_t samplerate,
|
||||
sound_producer_1bit& producer) {
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||
std::cerr << "Init failed" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SDL_AudioSpec as;
|
||||
as.freq = samplerate;
|
||||
as.format = AUDIO_U8;
|
||||
as.samples = 256;
|
||||
as.callback = audio_callback;
|
||||
as.userdata = reinterpret_cast<void*>(&producer);
|
||||
as.channels = 1;
|
||||
|
||||
if (SDL_OpenAudio(&as, NULL) < 0) {
|
||||
std::cerr << "Unable to open audio" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
|
||||
sound_server_1bit::~sound_server_1bit() { SDL_Quit(); }
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
struct sound_producer_1bit {
|
||||
// false = off, true = on
|
||||
virtual bool tick() = 0;
|
||||
};
|
||||
|
||||
struct sound_server_1bit {
|
||||
sound_server_1bit(uint16_t samplerate, sound_producer_1bit& producer);
|
||||
~sound_server_1bit();
|
||||
};
|
||||
Reference in New Issue
Block a user