diff --git a/Makefile b/Makefile index 1d7fb1e..7b57192 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ CC = /usr/bin/clang++ GDB = /usr/bin/gdb OLEVEL = -O2 -CFLAGS = -Wall -std=c++20 $(OLEVEL) -o $(PROJ) +CFLAGS = -Wall -std=c++17 $(OLEVEL) -o $(PROJ) -OBJECTS = src/wtpp.cpp +OBJECTS = src/wtpp.cpp src/wave.cpp src/wavetable.cpp src/generators.cpp build: $(CC) $(CFLAGS) $(OBJECTS) diff --git a/src/generators.cpp b/src/generators.cpp new file mode 100644 index 0000000..4933980 --- /dev/null +++ b/src/generators.cpp @@ -0,0 +1,85 @@ +#include "generators.h" +#include "wave.h" + +sample_table_t gen_sin() +{ + // Make the new Wavetable object + sample_table_t sin_vals = {0}; + // Make a place to store calculated value + float_t val = 0; + + // Loop through number of samples and set table values + for (uint16_t i = 0; i < DEFAULT_N_SAMPLES; i++) { + // Calculate the value of sin at position + val = std::sin((2 * M_PI * i) / DEFAULT_N_SAMPLES); + sin_vals[i] = val; + } + // Return the completed Wavetable object + return sin_vals; +} + +sample_table_t gen_squ() +{ + sample_table_t squ_vals = {0}; + + // Start high and go low at halfway + for (uint16_t i = 0; i < DEFAULT_N_SAMPLES; i++) { + if (i < (DEFAULT_N_SAMPLES / 2)) { + squ_vals[i] = 1; + } else { + squ_vals[i] = 0; + } + } + + return squ_vals; +} + +sample_table_t gen_saw() +{ + sample_table_t saw_vals = {0}; + float_t step = 2.0 / DEFAULT_N_SAMPLES; // calculate our incremental step size + float_t val = 0; // place to store calculate value + + // Start low go high [0, 1] + for (uint16_t i = 0; i < DEFAULT_N_SAMPLES; i++) { + saw_vals[i] = val; + val += step; + } + + return saw_vals; +} + +sample_table_t gen_tri() +{ + sample_table_t tri_vals = {0}; + uint16_t half_samples = DEFAULT_N_SAMPLES / 2; + float_t step = 2.0 / half_samples; // calculate our incremental step size + float_t val = 0; // place to store calculate value + + // Start low go high then low [0, 1, 0] + for (uint16_t i = 0; i < DEFAULT_N_SAMPLES; i++) { + tri_vals[i] = val; + if (i < half_samples) { + val += step; + } else { + val -= step; + } + } + + return tri_vals; +} + +sample_table_t gen_isaw() +{ + sample_table_t isaw_vals = {0}; + float_t step = 2.0 / DEFAULT_N_SAMPLES; // calculate our incremental step size + float_t val = 1; // place to store calculate value + + // Start high go low [1, 0] + for (uint16_t i = 0; i < DEFAULT_N_SAMPLES; i++) { + isaw_vals[i] = val; + val -= step; + } + + return isaw_vals; +} diff --git a/src/generators.h b/src/generators.h new file mode 100644 index 0000000..9e84223 --- /dev/null +++ b/src/generators.h @@ -0,0 +1,37 @@ +/*! @file generators.h + @brief Header for wave cycle data generators + */ +#ifndef GENERATORS_H_ +#define GENERATORS_H_ + +#include "math.h" +#include + +#include "wave.h" + +/*! Generate sine wave data + @return a table of values + */ +sample_table_t gen_sin(); + +/*! Generate square wave data + @return a table of values + */ +sample_table_t gen_squ(); + +/*! Generate saw wave data + @return a table of values + */ +sample_table_t gen_saw(); + +/*! Generate inverse saw wave data + @return a table of values + */ +sample_table_t gen_isaw(); + +/*! Generate triangle wave data + @return a table of values + */ +sample_table_t gen_tri(); + +#endif // GENERATORS_H_ diff --git a/src/wave.cpp b/src/wave.cpp new file mode 100644 index 0000000..f0e5938 --- /dev/null +++ b/src/wave.cpp @@ -0,0 +1,10 @@ +#include "wave.h" + +// Initialize index at 0 for wave cycles and wave tables +uint16_t Wave::m_nid = 0; + +void Wave::print_head() { + for (uint8_t i = 0; i < 3; i++) { + std::cout << m_table[i] << '\n'; + } +} diff --git a/src/wave.h b/src/wave.h new file mode 100644 index 0000000..de12395 --- /dev/null +++ b/src/wave.h @@ -0,0 +1,41 @@ +/*! @file wave.h + @brief Header for Wave class and associated Wave functions + */ +#ifndef WAVE_H_ +#define WAVE_H_ + +#include +#include +#include + +#include + +const uint16_t DEFAULT_N_SAMPLES = 1024; + +using sample_table_t = std::array; + +/*! @class Wave wave.h "wave.h" + @brief Single cycle wave object with lookup table + */ +class Wave { +private: + static uint16_t m_nid; /*!< Unique ID number of NEXT wave */ + sample_table_t m_table; /*!< Table of sample data */ + +public: + const uint16_t m_cid; /*!< Unique ID of current wavetable */ + Wave() : m_cid(m_nid++) {} + + /*! ID getter */ + uint16_t getId() { return m_cid; } + + /*! Sample data table setter + @param table Sample data table + */ + void setTable(sample_table_t table) { m_table = table; } + + /*! Prints the first 3 values of sample data */ + void print_head(); +}; + +#endif // WAVE_H_ diff --git a/src/wavetable.cpp b/src/wavetable.cpp new file mode 100644 index 0000000..b59149d --- /dev/null +++ b/src/wavetable.cpp @@ -0,0 +1,11 @@ +#include "wavetable.h" + +// Initialize index at 0 for wave cycles and wave tables +uint16_t Wavetable::m_nid = 0; + +std::string Wavetable::name() { + std::string id_str = std::to_string(m_cid); + id_str.append(": "); + id_str.append(m_name); + return id_str; +} diff --git a/src/wavetable.h b/src/wavetable.h new file mode 100644 index 0000000..6b462bf --- /dev/null +++ b/src/wavetable.h @@ -0,0 +1,41 @@ +/*! @file wavetable.h + @brief Header for Wavetable class and associated table functions + */ +#ifndef WAVETABLE_H_ +#define WAVETABLE_H_ + +#include +#include +#include + +#include "wave.h" + +/* Number of Wave cycle objects in table */ +const uint16_t DEFAULT_N_WAVES = 256; + +using wave_table_t = std::array; + +/*! @class Wavetable wavetable.h "wavetable.h" + @brief Object containing a table of single cycle Wave objects + */ +class Wavetable { +private: + static uint16_t m_nid; /*!< Unique ID number of wavetable */ + std::string m_name; /*!< String name of wavetable */ + wave_table_t m_wave_table; /*!< Table of Wave objects */ + +public: + const uint16_t m_cid; /*!< Unique ID of NEXT wavetable */ + Wavetable(std::string name, wave_table_t wt) + : m_name{name}, m_wave_table{wt}, m_cid(m_nid++) {} + + /*! ID getter */ + uint16_t getId() { return m_cid; } + + /*! Makes formatted name and id string + @return a formatted string in the form "id: name" + */ + std::string name(); +}; + +#endif // WAVETABLE_H_ diff --git a/src/wtpp.cpp b/src/wtpp.cpp new file mode 100644 index 0000000..bc65bfb --- /dev/null +++ b/src/wtpp.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "wave.h" +#include "generators.h" +#include "wavetable.h" + +static const uint32_t DEFAULT_SAMPLE_RATE = 44100; // 44.1 kHz sampling rate +static const uint8_t DEFAULT_BIT_DEPTH = 12; + +/*! Logs a message + @param message The string to be logged + */ +static void log(std::string message) +{ + std::cout << "wtpp: " << message << '\n'; +} + +int main() +{ + log("Generating wave cycle lookup tables"); + Wave sin_wave, squ_wave, saw_wave, tri_wave, isaw_wave; + + // Calculate fundamental wave values + sample_table_t sin_vals = gen_sin(); + sample_table_t squ_vals = gen_squ(); + sample_table_t saw_vals = gen_saw(); + sample_table_t tri_vals = gen_tri(); + sample_table_t isaw_vals = gen_isaw(); + + // Set wave lookup table values + sin_wave.setTable(sin_vals); + squ_wave.setTable(squ_vals); + saw_wave.setTable(saw_vals); + tri_wave.setTable(tri_vals); + isaw_wave.setTable(isaw_vals); + + log("Printing head of sine table"); + sin_wave.print_head(); + log("Printing head of square table"); + squ_wave.print_head(); + log("Printing head of saw table"); + saw_wave.print_head(); + log("Printing head of triangle table"); + tri_wave.print_head(); + log("Printing head of inverse saw table"); + isaw_wave.print_head(); + + // Create wave table of all fundamental Wave objects + wave_table_t fundies = {sin_wave, squ_wave, saw_wave, tri_wave, isaw_wave}; + Wavetable wt_01{"Fundamental Waves", fundies}; + log(wt_01.name()); + + return 0; +}