/* * 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 * */ #ifndef Auralizer_hxx #define Auralizer_hxx #include #include #include #include #include #include "EquidistantPointsFunction.hxx" #include #include #include #include #include #include "vmDataTypes.hxx" class AuralizationPlayer : public QThread { Q_OBJECT public: enum PlayStatus {Stoped, Paused, Playing}; AuralizationPlayer(QObject* parent=0) : QThread(parent) , mPlayStatus(Stoped) , mSamplingRate(44100.0) , mBeginTime(0.0) , mTimeBounds(0.0,1.0) , mBPF(0) , mAudio0(0) , mAudio1(0) , mPitchBounds(min_ref,max_ref) , _useOscillator(true) , _useAudio(false) { } virtual ~AuralizationPlayer() { if (mPlayStatus != Playing) return; mPlayStatus = Stoped; terminate(); wait(); } void SetDuration(double dur) { if(dur <= 0) return; mTimeBounds.min = 0.0; mTimeBounds.max = dur; mBeginTime = 0.0; } void SetSamplingRate(double sr) { mSamplingRate = sr; } void useAudio(bool useIt=true) { _useAudio = useIt; } void useOscillator(bool useIt=true) { _useOscillator = useIt; } bool IsPlaying() const { return mPlayStatus == Playing; } void SetData(const CLAM::BPF& bpf) { mBPF = &bpf; } enum { LEFT=1, RIGHT=2}; void SetAudioPtr(const CLAM::Audio* audio, unsigned channelMask=LEFT|RIGHT) { if (channelMask & LEFT) mAudio0 = audio; if (channelMask & RIGHT) mAudio1 = audio; } void SetPitchBounds(double min, double max) { if(min >= max) return; mPitchBounds.min = min; mPitchBounds.max = max; } signals: void playingTime(double); void stopTime(double, bool); public slots: void play() { mPlayStatus = Playing; start(); } void pause() { mPlayStatus = Paused; } void stop() { mPlayStatus = Stoped; wait(); } void timeBounds(double min, double max) { if(min < 0) return; if(min >= max) return; mTimeBounds.min = min; mTimeBounds.max = max; mBeginTime = mTimeBounds.min; } protected: volatile PlayStatus mPlayStatus; double mSamplingRate; double mBeginTime; CLAM::VM::Range mTimeBounds; const CLAM::BPF* mBPF; const CLAM::Audio* mAudio0; const CLAM::Audio* mAudio1; CLAM::VM::Range mPitchBounds; bool _useOscillator; bool _useAudio; static const double min_ref; static const double max_ref; private: void run() { if(!mAudio0) { _useAudio=false; _useOscillator=true; } if(mAudio0) mSamplingRate = mAudio0->GetSampleRate(); else mSamplingRate=44100; unsigned frameSize = 4092; CLAM::AudioManager manager(mSamplingRate,(int)frameSize); manager.Start(); CLAM::AudioOut channel0; CLAM::AudioIOConfig audioOutCfg0; audioOutCfg0.SetChannelID(0); channel0.Configure(audioOutCfg0); CLAM::AudioOut channel1; CLAM::AudioIOConfig audioOutCfg1; audioOutCfg1.SetChannelID(1); channel1.Configure(audioOutCfg1); channel0.Start(); channel1.Start(); CLAM::SimpleOscillatorConfig oscCfg; oscCfg.SetSamplingRate(mSamplingRate); oscCfg.SetAmplitude(0.6); CLAM::SimpleOscillator osc(oscCfg); CLAM::Audio samplesAudio0; CLAM::Audio samplesAudio1; CLAM::Audio samplesBpf; samplesAudio0.SetSize(frameSize); samplesAudio1.SetSize(frameSize); samplesBpf.SetSize(frameSize); CLAM::Audio silence; silence.SetSize(frameSize); int bpfIndex = FirstIndex(); unsigned nSamples = unsigned(mTimeBounds.max*mSamplingRate); unsigned leftIndex = unsigned(mBeginTime*mSamplingRate); osc.Start(); for(unsigned i=leftIndex; i < nSamples; i+=frameSize) { if (mPlayStatus!=Playing) break; unsigned rightIndex = leftIndex+frameSize; if (mBPF && mBPF->Size() && bpfIndex+1Size() && mBPF->GetXValue(bpfIndex+1)<= i/mSamplingRate) bpfIndex++; 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() && bpfIndex < mBPF->Size()) SendFloatToInControl(osc,"Pitch",GetPitch(bpfIndex)); osc.Do(samplesBpf); if (mBPF && mBPF->Size() && leftIndex/mSamplingRate < mBPF->GetXValue(bpfIndex)) { channel0.Do(silence); channel1.Do(silence); } else if (_useAudio) { channel0.Do(samplesAudio0); channel1.Do(_useOscillator? samplesBpf : samplesAudio1); } else { channel0.Do(samplesBpf); channel1.Do(samplesBpf); } emit playingTime(double(leftIndex)/mSamplingRate); leftIndex += 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 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 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; } }; class Auralizer { public: CLAM::Audio mClick; ///< Synthetized click for onsets CLAM::Audio mOnsetAuralizationAudio; ///< Current audio with segmentation marks inserted const CLAM::Audio * _currentAudio; public: AuralizationPlayer* mPlayer; Auralizer(QObject * parent) : _currentAudio(0) { mPlayer = new AuralizationPlayer(parent); initClick(); } void play() { mPlayer->play(); } void stop() { mPlayer->stop(); } void pause() { mPlayer->pause(); } bool isPlaying() { return mPlayer->IsPlaying(); } void seekTo(double miliseconds, double endMiliseconds) { mPlayer->timeBounds(miliseconds, endMiliseconds); } void setOptions(bool playOnsets, bool playLLDs) { CLAM_ASSERT(_currentAudio, "Auralizer::setOptions without audio"); mPlayer->SetAudioPtr(_currentAudio); if (playOnsets) mPlayer->SetAudioPtr(&mOnsetAuralizationAudio, AuralizationPlayer::RIGHT); mPlayer->useAudio(true); mPlayer->useOscillator( playLLDs ); } void setAudio(const CLAM::Audio & audio) { _currentAudio= & audio; mPlayer->SetAudioPtr(_currentAudio); mPlayer->SetDuration(double(audio.GetDuration())/1000.0); } void setSegmentation(const CLAM::Segmentation * segmentation) { if (!segmentation) return; CLAM_ASSERT(_currentAudio, "Auralizer::setOptions without audio"); const std::vector & marks = segmentation->onsets(); int nMarks = marks.size(); mOnsetAuralizationAudio.SetSize(0); mOnsetAuralizationAudio.SetSize(_currentAudio->GetSize()); mOnsetAuralizationAudio.SetSampleRate(_currentAudio->GetSampleRate()); int size = mOnsetAuralizationAudio.GetSize(); for (int i=0; iGetSampleRate()); if (samplePositionSetData(epf.GetBPF()); double minValue = epf.getMin(); double maxValue = epf.getMax(); // TODO: Move this margin to the widget double span = maxValue-minValue; minValue -= span*0.1; maxValue += span*0.1; mPlayer->SetPitchBounds(minValue, maxValue); } private: void initClick() { mClick.SetSize(1000); CLAM::OscillatorConfig cfg; cfg.SetFrequency(1000); cfg.SetAmplitude(1); cfg.SetSamplingRate(44100); CLAM::Oscillator osc(cfg); osc.Start(); osc.Do(mClick); osc.Stop(); } }; #endif//Auralizer_hxx