Best way to incorporate wav audio into a module?

Hiya @CircadianSound! I’ve put together a demo for you that embeds a 44,100 Hz sample as code into a VCV Rack module! :tada:

Here’s the code:

#include "kick.hpp"

#define KICK_SAMPLE_LENGTH 22820

struct Circadian : Module
{
  dsp::SchmittTrigger playback_trigger;
  float left_audio = 0;
  float right_audio = 0;
  bool playback = false;
  double playback_position = 0;
  
  enum ParamIds {
    PLAYBACK_BUTTON,
    NUM_PARAMS
  };
  enum InputIds {
    NUM_INPUTS
  };
  enum OutputIds {
    AUDIO_OUTPUT_LEFT,
    AUDIO_OUTPUT_RIGHT,
    NUM_OUTPUTS
  };
  
  Circadian()
  {
    config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
  }
  
  void process(const ProcessArgs &args) override
  {
    if(playback_trigger.process(params[PLAYBACK_BUTTON].getValue()))
    {
      // reset sample playback position
      playback_position = 0;
      
      // Set playback flag.  The sample will playback while this is true
      playback = true;
    }
    
    if(playback)
    {
      // 44100 is the sample rate of the recorded sample
      float step_amount = 44100 / args.sampleRate;
      
      // Step the playback position forward.
      playback_position = playback_position + step_amount;
      
      // convert float to integer
      unsigned int sample_position = playback_position;
      
      // If the playback position is past the playback length, end sample playback
      if(sample_position >= KICK_SAMPLE_LENGTH)
      {
        playback_position = 0;
        playback = false;
      }
      else
      {
        left_audio = kick_drum[sample_position][0];
        right_audio = kick_drum[sample_position][1];
        
        outputs[AUDIO_OUTPUT_LEFT].setVoltage(left_audio);
        outputs[AUDIO_OUTPUT_RIGHT].setVoltage(right_audio);
      }
    }
  }
};

struct CircadianWidget : ModuleWidget
{
  CircadianWidget(Circadian* module)
  {
    setModule(module);
    setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/looper_front_panel.svg")));
    
    // Add output jacks
    addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.560, 35.0)), module, Circadian::AUDIO_OUTPUT_LEFT));
    addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.560, 40.0)), module, Circadian::AUDIO_OUTPUT_RIGHT));
    
    // Add playback input
    addParam(createParamCentered<LEDButton>(mm2px(Vec(7.560, 5)), module, Circadian::PLAYBACK_BUTTON));
  }
};

You’ll notice that the only include is kick.hpp. It’s a bit long to paste here, but here’s a sample of what it contains…

  float kick_drum[][2] = {
    { -0.000030,-0.000061 },
    { -0.000030,-0.000030 },
    { 0.000000,-0.000091 },
    { 0.000000,-0.000091 },
    { -0.000031,-0.000061 },  // etc...

Here’s how I generated the sample data. First, I used Wavosaur to export a kick drum as text.

image

This left me with a pretty awful file to work with that looked like:

-0.000030	-0.000061	
-0.000030	-0.000030	
0.000000	-0.000091	
0.000000	-0.000091	
-0.000031	-0.000061

I wrote a quick PHP program to get this closer to what I needed:

<?PHP
  /*
    For prepping samples for vcvrack embed
  */

  $input_data = file_get_contents("circadian.txt");
  $lines = explode("\r\n",$input_data);
  $output_text = "{";
  $pair_count = 0;
  foreach($lines as $line)
  {
    $pair_count ++;
    list($left_audio, $right_audio) = explode("	", $line);
    $output_text .= "{ $left_audio,$right_audio },";
  }

  $output_text .= "}";

  file_put_contents("output.text", $output_text);
  print("pair count: $pair_count");
?>

The resulting output is essentially what I used in kick.hpp, but I had to remove a trailing comma that I was too lazy to fix in the PHP code.

Here’s the code on GitHub:

Here’s a video of it in action. I borrowed a module’s front panel and didn’t spend any time on customizing it:

6 Likes