wavetable loading checkpoint
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
build/*
|
build/*
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
scripts/_pycache_/*
|
||||||
@@ -21,7 +21,7 @@ This synthesizer isn't very good, but it's neat :3
|
|||||||
oscillators increase the sound complexity considerably
|
oscillators increase the sound complexity considerably
|
||||||
- [x] Create a UI scope to visualize the synthesized composite waveform
|
- [x] Create a UI scope to visualize the synthesized composite waveform
|
||||||
- [x] Create wavetables for more complex tone generation. Needs to be selectable from ui
|
- [x] Create wavetables for more complex tone generation. Needs to be selectable from ui
|
||||||
- [ ] Wavetable file loading
|
- [x] Wavetable file loading
|
||||||
- [x] Create digital filters, prob biquad. Controllable from ui obv (cutoff + resonance)
|
- [x] Create digital filters, prob biquad. Controllable from ui obv (cutoff + resonance)
|
||||||
- [x] Add polyphony somewhere. Probably involves a voice class. If processing power
|
- [x] Add polyphony somewhere. Probably involves a voice class. If processing power
|
||||||
allows it, tie a voice to each midi note
|
allows it, tie a voice to each midi note
|
||||||
|
|||||||
BIN
config/wavetables/sine.wt
Normal file
BIN
config/wavetables/sine.wt
Normal file
Binary file not shown.
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
def process(phase):
|
def process(phase):
|
||||||
print("im from process")
|
return math.sin(phase)
|
||||||
|
|||||||
@@ -3,30 +3,60 @@
|
|||||||
# a wavetable file consists of a one-dimensional array of samples representing one period of a waveform
|
# a wavetable file consists of a one-dimensional array of samples representing one period of a waveform
|
||||||
# metadata includes:
|
# metadata includes:
|
||||||
# - file version (for program compatibility)
|
# - file version (for program compatibility)
|
||||||
# - binary format (float, double, int32, etc.)
|
# - binary format (float, double, int32, etc.) (RIGHT NOW I ONLY USE FLOAT)
|
||||||
# - domain (normal is a phase from x=0 to x=2pi)
|
# - domain (normal is a phase from x=0 to x=2pi)
|
||||||
# - range (depending on datatypes, e.g. float=[-1,1], int32=[-2^15, 2^15-1])
|
# - range (depending on datatypes, e.g. float=[-1,1], int32=[-2^15, 2^15-1])
|
||||||
# - waveform RMS (for loudness normalization)
|
# - waveform RMS (for loudness normalization)
|
||||||
|
# - sample count
|
||||||
# the synth program uses the filename, not any metadata
|
# the synth program uses the filename, not any metadata
|
||||||
|
|
||||||
# this script uses the function defined in example_wavetable.py to calculate samples
|
# this script uses the function defined in example_wavetable.py to calculate samples
|
||||||
# if you want a custom wavetable, copy/edit/modify the example function (desmos is great for brainstorming)
|
# if you want a custom wavetable, copy/edit/modify the example function (desmos is great for brainstorming)
|
||||||
|
|
||||||
|
from array import array
|
||||||
|
import math
|
||||||
|
|
||||||
import example_wavetable
|
import example_wavetable
|
||||||
|
|
||||||
|
wavetableLength = 2048
|
||||||
|
|
||||||
def createFile():
|
def createFile():
|
||||||
print("creating file")
|
print("creating file")
|
||||||
return 1
|
file = open("sine.wt", "wb")
|
||||||
|
return file
|
||||||
|
|
||||||
def writeMetadata(file):
|
def writeMetadata(file):
|
||||||
print("im writing metadata")
|
print(">> im writing metadata")
|
||||||
|
|
||||||
def generateWavetable(file):
|
def generateWavetable(file):
|
||||||
print("im generating the wavetable")
|
print(">> im generating the wavetable")
|
||||||
example_wavetable.process()
|
|
||||||
|
# init variables
|
||||||
|
data_list = [None] * wavetableLength
|
||||||
|
phaseInc = 2*math.pi / wavetableLength
|
||||||
|
x = 0
|
||||||
|
accumulator = 0
|
||||||
|
|
||||||
|
# generate each discrete sample
|
||||||
|
for i in range(wavetableLength):
|
||||||
|
sample = example_wavetable.process(x)
|
||||||
|
accumulator += sample * sample
|
||||||
|
x += phaseInc
|
||||||
|
data_list[i] = sample
|
||||||
|
|
||||||
|
# normalize by rms
|
||||||
|
rms = math.sqrt(accumulator/wavetableLength)
|
||||||
|
print(">> wavetable RMS: ", rms)
|
||||||
|
for i in range(wavetableLength):
|
||||||
|
data_list[i] /= rms
|
||||||
|
|
||||||
|
# write to file
|
||||||
|
binary_data = array("f", data_list)
|
||||||
|
file.write(binary_data)
|
||||||
|
|
||||||
def closeFile(file):
|
def closeFile(file):
|
||||||
print("finishing up")
|
print(">> finishing up")
|
||||||
|
file.close()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("Hello main")
|
print("Hello main")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
WavetableController::WavetableController() {
|
WavetableController::WavetableController() {
|
||||||
// load from files
|
// load from files
|
||||||
@@ -17,17 +18,19 @@ void WavetableController::init() {
|
|||||||
|
|
||||||
wavetables_.resize(4); // resize for however many files we find
|
wavetables_.resize(4); // resize for however many files we find
|
||||||
|
|
||||||
// don't really know how the files are gonna work
|
// wavetable file structure is best explained in scripts/generate_wavetable.py
|
||||||
// but I'd like two files- a yaml that contains metadata like name, length, range, datatype, etc.
|
|
||||||
// and the main data be just a big array of that data type in a binary file
|
// read the wavetable file
|
||||||
// although having it all in a single bin makes the most sense with the metadata being in the header
|
std::ifstream inputFile("config/wavetables/sine.wt", std::ios::in | std::ios::binary);
|
||||||
|
if(!inputFile) std::cout << "error opening file" << std::endl;
|
||||||
|
inputFile.read(reinterpret_cast<char*>(wavetables_[0].data()), SYNTH_WAVETABLE_SIZE * sizeof(float));
|
||||||
|
|
||||||
float phase = 0.0f;
|
float phase = 0.0f;
|
||||||
float phaseInc = 2.0f * M_PI / static_cast<float>(SYNTH_WAVETABLE_SIZE);
|
float phaseInc = 2.0f * M_PI / static_cast<float>(SYNTH_WAVETABLE_SIZE);
|
||||||
|
|
||||||
for(int i = 0; i < SYNTH_WAVETABLE_SIZE; i++) {
|
for(int i = 0; i < SYNTH_WAVETABLE_SIZE; i++) {
|
||||||
|
|
||||||
wavetables_[0][i] = std::sin(phase) / 0.707f; // sine
|
//wavetables_[0][i] = std::sin(phase) / 0.707f; // sine
|
||||||
wavetables_[1][i] = (phase >= M_PI) ? 1.0f : -1.0f; // square
|
wavetables_[1][i] = (phase >= M_PI) ? 1.0f : -1.0f; // square
|
||||||
wavetables_[2][i] = ((phase / M_PI) - 1.0f) / 0.577f; // saw
|
wavetables_[2][i] = ((phase / M_PI) - 1.0f) / 0.577f; // saw
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user