Wavetable from RAW sd file

apiel

Member
I try to load a sound file from the SD to build a wave table. I am playing around and somehow it is working. My main concern is how to handle the frequency. At first I though to think about a sound sample like a cycle, so at 1Hz the sound would be played once, 2Hz twice... But this didn't sound right to me when it came to play notes. So I decided to have a base frequency (C4) and modulate the speed to play the sample base on this frequency. This seem to work better, at least for what I want to do. But I actually wonder if there is not a proper algorithm to do this. (I am still beginning with synthetisis and mainly trying thing out in a freestyle way) Following is the code:

Code:
#ifndef AUDIO_SYNTH_WAVE_TABLE_SD_H_
#define AUDIO_SYNTH_WAVE_TABLE_SD_H_

#include <Arduino.h>
#include <AudioStream.h>

template <uint16_t MAX_TABLE_SIZE = 24000>
class AudioSynthWaveTableSD : public AudioStream {
   public:
    AudioSynthWaveTableSD() : AudioStream(0, NULL), magnitude(16384) {}
    AudioSynthWaveTableSD *frequency(float freq) {
        if (freq <= 0.0) {
            phase_increment = 0.0;
        } else {
            phase_increment = freq / baseFreq;
        }
        return this;
    }

    AudioSynthWaveTableSD *amplitude(float n) {
        magnitude = constrain(n, 0.0, 1.0);
        return this;
    }

    void update(void) {
        audio_block_t *block = allocate();

        if (block == NULL || magnitude == 0.0 || phase_increment == 0.0)
            return;  // but here we might still want to increase the
                     // phase_accumulator

        for (unsigned int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
            phase_accumulator += phase_increment;
            if ((uint32_t)phase_accumulator > end) {
                phase_accumulator = start;
            }
            block->data[i] =
                (int16_t)(data[(uint32_t)phase_accumulator] * magnitude);
        }

        transmit(block);
        release(block);
    }

    bool load(const char *filename) {
        File rawfile;
        rawfile = SD.open(filename);
        if (!rawfile || !rawfile.available()) {
            return false;
        }
        size = rawfile.read(data, min(MAX_TABLE_SIZE, rawfile.size()));
        end = min(end, size);

        rawfile.close();
        return true;
    }

    AudioSynthWaveTableSD *setBaseFreq(float freq) {
        baseFreq = freq;
        return this;
    }

    AudioSynthWaveTableSD *setStart(uint32_t val) {
        start = val;
        return this;
    }

    AudioSynthWaveTableSD *setEnd(uint32_t val) {
        end = min(val, size);
        return this;
    }

   private:
    float baseFreq = 440.0;
    float phase_accumulator;
    float phase_increment;
    float magnitude;
    int16_t data[MAX_TABLE_SIZE];

    uint32_t size = 0;
    uint32_t end = MAX_TABLE_SIZE;
    uint32_t start = 0;
};

#endif

I would love to get feedback to improve the code :)
 
Phase accumulators typically have many more bits than used to index the table - the fractional part gives the ability to
interpolate between neighbouring samples and greatly reduce artifacts - have a look at how this in done in the
AudioSynthWaveform object for the ARBITRARY_WAVEFORM case in the audio lib sources:

https://github.com/PaulStoffregen/Audio/blob/master/synth_waveform.cpp


There's also the more complex AudioSynthWavetable class you might want to try out, come to that.
 
Thanks for your advice. I was actually first trying to make my wavetable base on the ARBITRARY_WAVEFORM but I couldn't reproduce the sound I wanted, this is why I come up with the solution just over. Base on your advice I tried again but I don't manage to get the whole wave and unfortunately I don't understand the logic behind the ARBITRARY_WAVEFORM, especially the purpose of all those bits shifting. This is what I did so far https://github.com/apiel/groovebox/blob/main/AudioSynthWaveTableSD2.h

And my first version is https://github.com/apiel/groovebox/blob/main/AudioSynthWaveTableSD.h

I will keep investigating, maybe I can understand better.
 
Hi MarkT, what are you calling DDS? cause when I search on google, I am not sure about what to pickup :p
 
Back
Top