here's how my method works:
use wavosaur, the free wav editor. under the file pin, select 'export as text,' you'll get a .txt file with content like..
0.0001910
-0.0012646
-0.0020047
0.0203930
use a text editor and add
f,
at the end of each line (indicating the values are float variables if you're new to c++) and pull the unneeded zeroes before the decimal points to save space..
.0001910f,
-.0012646f,
-.0020047f,
.0203930f,
(((then, if you have a good text editor, remove (most of?) the carriage returns so it's on a smaller amount of lines... i removed carriage returns with crimson editor, recording a 'macro' of joining values in groups of 100... this will make vertical scrolling more convenient for editing the file as it will be 10s of thousands of lines long otherwise))))
..so you have a .txt file that looks like
.0001910f, -.0012646f, -.0020047f, .0203930f,
the process loop for the sem is:
Code: Select all
void Module::sub_process(long buffer_offset, long sampleFrames )
{
float *in1 = buffer_offset + input1_buffer;
float *in2 = buffer_offset + input2_buffer;
float *out1 = buffer_offset + output1_buffer;
while(--sampleFrames >= 0) {
if (*in2 > 0.f && gatebuf <= 0.f) {
inc = pow(2.f, (*in1 * 10.f) - 5.f) * sratio;
count = 0.f;
}
if (count < 9754.f) {
c = (int)count;
//d = count - (float)c;
//o = wave[c] + (wave[c+1] - wave[c]) * d;
o = wave[c];
count += inc;
if (count >= 9754) o = 0.f;
}
*out1 = o;
gatebuf = *in2;
in1++;
in2++;
out1++;
}
}
remember, pow(2, 0) is 1.00000f. sratio is 44100.f / samplerate, producing 1.0 at 44100 and 0.5 at 88200 et c.
with a pitch of 5 and a samplerate of 44100, inc is 1, the sample is incremented by 1 for each sample
in this case, my sample is 9753 samples long (array is 9754 samples, with an extra '0' at the end).
linear interpolation is commented out
(((for faster code inc and count can be done with integers.. instead of using a decimal variable, 'inc' is a large integer, eg. progressing at 4096, then the read position integer is derived from count using a bitshift, like readposition = count >> 12 - this makes the pitch slightly less accurate but can reduce cpu, and is suitable for noisy percussion samples.)))
the only thing that's left is to get the sample data into the sem... as said, i'm not used to declaring preset data. i tried declaring wave[] as a const in the .cpp file, this produced a large cpu spike on the first trigger but fine otherwise.
the best performance i get is to declare a temporary array with the sample data and then pass it to the wave[] array, which is declared in the header. there's no cpu spike, and so far (i've only used a few 10's of thousands of smaple data so far) quick startup.
my header looks like this..
Code: Select all
void zchannels(); // i make a separate function for writing data to arrays
private:
float *input1_buffer; // pitch pin
float *input2_buffer; // gate pin
float *output1_buffer;
short int sample; // various list entry pins for my module
short int mode;
short int active;
float samplerate;
float sratio; // this is declared as 44100.f / samplerate :)
int i;
float o;
float wave[9754];
float count;
float inc;
int c;
float d;
float gatebuf;
int static_count;
Code: Select all
void Module::open()
{
SEModule_base::open();
SET_PROCESS_FUNC(Module::sub_process);
samplerate = getSampleRate();
sratio = 44100.f / samplerate;
activebuf = -97; // not used in this tutorial
zchannels();
o = 0.f; // i declare i and o as my all-purpose temporary int and float vaiables
count = 40000.f;
inc = 1.f;
c = 0;
d = 0.f;
gatebuf = -97.f;
getPin(PN_OUTPUT1)->TransmitStatusChange( SampleClock(), ST_RUN);
}
and the zchannels() function looks like this...
Code: Select all
void Module::zchannels() {
float temp1[9754] = {
.019013f, .084689f, .181677f.....
......
......
..... 0.000031f, 0.000061f};
for (i = 0; i < 9754; i++) {
wave[i] = temp1[i];
}
wave[9754] = 0.f;
}
i'll post a demo sem later once i've improved the performance (the above is ~2x se native osc during playback due to the float to int conversion, doesn't sleep, is smaller than 1x native osc between playback, so uses about 1x se osc cpu during normal intermittent triggering. you'll also note that pitch is only calculated at sample triggering, this is easy to amend
once your SEM base code is built, it takes a few minutes of using a text editor to format the sample data, and voila! solid, reliable, and if you tweak the above code as described, fairly cpu efficient
