[music-dsp] designing wavetables

Laurent de Soras [Ohm Force] laurent at ohmforce.com
Thu May 8 06:12:00 EDT 2003


Urs Heckmann wrote:
> 
> I guess the best way to do this is using iFFT with 1024 real values 
> only (imaginary values introduce phase shift and screw up zero 
> crossings?!?), where for each bandlimitted subtable a certain range of 
> values is zeroed out.

You can also use my FFTReal class <http://ldesoras.free.fr/src/FFTReal-1.03.zip>,
which performs FFT on real numbers and is roughly equivalent
to the FHT regarding CPU load.

I have also a function to build the mipmaps. The following code uses
an auxiliary class not given here to store the wavetables, I think
its members are self-explaining :

void build_mipmaps (WavetableDataType &wavetable)
{
    // Copy first table into temporary zone
    const int      bigger_table = wavetable.get_nbr_tables () - 1;
    WavetableDataType::DataType *   bwt_ptr = wavetable.use_table (bigger_table);
    std::vector <FFTReal::flt_t> temp (WavetableDataType::MAX_SIZE);
    for (long i = 0; i < WavetableDataType::MAX_SIZE; ++i)
    {
       temp [i] = static_cast <FFTReal::flt_t> (bwt_ptr [i]);
    }

    FFTReal        fft (WavetableDataType::MAX_SIZE);
    std::vector <FFTReal::flt_t> bins (WavetableDataType::MAX_SIZE);

    // Get spectrum data of the longest wavetable
    fft.do_fft (&bins [0], &temp [0]);
    fft.rescale (&bins [0]);
    long           nbr_used_bins = _max_table_size / 2;
    const long     imag_index = nbr_used_bins;

    // Build all other wavetables
    for (int table = bigger_table - 1; table >= 0; --table)
    {
       // Reduce spectrum bandwidth by 1/2
       const long     old_nbr_used_bins = nbr_used_bins;
       nbr_used_bins /= 2;
       for (long bin = nbr_used_bins + 1; bin < old_nbr_used_bins; ++bin)
       {
          bins [bin] = 0;
          bins [imag_index + bin] = 0;
       }
       bins [old_nbr_used_bins] = 0;   // Kill real part of old nyquist freq
       bins [imag_index + nbr_used_bins] = 0;   // Kill imag part of new nyquist freq

       // Transform
       fft.do_ifft (&bins [0], &temp [0]);

       // Decimate if required
       const long     table_len = wavetable.get_table_len (table);
       const long     step = _max_table_size / table_len;
       for (long pos = 0; pos < table_len; ++pos)
       {
          const WavetableDataType::DataType   val =
             static_cast <WavetableDataType::DataType> (temp [pos * step]);
          wavetable.set_sample (table, pos, val);
       }
    }

    wavetable.update_all_tables_unroll ();
}

I have tweaked it a bit to isolate it from its context and
to make it work stand-alone, so I hope I haven't introduced
too much errors ;). Tell me if you need more info.

-- Laurent

==================================+========================
Laurent de Soras                  |               Ohm Force
DSP developer & Software designer |  Digital Audio Software
mailto:laurent at ohmforce.com       | http://www.ohmforce.com
==================================+========================




More information about the music-dsp mailing list