/* * Copyright (c) 2001-2006 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "AudioIO.hxx" #include "AudioManager.hxx" #include "AudioOut.hxx" #include "SimpleOscillator.hxx" #include "vmBPFPlayer.hxx" namespace CLAM { namespace VM { const double min_ref = 8.1758; // 8.1758 Hz const double max_ref = 12545.9; // 12545.9 Hz BPFPlayer::BPFPlayer(QObject* parent) : Player(parent) , mBPF(0) , mAudio0(0) , mAudio1(0) , mPitchBounds(min_ref,max_ref) { SetPlayingFlags(CLAM::VM::eUseOscillator); } BPFPlayer::~BPFPlayer() { } void BPFPlayer::SetData(const BPF& bpf) { mBPF = &bpf; } void BPFPlayer::SetAudioPtr(const Audio* audio, unsigned channelMask) { if (channelMask&1) mAudio0 = audio; if (channelMask&2) mAudio1 = audio; } void BPFPlayer::SetPitchBounds(double min, double max) { if(min >= max) return; mPitchBounds.min = min; mPitchBounds.max = max; } void BPFPlayer::run() { if(!mAudio0) SetPlayingFlags(CLAM::VM::eUseOscillator); if(mAudio0) mSamplingRate = mAudio0->GetSampleRate(); else mSamplingRate=44100; unsigned frameSize = 4092; AudioManager manager(mSamplingRate,(int)frameSize); manager.Start(); AudioOut channel0; AudioIOConfig audioOutCfg0; audioOutCfg0.SetChannelID(0); channel0.Configure(audioOutCfg0); AudioOut channel1; AudioIOConfig audioOutCfg1; audioOutCfg1.SetChannelID(1); channel1.Configure(audioOutCfg1); channel0.Start(); channel1.Start(); SimpleOscillatorConfig oscCfg; oscCfg.SetSamplingRate(mSamplingRate); oscCfg.SetAmplitude(0.6); SimpleOscillator osc(oscCfg); Audio samplesAudio0; Audio samplesAudio1; Audio samplesBpf; samplesAudio0.SetSize(frameSize); samplesAudio1.SetSize(frameSize); samplesBpf.SetSize(frameSize); Audio silence; silence.SetSize(frameSize); unsigned firstIndex = FirstIndex(); unsigned k = firstIndex; unsigned start = unsigned(mBeginTime*mSamplingRate); unsigned nSamples = unsigned(mTimeBounds.max*mSamplingRate); unsigned leftIndex = start; unsigned rightIndex = leftIndex+frameSize; osc.Start(); for(unsigned i=start; i < nSamples; i+=frameSize) { if (mPlayStatus!=Playing) break; if(mBPF && mBPF->Size() && k+1Size() && mBPF->GetXValue(k+1)<= i/mSamplingRate) k++; if(mAudio0 && rightIndex < unsigned(mAudio0->GetSize())) mAudio0->GetAudioChunk(int(leftIndex),int(rightIndex),samplesAudio0); if(mAudio1 && rightIndex < unsigned(mAudio1->GetSize())) mAudio1->GetAudioChunk(int(leftIndex),int(rightIndex),samplesAudio1); if(mBPF && mBPF->Size() && k < mBPF->Size()) SendFloatToInControl(osc, "Pitch", GetPitch(k)); osc.Do(samplesBpf); if (mBPF && mBPF->Size() && leftIndex/mSamplingRate < mBPF->GetXValue(k)) { channel0.Do(silence); channel1.Do(silence); } else if ((mPlayingFlags & CLAM::VM::eAudio) && (mPlayingFlags & CLAM::VM::eUseOscillator)) { channel0.Do(samplesAudio0); channel1.Do(samplesBpf); } else if (mPlayingFlags & CLAM::VM::eAudio && !(mPlayingFlags & CLAM::VM::eUseOscillator)) { channel0.Do(samplesAudio0); channel1.Do(samplesAudio1); } else { channel0.Do(samplesBpf); channel1.Do(samplesBpf); } emit playingTime(double(leftIndex)/mSamplingRate); leftIndex += frameSize; rightIndex += frameSize; } osc.Stop(); channel0.Stop(); channel1.Stop(); if (mPlayStatus==Playing) mPlayStatus=Stoped; mBeginTime = (mPlayStatus==Paused) ? double(leftIndex)/mSamplingRate : mTimeBounds.min; emit stopTime(double(leftIndex)/mSamplingRate,mPlayStatus==Paused); } unsigned BPFPlayer::FirstIndex() { if (!mBPF ) return 0; unsigned nPoints = mBPF->Size(); if(nPoints <= 1) return 0; if(mBeginTime <= mBPF->GetXValue(0)) return 0; if(mBeginTime >= mBPF->GetXValue(nPoints-1)) return nPoints-1; unsigned index = 0; unsigned left_index = 0; unsigned right_index = nPoints-1; while(left_index <= right_index) { const unsigned currentIndex = (left_index+right_index)/2; if(currentIndex >= nPoints-1) { index = currentIndex; break; } if(mBeginTime >= double(mBPF->GetXValue(currentIndex)) && mBeginTime <= double(mBPF->GetXValue(currentIndex+1))) { index = currentIndex; break; } if(mBeginTime < double(mBPF->GetXValue(currentIndex))) { right_index = currentIndex-1; } else if(mBeginTime > double(mBPF->GetXValue(currentIndex))) { left_index = currentIndex+1; } } return index; } double BPFPlayer::GetPitch(unsigned index) { double value = mBPF->GetValueFromIndex(index); // if(value >= min_ref && value <= max_ref) return value; if(value < mPitchBounds.min) value = mPitchBounds.min; else if(value > mPitchBounds.max) value = mPitchBounds.max; return (value-mPitchBounds.min)*(max_ref-min_ref)/mPitchBounds.Span()+min_ref; } } } // END