You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/arts/modules/synth/synth_delay_impl.cpp

139 lines
4.3 KiB

/*
Copyright (C) 2000 Jeff Tranter
tranter@pobox.com
Stefan Westerfeld
stefan@space.twc.de
Jens Hahn
Jens.Hahn@t-online.de
2001 Matthias Kretz
kretz@kde.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "artsmodulessynth.h"
#include "stdsynthmodule.h"
#include <math.h>
using namespace Arts;
// This delays the input signal for an amount of time. The time
// specification must be between 0 and 1 for a delay between 0 seconds
// and 1 second.
//
// This kind of delay may not be used in feedback structures. This is
// because it's a variable delay. You can modify it's length while it
// is running, and even set it down to zero. But since in a feedback
// structure the own output is needed to calculate the next samples, a
// delay whose value could drop to zero during synthesis could lead to
// a stall situation.
//
// Use CDELAYs in that setup, perhaps combine a small constant delay
// (of 0.001 seconds) with a flexible delay.
//
// You can also combine a CDELAY and a DELAY to achieve a variable
// length delay with a minimum value in a feedback loop. Just make
// sure that you have a CDELAY involved.
class Synth_DELAY_impl : virtual public Synth_DELAY_skel,
virtual public StdSynthModule
{
protected:
unsigned long _buffersize;
unsigned long _bitmask;
float * _buffer;
float _maxdelay;
unsigned int _writepos;
public:
Synth_DELAY_impl() : _buffersize( 0 ), _bitmask( 0 ), _buffer( 0 ), _maxdelay( 0 ), _writepos( 0 )
{
maxdelay( 1 ); // take a one second buffer if nothing else is specified
}
~Synth_DELAY_impl()
{
delete[] _buffer;
}
void streamInit()
{
// initialize buffer to all zeroes
for ( unsigned long i = 0; i < _buffersize; i++ )
_buffer[i] = 0.0;
}
void calculateBlock(unsigned long samples)
{
for( unsigned long i = 0; i <samples; i++ )
{
double int_pos;
double error = modf( time[i] * samplingRateFloat, &int_pos );
unsigned long readpos1 = ( _writepos - (unsigned long)(int_pos) ) & _bitmask;
unsigned long readpos2 = ( readpos1 - 1 ) & _bitmask; // Shouldn't this be +1? (mkretz)
// No, it's right this way:
// ( 1 - error ) needs to be multiplied with the second
// sample; error with the first
_buffer[_writepos] = invalue[i];
outvalue[i] = _buffer[readpos1] * ( 1 - error ) + _buffer[readpos2] * error;
_writepos++;
_writepos &= _bitmask;
}
}
float maxdelay() { return _maxdelay; }
void maxdelay(float newmaxdelay)
{
if( newmaxdelay <= 0 )
return;
_maxdelay = newmaxdelay;
double n = ceil( log( double(_maxdelay * samplingRateFloat) ) / log( 2. ) );
unsigned long newbuffersize = (unsigned long)( pow( 2, n ) );
unsigned long newbitmask = newbuffersize - 1;
if( newbuffersize != _buffersize )
{
float *newbuffer = new float[newbuffersize];
if( newbuffersize > _buffersize ) {
for( unsigned long i = 0; i < _buffersize; i++ ) {
newbuffer[i] = _buffer[_writepos];
_writepos++;
_writepos &= newbitmask;
}
for( unsigned long i = _buffersize; i < newbuffersize; i++ )
newbuffer[i] = 0;
} else {
_writepos -= newbuffersize;
_writepos &= newbitmask;
for( unsigned long i = 0; i < newbuffersize; i++ ) {
newbuffer[i] = _buffer[_writepos];
_writepos++;
_writepos &= newbitmask;
}
}
_buffer = newbuffer;
_buffersize = newbuffersize;
_bitmask = newbitmask;
}
maxdelay_changed( _maxdelay );
}
};
REGISTER_IMPLEMENTATION(Synth_DELAY_impl);