|
|||
Hello.
I'm currently exploring writing a vibrato program/plug-in and I have it mostly working pretty well except for what sounds like sample noise in the output. I've parsed the code and stepped through breakpoints several times, but the problem is eluding me. Here is a sample of the output with the undesired noise: http://www.christianfloisand.com/vibtest.wav Here is the code (un-optimized for easier reading): SR = 44100 VDEL_T = 0.0005 // variable delay time PHASE = 0 // phase for sine wave modifier MDEL_S = (int) VDEL_T * SR // maximum delay in samples buffer = new float[1024] // soundfile buffer delayBuf = new float[MDEL_S] memset (delayBuf, 0, sizeof(float)*MDEL_S) writeIndex = 0 // write position for delayBuf // the vibrato function, using variable delay and a sine wave LFO // to modulate the delay time void vibrato (float *input, float *delayBuf, int *writeIndex, int frames) { int readIndex; float out, delSamples, rawPos, fract, next; for (int i = 0; i < frames; i++) { // frames = 1024 // modulate delay time by sine wave LFO delSamples = (VDEL_T * sin(PHASE) * SR; if (delSamples > MDEL_S) delSamples = (float) MDEL_S; // calculate read pos in buffer relative to write pos rawPos = *writeIndex - delSamples; // and check bounds within circular buffer, delayBuf rawPos = (rawPos >= 0 ? (rawPos < MDEL_S ? rawPos : rawPos - MDEL_S) : rawPos + MDEL_S; readIndex = (int) rawPos; // get read pos in buffer frac = rawPos - readIndex; // for interpolation if (readIndex != MDEL_S-1) next = delayBuf[readIndex+1]; else next = delayBuf[0]; out = delayBuf[readIndex] + frac * (next - delayBuf[readIndex]); delayBuf[*writeIndex] = input[i]; input[i] = out; // wrap writeIndex if needed if (*writeIndex != MDEL_S) *writeIndex++; else *writeIndex = 0; PHASE += TWOPI * freq / SR; // increment phase, freq = 6.4Hz if (PHASE >= TWOPI) PHASE -= TWOPI; if (PHASE < 0) PHASE += TWOPI; } } // in the main loop, read from soundfile (in) into buffer // (vector size of 1024), process vibrato on buffer, // then write to output file (out) do { readCount = sf_readf_float(in, buffer, VECTORSIZE); vibrato(buffer, delayBuf, &writeIndex, readCount); writeCount = sf_writef_float(out, buffer, readCount); } while (readCount); Any ideas what is causing the sample noise? I'm using a slightly modified variable delay algorithm from a text ("Audio Programming", by Boulanger & Lazzarini). And so far I'm only handling mono files until I get it perfected (rid of the noise). Many thanks for any feedback. Chris |
|||
| ^ | Joined: 15 Apr 2012 Member: #278696 Location: Toronto, ON | ||
|
|||
write a delay class and apply unit tests.
once you have a working delay object applying a modulation to the time is trivial. here is a very quick example: class delay { public: delay() { time = 0; size = 0; buffer = 0; end = 0; pos = 0; } ~delay() { if (buffer) delete [] buffer; } INL int get_pos() { int p = pos - buffer - time; return (p >= 0 ? p : p + size); } INL void set_size(int n) { if (size != n) { size = n; time = 0; fraction = 0.0f; float *n = new float[size]; float *t = buffer; buffer = n pos = buffer; end = buffer + size; clear(); if (t) { delete [] t; } } } INL int get_size() { return size; } INL void set_time(float v) { ASSERT(v >= 0); ASSERT(v < size); time = ftol(v); fraction = v - time; } INL int get_time() { return time; } INL void clear() { if (buffer) { float *p = buffer; while (p < end) { *p++ = 0.0f; } } } INL void advance() { ASSERT(pos >= buffer); ASSERT(pos < end); ASSERT(end > buffer); pos++; if (pos >= end) pos = buffer; } INL float read_lerp(int i, float f) { ASSERT(pos); float *A = pos - i; float *B = pos - i - 1; if (B < buffer) { B += size; if (A < buffer) { A += size; } } return lerp(*A, *B, f) + 1e-10f; } INL float read() { return read_lerp(time, fraction); } INL void feed(float input) { ASSERT(pos); *pos = 1E-10f + input; advance(); } INL float read_feed(float input) { float tmp = read(); feed(input); return tmp; } private: int size; float *buffer; float *end; float *pos; int time; float fraction; }; it could use a LOT more assertions to make sure everything is always valid. these can be defined only when you have a specific define like ENABLE_ASSERTIONS. you can then set your project configuration up so that you have release, debug, test/assert. the set_size function could actually allocate a new size and schedule the buffers to be exchanged on the next process call. it's quite complex enough for a simple example though. then it just becomes a matter of calling constructor() { delay.set_size(max_time); } process() { delay.set_time(base_time + modulation); for (i = 0; i < samples; i++) { output = delay.read_feed(input); } } if you do anything wrong the assertions will trigger to show you what you messed up. |
|||
| ^ | Joined: 07 Dec 2004 Member: #50793 | ||
|
|||
I did start out by coding the algorithm I gave above to work with a simple constant delay, and it does -- it works perfectly fine with a constant delay. Looking over your code that you provided helped me find a solution though! At the top of the loop where I calculate the variable delay in samples I had:
delaySamples = baseDelayTime * sine() * SR Then I changed it to this, which solved my problem: delaySamples = ((baseDelayTime / 2) + (sine() * baseDelayTime / 2)) * SR Works like a charm! Thanks for the feedback. |
|||
| ^ | Joined: 15 Apr 2012 Member: #278696 Location: Toronto, ON | ||
|
|||
don't forget that you can't have a delay of zero if you read before feed. you have to add special code to handle that. you'll figure that out if you implement a comb filter / flanger. |
|||
| ^ | Joined: 07 Dec 2004 Member: #50793 | ||
|
|||
Yeah, that makes sense. I'll keep that in mind, thanks! |
|||
| ^ | Joined: 15 Apr 2012 Member: #278696 Location: Toronto, ON |
| KVR Forum Index » DSP and Plug-in Development | All times are GMT - 8 Hours |
|
Printable version |
Disclaimer: All communications made available as part of this forum and any opinions, advice, statements, views or other information expressed in this forum are solely provided by, and the responsibility of, the person posting such communication and not of kvraudio.com (unless kvraudio.com is specifically identified as the author of the communication).
Powered by phpBB © phpBB Group















