Skip to content

Instantly share code, notes, and snippets.

@chbtoys
Created July 17, 2022 09:32
Show Gist options
  • Save chbtoys/978de513b61ae51d5a3f6e8aecd67861 to your computer and use it in GitHub Desktop.
Save chbtoys/978de513b61ae51d5a3f6e8aecd67861 to your computer and use it in GitHub Desktop.
audio programming - beginner level
// Signal Generators
//
// Compile: clang++ -std=c++20 -lpng 00-signalgenerators.cpp -o 00-signalgenerators
//
// If #include <png++/png.hpp> is missing:
// > brew install png++
// png++ (header-only) is used to render audio as images to visualize the waveform.
// Install with homebrew on macOS or with other package manager.
// https://savannah.nongnu.org/projects/pngpp/
//
// Uses Adam Stark's AudioFile (header-only) to write AIFF-files.
// Check out the code from github link below.
// https://github.com/adamstark/AudioFile
//
// Uses p-ranav Indicators
// > git clone https://github.com/p-ranav/indicators
// > cd indicators
// > mkdir build && cd build
// > cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..
// > make
//
// python3 utils/amalgamate/amalgamate.py -c single_include.json -s .
//
// If clang++ is missing:
// clang++ from XCode:
// > xcode-select --install
// > xcode-select -p
//
// clang++ from homebrew:
// > brew install llvm
// If clang++ is needed, install it with homebrew for macOS or...
// https://clang.llvm.org/get_started.html
#define _USE_MATH_DEFINES
#include <cmath>
#include <vector>
#include <random>
#include <filesystem>
#include "indicators.hpp"
#include <png++/png.hpp>
#include "AudioFile/AudioFile.h"
namespace Render
{
void fillbackground(png::image<png::rgb_pixel>& image);
void drawpx(png::image<png::rgb_pixel>& image, int x, int y);
void drawline(png::image<png::rgb_pixel>& image, int x1, int y1, int x2, int y2);
void drawwave(png::image<png::rgb_pixel>& image,std::vector<uint32_t>& signalY);
}
namespace SignalGenerators
{
void generatesinewaveaiff();
void rendersinewavepng();
void generatesumoffirsteightpartialsaiff();
void rendersumoffirsteightpartialspng();
void generatesawtoothwaveaiff();
void rendersawtoothwavepng();
void generatesquarewaveaiff();
void rendersquarewavepng();
void generatetrianglewaveaiff();
void rendertrianglewavepng();
void generatetwentyfivepulsewaveaiff();
void rendertwentyfivepulsewavepng();
void generateconvexcurveaiff();
void renderconvexcurvepng();
void generateconcavecurveaiff();
void renderconcavecurvepng();
void generatefrequencymodulationaiff();
void renderfrequencymodulationpng();
void generatephasemodulationaiff();
void renderphasemodulationpng();
void generateamplitudedmodulationaiff();
void renderamplitudedmodulationpng();
void generateringmodulationaiff();
void renderringmodulationpng();
void generatenoiseaiff();
void rendernoisepng();
void generatepulsewaveaiff();
void renderpulsewavepng();
}
int main()
{
namespace fs = std::filesystem;
fs::create_directory("signalgenerators");
using namespace indicators;
// Hide cursor
show_console_cursor(false);
// Setup ProgressBar
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"■"},
option::Lead{"■"},
option::Remainder{"-"},
option::End{" ]"},
option::PostfixText{"Generating: Sine Wave 1/28"},
option::ForegroundColor{Color::cyan},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update progress
bar.set_progress(13);
SignalGenerators::generatesinewaveaiff();
// Update progress
bar.set_progress(19);
bar.set_option(option::PostfixText{"Rendering: Sine Wave 2/28"});
SignalGenerators::rendersinewavepng();
// Update progress
bar.set_progress(22);
bar.set_option(option::PostfixText{"Generating: Sum of first eight partials 3/28"});
SignalGenerators::generatesumoffirsteightpartialsaiff();
// Update progress
bar.set_progress(25);
bar.set_option(option::PostfixText{"Rendering: Sum of first eight partials 4/28"});
SignalGenerators::rendersumoffirsteightpartialspng();
// Update progress
bar.set_progress(28);
bar.set_option(option::PostfixText{"Generating: Saw Tooth Wave 5/28"});
SignalGenerators::generatesawtoothwaveaiff();
// Update progress
bar.set_progress(31);
bar.set_option(option::PostfixText{"Rendering: Saw Tooth Wave 6/28"});
SignalGenerators::rendersawtoothwavepng();
// Update progress
bar.set_progress(34);
bar.set_option(option::PostfixText{"Generating: Square Wave 7/28"});
SignalGenerators::generatesquarewaveaiff();
// Update progress
bar.set_progress(37);
bar.set_option(option::PostfixText{"Rendering: Square Wave 8/28"});
SignalGenerators::rendersquarewavepng();
// Update progress
bar.set_progress(40);
bar.set_option(option::PostfixText{"Generating: Triangle Wave 9/28"});
SignalGenerators::generatetrianglewaveaiff();
// Update progress
bar.set_progress(43);
bar.set_option(option::PostfixText{"Rendering: Triangle Wave 10/28"});
SignalGenerators::rendertrianglewavepng();
// Update progress
bar.set_progress(46);
bar.set_option(option::PostfixText{"Generating: 25% Pulse Wave 11/28"});
SignalGenerators::generatetwentyfivepulsewaveaiff();
// Update progress
bar.set_progress(49);
bar.set_option(option::PostfixText{"Rendering: 25% Pulse Wave 12/28"});
SignalGenerators::rendertwentyfivepulsewavepng();
// Update progress
bar.set_progress(52);
bar.set_option(option::PostfixText{"Generating: Convex Curve 13/28"});
SignalGenerators::generateconvexcurveaiff();
// Update progress
bar.set_progress(55);
bar.set_option(option::PostfixText{"Rendering: Convex Curve 14/28"});
SignalGenerators::renderconvexcurvepng();
// Update progress
bar.set_progress(58);
bar.set_option(option::PostfixText{"Generating: Concave Curve 15/28"});
SignalGenerators::generateconcavecurveaiff();
// Update progress
bar.set_progress(61);
bar.set_option(option::PostfixText{"Rendering: Concave Curve 16/28"});
SignalGenerators::renderconcavecurvepng();
// Update progress
bar.set_progress(64);
bar.set_option(option::PostfixText{"Generating: Frequency Modulation 17/28"});
SignalGenerators::generatefrequencymodulationaiff();
// Update progress
bar.set_progress(67);
bar.set_option(option::PostfixText{"Rendering: Frequency Modulation 18/28"});
SignalGenerators::renderfrequencymodulationpng();
// Update progress
bar.set_progress(70);
bar.set_option(option::PostfixText{"Generating: Phase Modulation 19/28"});
SignalGenerators::generatephasemodulationaiff();
// Update progress
bar.set_progress(73);
bar.set_option(option::PostfixText{"Rendering: Phase Modulation 20/28"});
SignalGenerators::renderphasemodulationpng();
// Update progress
bar.set_progress(76);
bar.set_option(option::PostfixText{"Generating: Amplitude Modulation 21/28"});
SignalGenerators::generateamplitudedmodulationaiff();
// Update progress
bar.set_progress(79);
bar.set_option(option::PostfixText{"Rendering: Amplitude Modulation 22/28"});
SignalGenerators::renderamplitudedmodulationpng();
// Update progress
bar.set_progress(82);
bar.set_option(option::PostfixText{"Generating: Ring Modulation 23/28"});
SignalGenerators::generateringmodulationaiff();
// Update progress
bar.set_progress(85);
bar.set_option(option::PostfixText{"Rendering: Ring Modulation 24/28"});
SignalGenerators::renderringmodulationpng();
// Update progress
bar.set_progress(88);
bar.set_option(option::PostfixText{"Generating: White Noise 25/28"});
SignalGenerators::generatenoiseaiff();
// Update progress
bar.set_progress(91);
bar.set_option(option::PostfixText{"Rendering: White Noise 26/28"});
SignalGenerators::rendernoisepng();
// Update progress
bar.set_progress(94);
bar.set_option(option::PostfixText{"Generating: Pulse Wave 27/28"});
SignalGenerators::generatepulsewaveaiff();
// Update progress
bar.set_progress(97);
bar.set_option(option::PostfixText{"Rendering: Pulse Wave 28/28"});
SignalGenerators::renderpulsewavepng();
// Update progress
bar.set_progress(100);
bar.set_option(option::PostfixText{"Done 28/28"});
// Show cursor
show_console_cursor(true);
return 0;
}
namespace SignalGenerators
{
void generatesinewaveaiff()
{
const std::string sineName="signalgenerators/01-sine-wave.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
// Genrate Sine wave
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
a.samples[channel][i]=sin((static_cast<double> (i) / sampleRate) * frequencyInHz * 2.0 * M_PI);
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void rendersinewavepng()
{
const std::string sineName="signalgenerators/02-sine-wave.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<sampleRate;++i)
{
double value=sin((static_cast<double> (i) / sampleRate) * frequencyInHz * 2.0 * M_PI);
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatesumoffirsteightpartialsaiff()
{
const std::string sineName="signalgenerators/03-sine-wave-first-eight-partials.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
double s1=0.0,s2=0.0,s3=0.0,s4=0.0,s5=0.0,s6=0.0,s7=0.0,s8=0.0,ss=0.0;
// Genrate Sine wave
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
s1=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*1) * 2.0 * M_PI);
s2=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*2) * 2.0 * M_PI);
s3=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*3) * 2.0 * M_PI);
s4=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*4) * 2.0 * M_PI);
s5=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*5) * 2.0 * M_PI);
s6=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*6) * 2.0 * M_PI);
s7=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*7) * 2.0 * M_PI);
s8=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*8) * 2.0 * M_PI);
ss=(s1+s2+s3+s4+s5+s6+s7+s8)/8;
a.samples[channel][i]=ss;
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void rendersumoffirsteightpartialspng()
{
const std::string sineName="signalgenerators/04-sine-wave-first-eight-partials.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double s1=0.0,s2=0.0,s3=0.0,s4=0.0,s5=0.0,s6=0.0,s7=0.0,s8=0.0,ss=0.0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
// Genrate Sine waves
for (int i=0;i<sampleRate;++i)
{
s1=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*1) * 2.0 * M_PI);
s2=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*2) * 2.0 * M_PI);
s3=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*3) * 2.0 * M_PI);
s4=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*4) * 2.0 * M_PI);
s5=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*5) * 2.0 * M_PI);
s6=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*6) * 2.0 * M_PI);
s7=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*7) * 2.0 * M_PI);
s8=sin((static_cast<double> (i) / sampleRate) * (frequencyInHz*8) * 2.0 * M_PI);
ss=(s1+s2+s3+s4+s5+s6+s7+s8)/8;
if (ss >= 0.0) {
signalY[i]=300-(300*ss);
} else if (ss < 0.0)
{
signalY[i]=300+(300*fabs(ss));
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatesawtoothwaveaiff()
{
const std::string sineName="signalgenerators/05-saw-tooth-wave.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double ss;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
ss=-2/M_PI*atan(1/tan(frequencyInHz*M_PI*i/sampleRate));
a.samples[channel][i]=ss;
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void rendersawtoothwavepng()
{
const std::string sineName="signalgenerators/06-saw-tooth-wave.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double ss;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<44100;++i)
{
ss=-2/M_PI*atan(1/tan(frequencyInHz*M_PI*i/sampleRate));
if (ss >= 0.0) {
signalY[i]=300-(300*ss);
} else if (ss < 0.0)
{
signalY[i]=300+(300*fabs(ss));
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatesquarewaveaiff()
{
const std::string sineName="signalgenerators/07-square-wave.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
double dutyCycle=period*0.5;
double ss;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
if ((i%int(period)) >= 0 && (i%int(period)) < int(dutyCycle))
{
ss=0.7;
} else {
ss=-0.7;
}
a.samples[channel][i]=ss;
}
}
a.samples[0][0]=0.0;
a.samples[0][44099]=0.0;
a.save(sineName,AudioFileFormat::Aiff);
}
void rendersquarewavepng()
{
const std::string sineName="signalgenerators/08-square-wave.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
double dutyCycle=period*0.5;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<44100;++i)
{
if ((i%int(period)) >= 0 && (i%int(period)) < int(dutyCycle))
{
signalY[i]=0;
} else {
signalY[i]=600;
}
}
signalY[0]=300;
signalY[44099]=300;
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatetrianglewaveaiff()
{
const std::string sineName="signalgenerators/09-trangle-wave.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double ss;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
ss=M_2_PI*asin(sin(frequencyInHz*2*M_PI*i/sampleRate));
a.samples[channel][i]=ss;
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void rendertrianglewavepng()
{
const std::string sineName="signalgenerators/10-trangle-wave.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double ss;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<44100;++i)
{
ss=M_2_PI*asin(sin(frequencyInHz*2*M_PI*i/sampleRate));
if (ss >= 0.0) {
signalY[i]=300-(300*ss);
} else if (ss < 0.0)
{
signalY[i]=300+(300*fabs(ss));
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatetwentyfivepulsewaveaiff()
{
const std::string sineName="signalgenerators/11-twentyfive-pulse-wave.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
double dutyCycle=period*0.25;
double ss;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
if ((i%int(period)) >= 0 && (i%int(period)) < int(dutyCycle))
{
ss=0.7;
} else {
ss=-0.7;
}
a.samples[channel][i]=ss;
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void rendertwentyfivepulsewavepng()
{
const std::string sineName="signalgenerators/12-twentyfive-pulse-wave.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
double dutyCycle=period*0.25;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<44100;++i)
{
if ((i%int(period)) >= 0 && (i%int(period)) < int(dutyCycle))
{
signalY[i]=0;
} else {
signalY[i]=600;
}
}
signalY[0]=300;
signalY[44099]=300;
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generateconvexcurveaiff()
{
const std::string sineName="signalgenerators/13-convex-curve.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
uint32_t maxValue=0,temp=0;
double ss,sss;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<44100;++i)
{
temp=pow(abs((i % int(period)) - (int(period)/2)), 2.0);
if (temp > maxValue) {maxValue=temp;}
}
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
temp=pow(abs((i % int(period)) - (int(period)/2)), 2.0);
ss=double(temp)/double(maxValue);
sss=(ss-0.5)*1.5;
a.samples[channel][i]=sss;
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderconvexcurvepng()
{
const std::string sineName="signalgenerators/14-convex-curve.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
double ss;
uint32_t maxValue=0,temp=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<44100;++i)
{
temp=pow(abs((i % int(period)) - (int(period)/2)), 2.0);
if (temp > maxValue) {maxValue=temp;}
}
for (int i=0;i<44100;++i)
{
temp=pow(abs((i % int(period)) - (int(period)/2)), 2.0);
ss=double(temp)/double(maxValue);
signalY[i]=600-(600*ss);
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generateconcavecurveaiff()
{
const std::string sineName="signalgenerators/15-concave-curve.aiff";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
uint32_t maxValue=0;
double ss,sss,temp;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<44100;++i)
{
temp=pow(abs((i % int(period)) - (period/2.0)), 0.5);
if (int(temp) > maxValue) {maxValue=int(temp);}
}
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
temp=pow(abs((i % int(period)) - (period/2.0)), 0.5);
ss=temp/double(maxValue);
sss=(ss-0.5)*1.5;
a.samples[channel][i]=sss;
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderconcavecurvepng()
{
const std::string sineName="signalgenerators/16-concave-curve.png";
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
double period=sampleRate/frequencyInHz;
double ss,temp;
uint32_t maxValue=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (int i=0;i<44100;++i)
{
temp=pow(abs((i % int(period)) - (period/2.0)), 0.5);
if (int(temp) > maxValue) {maxValue=int(temp);}
}
for (int i=0;i<44100;++i)
{
temp=pow(abs((i % int(period)) - (period/2.0)), 0.5);
ss=temp/double(maxValue);
signalY[i]=600-(600*ss);
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatefrequencymodulationaiff()
{
const std::string sineName="signalgenerators/17-frequency-modulation.aiff";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifierFrequency = frequencyInHz * 3;
double modifierIncrement = frequencyRadian * modifierFrequency;
double modifierPhase = 0;
double carrierIncrement = 0;
double carrierPhase = 0;
double modifieramplitude = 2 * modifierFrequency;
double modifierValue = 0;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
a.samples[channel][i]=sinf(carrierPhase);
modifierValue = modifieramplitude * sinf(modifierPhase);
carrierIncrement = frequencyRadian * (frequencyInHz + modifierValue);
carrierPhase = carrierPhase + carrierIncrement;
modifierPhase = modifierPhase + modifierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
else if (carrierPhase < 0) {
carrierPhase += twoPI;
}
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderfrequencymodulationpng()
{
const std::string sineName="signalgenerators/18-frequency-modulation.png";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifierFrequency = frequencyInHz * 3;
double modifierIncrement = frequencyRadian * modifierFrequency;
double modifierPhase = 0;
double carrierIncrement = 0;
double carrierPhase = 0;
double modifieramplitude = 2 * modifierFrequency;
double modifierValue = 0;
double value=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (uint32_t i=0;i<sampleRate;++i)
{
value=sinf(carrierPhase);
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
modifierValue = modifieramplitude * sinf(modifierPhase);
carrierIncrement = frequencyRadian * (frequencyInHz + modifierValue);
carrierPhase = carrierPhase + carrierIncrement;
modifierPhase = modifierPhase + modifierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
else if (carrierPhase < 0) {
carrierPhase += twoPI;
}
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatephasemodulationaiff()
{
const std::string sineName="signalgenerators/19-phase-modulation.aiff";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifierFrequency = frequencyInHz * 3;
double carrierIncrement = frequencyRadian * frequencyInHz;
double modifieramplitude = frequencyRadian * (2 * modifierFrequency);
double modifierValue = 0;
double carrierPhase = 0;
double modifierPhase = 0;
double modifierIncrement = frequencyRadian * modifierFrequency;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
a.samples[channel][i]=sinf(carrierPhase);
modifierValue = modifieramplitude * sinf(modifierPhase);
carrierPhase = carrierPhase + carrierIncrement + modifierValue;
modifierPhase = modifierPhase + modifierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
else if (carrierPhase < 0) {
carrierPhase += twoPI;
}
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderphasemodulationpng()
{
const std::string sineName="signalgenerators/20-phase-modulation.png";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifierFrequency = frequencyInHz * 3;
double carrierIncrement = frequencyRadian * frequencyInHz;
double modifieramplitude = frequencyRadian * (2 * modifierFrequency);
double modifierValue = 0;
double carrierPhase = 0;
double modifierPhase = 0;
double modifierIncrement = frequencyRadian * modifierFrequency;
double value=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (uint32_t i=0;i<sampleRate;++i)
{
value=sinf(carrierPhase);
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
modifierValue = modifieramplitude * sinf(modifierPhase);
carrierPhase = carrierPhase + carrierIncrement + modifierValue;
modifierPhase = modifierPhase + modifierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
else if (carrierPhase < 0) {
carrierPhase += twoPI;
}
if (modifierPhase >= twoPI){
modifierPhase -= twoPI;
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generateamplitudedmodulationaiff()
{
const std::string sineName="signalgenerators/21-amplituded-modulation.aiff";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifierFrequency = frequencyInHz * 2.5;
double modifierIncrement = frequencyRadian * modifierFrequency;
double modifieramplitude = 1.0;
double carrierPhase = 0;
double modifierPhase = 0;
double modifierScale = 1 / (1 + modifieramplitude);
double modifierValue = 0;
double carrierIncrement = frequencyRadian * frequencyInHz;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
modifierValue = 1.0 + (modifieramplitude * sinf(modifierPhase));
a.samples[channel][i]=((sinf(carrierPhase) * modifierValue) * modifierScale);
carrierPhase += carrierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
modifierPhase += modifierIncrement;
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderamplitudedmodulationpng()
{
const std::string sineName="signalgenerators/22-amplituded-modulation.png";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifierFrequency = frequencyInHz * 2.5;
double modifierIncrement = frequencyRadian * modifierFrequency;
double modifieramplitude = 1.0;
double carrierPhase = 0;
double modifierPhase = 0;
double modifierScale = 1 / (1 + modifieramplitude);
double modifierValue = 0;
double carrierIncrement = frequencyRadian * frequencyInHz;
double value=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (uint32_t i=0;i<sampleRate;++i)
{
modifierValue = 1.0 + (modifieramplitude * sinf(modifierPhase));
value=((sinf(carrierPhase) * modifierValue) * modifierScale);
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
carrierPhase += carrierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
modifierPhase += modifierIncrement;
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generateringmodulationaiff()
{
const std::string sineName="signalgenerators/23-ring-modulation.aiff";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifieramplitude = 1.0;
double modifierFrequency = frequencyInHz * 2.5;
double modifierPhase = 0;
double modifierIncrement = frequencyRadian * modifierFrequency;
double carrierPhase = 0;
double carrierIncrement = frequencyRadian * frequencyInHz;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
a.samples[channel][i]=(sinf(carrierPhase) * modifieramplitude * sinf(modifierPhase));
carrierPhase += carrierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
modifierPhase += modifierIncrement;
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderringmodulationpng()
{
const std::string sineName="signalgenerators/24-ring-modulation.png";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double modifieramplitude = 1.0;
double modifierFrequency = frequencyInHz * 2.5;
double modifierPhase = 0;
double modifierIncrement = frequencyRadian * modifierFrequency;
double carrierPhase = 0;
double carrierIncrement = frequencyRadian * frequencyInHz;
double value=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (uint32_t i=0;i<sampleRate;++i)
{
value=(sinf(carrierPhase) * modifieramplitude * sinf(modifierPhase));
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
carrierPhase += carrierIncrement;
if (carrierPhase >= twoPI) {
carrierPhase -= twoPI;
}
modifierPhase += modifierIncrement;
if (modifierPhase >= twoPI) {
modifierPhase -= twoPI;
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatenoiseaiff()
{
const std::string sineName="signalgenerators/25-white-noise.aiff";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(-1.0, 1.0);
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
a.samples[channel][i]=dis(gen);
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void rendernoisepng()
{
const std::string sineName="signalgenerators/26-white-noise.png";
const double sampleRate=44100.0;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(-1.0, 1.0);
double value=0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (uint32_t i=0;i<sampleRate;++i)
{
value=dis(gen);
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
void generatepulsewaveaiff()
{
const std::string sineName="signalgenerators/27-pulse-wave.aiff";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double maxNumber = floor(sampleRate / (2.0 * frequencyInHz) - 0.5) - 1;
double phaseIncrementDenominator = (M_PI / sampleRate) * frequencyInHz;
double phaseIncrementNumerator = phaseIncrementDenominator * ((2.0 * maxNumber) + 1);
double phaseDenominator = 0.0;
double phaseNumerator = 0.0;
double amplitudeScale = 1.0 / (2.0 * maxNumber);
double value = 0;
// Setup the audio file
AudioFile<float> a;
a.setNumChannels(1);
a.setBitDepth(24);
a.setNumSamplesPerChannel(44100);
for (int i=0;i<a.getNumSamplesPerChannel();++i)
{
for (int channel=0;channel<a.getNumChannels();++channel)
{
double Denominator = sin(phaseDenominator);
if (Denominator == 0.0) {
value = 1.0;
} else {
value = amplitudeScale * ((sin(phaseNumerator) / Denominator) - 1);
}
a.samples[channel][i]=value;
phaseDenominator += phaseIncrementDenominator;
if (phaseDenominator >= twoPI) {
phaseDenominator -= twoPI;
}
phaseNumerator += phaseIncrementNumerator;
if (phaseNumerator >= twoPI) {
phaseNumerator -= twoPI;
}
}
}
a.save(sineName,AudioFileFormat::Aiff);
}
void renderpulsewavepng()
{
const std::string sineName="signalgenerators/28-pulse-wave.png";
const double twoPI=2*M_PI;
const double sampleRate=44100.0;
const double frequencyInHz=440.0;
const double frequencyRadian = twoPI / sampleRate;
double maxNumber = floor(sampleRate / (2.0 * frequencyInHz) - 0.5) - 1;
double phaseIncrementDenominator = (M_PI / sampleRate) * frequencyInHz;
double phaseIncrementNumerator = phaseIncrementDenominator * ((2.0 * maxNumber) + 1);
double phaseDenominator = 0.0;
double phaseNumerator = 0.0;
double amplitudeScale = 1.0 / (2.0 * maxNumber);
double value = 0;
std::vector<uint32_t> signalY;
signalY.resize(44100);
for (uint32_t i=0;i<sampleRate;++i)
{
double Denominator = sin(phaseDenominator);
if (Denominator == 0.0) {
value = 1.0;
} else {
value = amplitudeScale * ((sin(phaseNumerator) / Denominator) - 1);
}
if (value >= 0.0) {
signalY[i]=300-(300*value);
} else if (value < 0.0)
{
signalY[i]=300+(300*fabs(value));
}
phaseDenominator += phaseIncrementDenominator;
if (phaseDenominator >= twoPI) {
phaseDenominator -= twoPI;
}
phaseNumerator += phaseIncrementNumerator;
if (phaseNumerator >= twoPI) {
phaseNumerator -= twoPI;
}
}
png::image<png::rgb_pixel> image(44100,600);
Render::fillbackground(image);
Render::drawwave(image,signalY);
image.write(sineName);
}
}
namespace Render
{
void fillbackground(png::image<png::rgb_pixel>& image)
{
png::rgb_pixel px(0x04,0x13,0x31);
for (uint32_t y=0;y<image.get_height();y++) {
for (uint32_t x=0;x<image.get_width();++x) {
image.set_pixel(x,y,px);
}
}
}
void drawpx(png::image<png::rgb_pixel>& image, int x, int y)
{
if (((x >= 0) && (x < image.get_width())) && ((y >= 0) && (y < image.get_height())))
{
png::rgb_pixel px(0x7a,0xb1,0xe3);
image.set_pixel(x,y,px);
}
}
void drawline(png::image<png::rgb_pixel>& image, int x1, int y1, int x2, int y2)
{
int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i;
dx = x2 - x1; dy = y2 - y1;
if (dx == 0)
{
if (y2 < y1) std::swap(y1, y2);
for (y = y1; y <= y2; y++)
drawpx(image, x1, y);
return;
}
if (dy == 0)
{
if (x2 < x1) std::swap(x1, x2);
for (x = x1; x <= x2; x++)
drawpx(image, x, y1);
return;
}
dx1 = abs(dx); dy1 = abs(dy);
px = 2 * dy1 - dx1; py = 2 * dx1 - dy1;
if (dy1 <= dx1)
{
if (dx >= 0)
{
x = x1; y = y1; xe = x2;
}
else
{
x = x2; y = y2; xe = x1;
}
drawpx(image, x, y);
for (i = 0; x<xe; i++)
{
x = x + 1;
if (px<0)
px = px + 2 * dy1;
else
{
if ((dx<0 && dy<0) || (dx>0 && dy>0)) y = y + 1; else y = y - 1;
px = px + 2 * (dy1 - dx1);
}
drawpx(image, x, y);
}
}
else
{
if (dy >= 0)
{
x = x1; y = y1; ye = y2;
}
else
{
x = x2; y = y2; ye = y1;
}
drawpx(image, x, y);
for (i = 0; y<ye; i++)
{
y = y + 1;
if (py <= 0)
py = py + 2 * dx1;
else
{
if ((dx<0 && dy<0) || (dx>0 && dy>0)) x = x + 1; else x = x - 1;
py = py + 2 * (dx1 - dy1);
}
drawpx(image, x, y);
}
}
}
void drawwave(png::image<png::rgb_pixel>& image,std::vector<uint32_t>& signalY)
{
uint32_t y=0,ox=0,oy=0;
for (uint32_t x=0;x<image.get_width();++x)
{
y=signalY[x];
if (x == 0) {ox=x;oy=y;}
drawline(image,x,y,ox,oy);
ox=x;oy=y;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment