Tutorial - Changing sample pitch in real time
Implementing New Voice Type for Melody - Sampled Instrument
Objective: Demonstrate how to expand the functionality using the framework, showing examples of how to:
- add a new type of voice, played by a real instrument
- use this voice for melody, by changing pitch in real time
Prerequisities
If you haven't done so, please start with the first tutorial in the series to make sure you have all equipment and software ready.
Get Started
Let's assume you got the IDE installed, board connected to SWD and you tried the flashing utility to see that it communicates well.
Find a sample you want to use for the new instrument, it should be a WAV file, mono, 16bit. The sampling rate is not too important here.
Remove headers, so we have raw data (if you don't, some glitches might be heard) and save the file with "bin" extension.
Note down the file size.
Upload the bin file to a location in memory, where there is free space, using ST-Link utility (detailed steps here).
The Code
This may be surprising, but only one or two lines needs to be added to the code, as we have ready from previous tutorial.You remember the bit that looked like this:
if(drum_samples_ptr[i] >= 0) //if playing
{
//translate from 16-bit binary format to float
drum_machine_return_sample +=
((float)((int16_t*)(drum_bases[i]))[drum_samples_ptr[i]])
* DRUM_SAMPLE_VOLUME;
drum_samples_ptr[i]++;
...
}
In order to change the pitch of sample played back, let's change code like this (Variables have been renamed slightly too, from drum_* to bell_*):
if(bell_samples_ptr[i] >= 0) //if playing
{
//all the magic happens here:
sample_ptr = bell_samples_ptr[i] * bell_note_freq / 523.3f * 2;
if(sample_ptr < wavetable_lengths[i]) //do not overrun real sample length
{
//translate from 16-bit binary format to float
bell_return_sample +=
((float)((int16_t*)(bell_bases[i]))[sample_ptr]) * BELL_SAMPLE_VOLUME;
}
bell_samples_ptr[i]++;
...
}
Why "bell_note_freq / 523.3f * 2;"?
The goal here is to move the pointer slower or faster, depending on how far the desired note's frequency is from "base" frequency, in which the sample has been recorded at given sampling rate. In our case, the sample is C5 note, which has 523.3 Hz. Sample pointer's position will be recalculated by the ratio of our desired melody note's frequency vs this basic frequency.
Also, you know that difference between two octaves means doubling the frequency. Original sample might have been recorded at different sampling rate (for example. 44.1k vs 22.05k , and therefore sounded too high pitched. The last multiplication by two will move the pointer twice the speed, producing one octave lower sounding output.
Curious how it sounds?
This time sound recording only, check it you here on SoundCloud.