Created
July 17, 2022 09:32
-
-
Save chbtoys/978de513b61ae51d5a3f6e8aecd67861 to your computer and use it in GitHub Desktop.
audio programming - beginner level
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
// 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