Skip to content

Commit

Permalink
Some structuring; a bug fix for out wav
Browse files Browse the repository at this point in the history
1. Structuring in place to allow multiple effects at runtime
2. Close the output wav file, leading to it rendering on mac
  • Loading branch information
baconpaul committed Oct 8, 2024
1 parent d180bf7 commit 83edb03
Showing 1 changed file with 60 additions and 75 deletions.
135 changes: 60 additions & 75 deletions examples/voice-effect-example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ struct DbToLinearProvider
}
};

struct CLIArgBundle
{
std::string infileName{};
std::string outfileName{};
std::string datfileName{};
bool launchGnuplot{false};
};

struct SSTFX
{
std::array<float, 256> fb{};
Expand Down Expand Up @@ -92,101 +100,49 @@ struct SSTFX
}
};

std::unique_ptr<sst::voice_effects::utilities::VolumeAndPan<FxConfig>> fx;

// std::unique_ptr<sst::voice_effects::distortion::BitCrusher<FxConfig>> fx;

// std::unique_ptr<sst::voice_effects::dynamics::Compressor<FxConfig>> fx;

SSTFX() { dbtlp.init(); }

void init(float sampleRate)
{
sampleRate = sampleRate;
dbtlp.init();

// fx = std::make_unique<sst::voice_effects::dynamics::Compressor<FxConfig>>();
// fx->initVoiceEffect();
// fx->initVoiceEffectParams();
// fx->setFloatParam(sst::voice_effects::dynamics::Compressor<FxConfig>::fpThreshold, -10);
// fx->setFloatParam(sst::voice_effects::dynamics::Compressor<FxConfig>::fpRatio, 7);
// fx->setFloatParam(sst::voice_effects::dynamics::Compressor<FxConfig>::fpMakeUp, 3);

// fx = std::make_unique<sst::voice_effects::distortion::BitCrusher<FxConfig>>();
// fx->initVoiceEffectParams();
// fx->setFloatParam(sst::voice_effects::distortion::BitCrusher<FxConfig>::fpBitdepth, 0.3);
// fx->setFloatParam(sst::voice_effects::distortion::BitCrusher<FxConfig>::fpSamplerate,
// 0.0);

fx = std::make_unique<sst::voice_effects::utilities::VolumeAndPan<FxConfig>>();
fx->initVoiceEffectParams();
fx->setFloatParam(sst::voice_effects::utilities::VolumeAndPan<FxConfig>::fpVolume, 8);
fx->setFloatParam(sst::voice_effects::utilities::VolumeAndPan<FxConfig>::fpPan, -0.4);
}

void process(const float *const datainL, const float *const datainR, float *dataoutL,
float *dataoutR, float pitch)
{
fx->processStereo(datainL, datainR, dataoutL, dataoutR, pitch);
}
};

int main(int argc, char const *argv[])
template<typename FXT>
int exampleHarness(const CLIArgBundle &arg)
{
/*
* Set up command line arguments
*/
CLI::App app("..:: Voice Effects Example - Command Line player for SST Voice Effects ::..");

std::string infileName;
app.add_option("-i,--infile", infileName, "Input wav file for session")->required();

std::string outfileName;
app.add_option("-o,--outfile", outfileName, "Output wav file for session")->required();

std::string datfileName;
app.add_option("-d,--datfile", datfileName, "Optional plain text dat file");

bool launchGnuplot;
app.add_option("--gnuplot", launchGnuplot, "Attempt to launch gnuplot on datfile");

// TODO
// 1. Add a vec option (https://cliutils.github.io/CLI11/book/chapters/options.html)
// for float and int params
// 2. templatize the runner by type and allow you to select types with command line
// 3. RTAudio rather than file output

CLI11_PARSE(app, argc, argv);

if (launchGnuplot && datfileName.empty())
if (arg.launchGnuplot && arg.datfileName.empty())
{
std::cout << "To launch gnuplot you need to specify a datfile with -d" << std::endl;
exit(2);
return 2;
}

unsigned int channels;
unsigned int sampleRate;
drwav_uint64 totalPCMFrameCount;
float *pSampleData = drwav_open_file_and_read_pcm_frames_f32(
infileName.c_str(), &channels, &sampleRate, &totalPCMFrameCount, NULL);
arg.infileName.c_str(), &channels, &sampleRate, &totalPCMFrameCount, NULL);

// TODO - how does this report errors?
if (totalPCMFrameCount <= 0 || pSampleData == nullptr)
{
std::cout << "No samples in file. Exiting" << std::endl;
exit(2);
return 2;
}
printf("sampleRate: %d channels: %d, totalPCMFrameCount: %llu\n", sampleRate, channels,
totalPCMFrameCount);

if (channels > 2)
{
printf("Only 1 or 2 channels wav files supported, exiting.\n");
exit(3);
return 3;
}

SSTFX fx;
fx.init(sampleRate);
auto fx = std::make_unique<FXT>();
fx->sampleRate = sampleRate;
fx->initVoiceEffectParams();
fx->setFloatParam(0 /*sst::voice_effects::utilities::VolumeAndPan<FxConfig>::fpVolume */, 8);
fx->setFloatParam(1 /*sst::voice_effects::utilities::VolumeAndPan<FxConfig>::fpPan*/, -0.4);

static constexpr auto blockSize = SSTFX::FxConfig::blockSize;

uint32_t total_blocks = totalPCMFrameCount / blockSize;
Expand All @@ -198,14 +154,14 @@ int main(int argc, char const *argv[])
auto outputSamples = new float[totalPCMFrameCount * 2];

FILE *datFile{nullptr};
if (!datfileName.empty())
if (!arg.datfileName.empty())
{
datFile = fopen(datfileName.c_str(), "w");
datFile = fopen(arg.datfileName.c_str(), "w");

if (!datFile)
{
std::cout << "Datfile not open at '" << datfileName << "'" << std::endl;
exit(4);
std::cout << "Datfile not open at '" << arg.datfileName << "'" << std::endl;
return 4;
}
}

Expand All @@ -230,7 +186,7 @@ int main(int argc, char const *argv[])
}
}

fx.process((const float *)&inputL[0], (const float *)&inputR[0], &outputL[0], &outputR[0],
fx->processStereo((const float *)&inputL[0], (const float *)&inputR[0], &outputL[0], &outputR[0],
1);

for (size_t sample_index = 0; sample_index < blockSize; sample_index++)
Expand All @@ -254,22 +210,51 @@ int main(int argc, char const *argv[])
format.container = drwav_container_riff;
format.format = DR_WAVE_FORMAT_IEEE_FLOAT;
format.channels = 2;
format.sampleRate = 44100;
format.sampleRate = sampleRate;
format.bitsPerSample = 32;
drwav_init_file_write(&wav, outfileName.c_str(), &format, NULL);
std::cout << "Writing " << sample_count << " r=" << sampleRate << " sample wav file to " << arg.outfileName << std::endl;
if (!drwav_init_file_write(&wav, arg.outfileName.c_str(), &format, nullptr))
{
std::cout << "Cannot init file write the outfile" << std::endl;
return 3;
}
drwav_uint64 framesWritten = drwav_write_pcm_frames(&wav, sample_count, outputSamples);
drwav_uninit(&wav);

delete[] outputSamples;

if (launchGnuplot)
if (arg.launchGnuplot)
{
auto cmd = fmt::format("gnuplot -p -e \"plot '{}' using 1:2 with lines, '' using "
"1:3 with lines\"",
datfileName);
arg.datfileName);
std::cout << "Launching " << cmd << std::endl;
system(cmd.c_str());
}
return 0;
}

int main(int argc, char const *argv[])
{
/*
* Set up command line arguments
*/
CLI::App app("..:: Voice Effects Example - Command Line player for SST Voice Effects ::..");
CLIArgBundle arg;

app.add_option("-i,--infile", arg.infileName, "Input wav file for session")->required();
app.add_option("-o,--outfile", arg.outfileName, "Output wav file for session")->required();
app.add_option("-d,--datfile", arg.datfileName, "Optional plain text dat file");
app.add_option("--gnuplot", arg.launchGnuplot, "Attempt to launch gnuplot on datfile");

return 0;
// TODO
// - Add a vec option (https://cliutils.github.io/CLI11/book/chapters/options.html)
// for float and int params
// - RTAudio rather than file output
// - Add a ringout option

CLI11_PARSE(app, argc, argv);

// This style will allow us to have a switch statement in the near future for effect
return exampleHarness<sst::voice_effects::utilities::VolumeAndPan<SSTFX::FxConfig>>(arg);
}

0 comments on commit 83edb03

Please sign in to comment.