/* Copyright (C) 2000 Stefan Westerfeld stefan@space.twc.de 2001, 2003 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 "artsflow.h" #include "stdsynthmodule.h" #include "debug.h" #include #include #include #undef DEBUG_MESSAGES using namespace std; using namespace Arts; namespace Arts { class AudioToByteStream_impl : public AudioToByteStream_skel, public StdSynthModule { long _samplingRate, _channels, _bits; long sampleSize; double step; bool interpolate; vector leftbuffer; vector rightbuffer; int range; double _pos; protected: void updateSampleSize() { sampleSize = _channels * _bits / 8; } public: AudioToByteStream_impl() : _pos(0) { samplingRate(44100); channels(2); bits(16); } long samplingRate() { return _samplingRate; } void samplingRate(long newRate) { double newStep = samplingRateFloat / (float)newRate; arts_return_if_fail(newStep > 0); _samplingRate = newRate; step = newStep; double delta = step - floor(step); interpolate = fabs(delta) > 0.001; #ifdef DEBUG_MESSAGES arts_debug( "samplingRate(%i): step = %e, delta = %e, interpolate: %i", newRate, step, delta, interpolate ); #endif } long channels() { return _channels; } void channels(long newChannels) { arts_return_if_fail(newChannels == 1 || newChannels == 2); _channels = newChannels; updateSampleSize(); } long bits() { return _bits; } void bits(long newBits) { arts_return_if_fail(newBits == 8 || newBits == 16); _bits = newBits; range = (newBits == 8 ) ? 128 : 32768; updateSampleSize(); } void calculateBlock(unsigned long samples) { leftbuffer.resize( 1 + samples ); rightbuffer.resize( 1 + samples ); for( unsigned long i = 0; i < samples; ++i ) { leftbuffer[1 + i] = (left[i] > 1.0f) ? 1.0f : (left[i] < -1.0f) ? -1.0f : left[i]; rightbuffer[1 + i] = (right[i] > 1.0f) ? 1.0f : (right[i] < -1.0f) ? -1.0f : right[i]; } int samplestosend = (int)ceil(leftbuffer.size() / step); DataPacket *packet = outdata.allocPacket( samplestosend * sampleSize ); #ifdef DEBUG_MESSAGES arts_debug( "calculateBlock(%i): send %i samples", samples, samplestosend ); #endif int processed = 0; if( interpolate ) { double pos = 0; if( _channels == 2 ) { if( _bits == 16 ) { while( _pos < (double)leftbuffer.size() - 1 ) { double error = modf(_pos, &pos); int intpos = (int)pos; #ifdef DEBUG_MESSAGES arts_debug( "pos=%i, error=%e", intpos, error ); #endif long leftchannel = long((leftbuffer[intpos] * (1.0 - error) + leftbuffer[intpos + 1] * error) * 32768) + 32768; long rightchannel = long((rightbuffer[intpos] * (1.0 - error) + rightbuffer[intpos + 1] * error) * 32768) + 32768; packet->contents[processed ] = leftchannel; packet->contents[processed + 1] = (leftchannel >> 8) - 128; packet->contents[processed + 2] = rightchannel; packet->contents[processed + 3] = (rightchannel >> 8) - 128; _pos += step; processed += 4; } } else if( _bits == 8 ) { while( _pos < (double)leftbuffer.size() - 1 ) { double error = modf(_pos, &pos); int intpos = (int)pos; long leftchannel = long((leftbuffer[intpos] * (1.0 - error) + leftbuffer[intpos + 1] * error) * 128) + 128; long rightchannel = long((rightbuffer[intpos] * (1.0 - error) + rightbuffer[intpos + 1] * error) * 128) + 128; packet->contents[processed ] = leftchannel; packet->contents[processed + 1] = rightchannel; _pos += step; processed += 2; } } } else { if( _bits == 16 ) { while( _pos < (double)leftbuffer.size() - 1 ) { double error = modf(_pos, &pos); int intpos = (int)pos; long leftchannel = long(((leftbuffer[intpos] + rightbuffer[intpos]) * (1.0 - error) + (leftbuffer[intpos + 1] + rightbuffer[intpos + 1]) * error) * 16384) + 32768; packet->contents[processed ] = leftchannel; packet->contents[processed + 1] = (leftchannel >> 8) - 128; _pos += step; processed += 2; } } else if( _bits == 8 ) { while( _pos < (double)leftbuffer.size() - 1 ) { double error = modf(_pos, &pos); int intpos = (int)pos; long leftchannel = long(((leftbuffer[intpos] + rightbuffer[intpos]) * (1.0 - error) + (leftbuffer[intpos + 1] + rightbuffer[intpos + 1]) * error) * 64) + 128; packet->contents[processed] = leftchannel; _pos += step; ++processed; } } } } else { if( _channels == 2 ) { if( _bits == 16 ) { while( _pos < (double)leftbuffer.size() - 1 ) { int intpos = (int)_pos; long leftchannel = long(leftbuffer[intpos] * 32768) + 32768; long rightchannel = long(rightbuffer[intpos] * 32768) + 32768; packet->contents[processed ] = leftchannel; packet->contents[processed + 1] = (leftchannel >> 8) - 128; packet->contents[processed + 2] = rightchannel; packet->contents[processed + 3] = (rightchannel >> 8) - 128; _pos += step; processed += 4; } } else if( _bits == 8 ) { while( _pos < (double)leftbuffer.size() - 1 ) { int intpos = (int)_pos; long leftchannel = long(leftbuffer[intpos] * 128) + 128; long rightchannel = long(rightbuffer[intpos] * 128) + 128; packet->contents[processed ] = leftchannel; packet->contents[processed + 1] = rightchannel; _pos += step; processed += 2; } } } else { if( _bits == 16 ) { while( _pos < (double)leftbuffer.size() - 1 ) { int intpos = (int)_pos; long leftchannel = long((leftbuffer[intpos] + rightbuffer[intpos]) * 16384) + 32768; packet->contents[processed ] = leftchannel; packet->contents[processed + 1] = (leftchannel >> 8) - 128; _pos += step; processed += 2; } } else if( _bits == 8 ) { while( _pos < (double)leftbuffer.size() - 1 ) { int intpos = (int)_pos; long leftchannel = long((leftbuffer[intpos] + rightbuffer[intpos]) * 64) + 128; packet->contents[processed] = leftchannel; _pos += step; ++processed; } } } } leftbuffer[0] = leftbuffer.back(); rightbuffer[0] = rightbuffer.back(); _pos = _pos - floor(_pos); packet->size = processed; packet->send(); #ifdef DEBUG_MESSAGES arts_debug( "calculateBlock(%i): %i samples sent, _pos = %e", samples, processed / sampleSize, _pos ); #endif } }; REGISTER_IMPLEMENTATION(AudioToByteStream_impl); }