1 /* === S Y N F I G ========================================================= */
2 /*! \file audiocontainer.cpp
3 ** \brief Audio Container implementation File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
33 #include <sigc++/signal.h>
35 #include <ETL/stringf>
37 //#include <ETL/thread>
38 #include <glibmm/thread.h>
40 #include <synfig/general.h>
42 #include <glibmm/main.h>
44 #include "audiocontainer.h"
61 /* === U S I N G =========================================================== */
65 using namespace synfig;
67 /* === M A C R O S ========================================================= */
70 #define AUDIO_OUTPUT FSOUND_OUTPUT_OSS
73 /* === G L O B A L S ======================================================= */
74 const double delay_factor = 3;
76 /* === P R O C E D U R E S ================================================= */
78 /* === M E T H O D S ======================================================= */
80 /* === E N T R Y P O I N T ================================================= */
82 //Help constructing stuff
84 using studio::AudioContainer;
87 bool build_profile(FSOUND_SAMPLE *sample, double &samplerate, std::vector<char> &samples)
89 bool build_profile(FSOUND_SAMPLE */*sample*/, double &/*samplerate*/, std::vector<char> &/*samples*/)
94 float sps = samplerate;
96 //trivial rejection...
97 if(!sample || sps < 1)
99 synfig::warning("build_profile: Sample rate was too low or sample was invalid");
103 //lock for all samples and process them into a subset
104 unsigned int mode = FSOUND_Sample_GetMode(sample);
106 //make sure that it's 8 bit... I hope this works...
108 //sample rate of the actual song...
109 int allsamplerate = 0;
110 FSOUND_Sample_GetDefaults(sample,&allsamplerate,0,0,0);
112 //get the size of the sample defaults from the mode
114 int channelsize = 1; //number of bytes
116 if(mode & FSOUND_16BITS) channelsize = 2; //this shouldn't happen
117 if(mode & FSOUND_STEREO) channels = 2;
119 //Get the sample information
120 int samplesize = channels*channelsize; //the only two things that increase samplesize
121 int numsamples = FSOUND_Sample_GetLength(sample); //number of samples in the sound
122 int sizeall = samplesize*numsamples; //should be the size of the entire song...
126 synfig::warning("ProfileAudio: Sample buffer cannot be size smaller than 1 (%X)",FSOUND_GetError());
130 //be sure that the new sample rate is less than or equal to the original
131 if(sps > allsamplerate) sps = allsamplerate;
133 float stride = allsamplerate/(float)sps;
135 //down sampling to 8 bit min/max values
136 synfig::warning("About to downsample from %d Hz to %.1f Hz, sample stride: %f", allsamplerate, sps, stride);
138 char *sampledata=0,*useless = 0;
139 unsigned int len1,len2;
140 // vector<char> samples;
142 if(!FSOUND_Sample_Lock(sample,0,sizeall,(void**)&sampledata,(void**)&useless,&len1,&len2))
144 synfig::warning("ProfileAudio: Unable to lock the sound buffer... (%X)",FSOUND_GetError());
147 synfig::warning("Locked: %X: %d bytes, %X: %d bytes",sampledata,len1,useless,len2);
152 char *iter = sampledata;
153 char *end = iter + sizeall;
156 float numinc = sps/(float)allsamplerate;
158 /* Loop per sample DDA alg.
163 //HACK - to prevent if statement inside inner loop
164 //synfig::warning("wo baby wo baby, inc: %d, stride: %f, size: %d", inc, stride, sizeall);
167 int maxs = 0, mins = 0;
169 for(;curaccum < 1; curaccum += numinc)
171 for(i = 0; iter < end && i < channels; ++i, iter += channelsize)
173 maxs = std::max(maxs,(int)*iter);
174 mins = std::min(mins,(int)*iter);
177 //insert onto new list
178 samples.push_back(maxs);
179 samples.push_back(mins);
181 //and flush all the used samples for curaccum
184 }else if(channelsize == 2)
187 char *iter = sampledata;
188 char *end = iter + sizeall;
191 float numinc = sps/(float)allsamplerate;
193 /* Loop per sample DDA alg.
198 //HACK - to prevent if statement inside inner loop
199 //synfig::warning("wo baby wo baby, inc: %d, stride: %f, size: %d", inc, stride, sizeall);
202 int maxs = 0, mins = 0;
204 for(;curaccum < 1; curaccum += numinc)
206 for(i = 0; iter < end && i < channels; ++i, iter += channelsize)
208 maxs = std::max(maxs,(int)*(short*)iter);
209 mins = std::min(mins,(int)*(short*)iter);
212 //insert onto new list
213 samples.push_back(maxs / 256);
214 samples.push_back(mins / 256);
216 //and flush all the used samples for curaccum
222 synfig::warning("Stats: %f seconds with %d bytes now %d bytes", (samples.size()/2)/sps, sizeall, samples.size());
223 synfig::warning(" %f seconds before", numsamples/(float)allsamplerate);
225 //we're done yay!, unlock
226 FSOUND_Sample_Unlock(sample,sampledata,useless,len1,len2);
227 synfig::info("Unlocked");
229 //FSOUND_PlaySound(FSOUND_FREE,sound); //test
232 samplerate = sps*2; //it must be x2 because we are sampling max and min
244 //FMOD Systemwide Specific data mostly here...
249 static double buffer_length_sec = 0;
251 //------- Scrubbing --------------
252 /* Scrubbing works as follows:
254 The sound is played using PlaySoundEx
255 we specify a user created DSP for scrubbing
256 set it initially to inactive
258 When the program initiates it
259 we set the initial data in the shared structure and activate the dsp unit
260 then for each cursor update we get we set the value in the shared structure
264 If IsPlaying just governs the channel play/stop value or if it also concerns the pause state
268 //so we can know where to create all this stuff
271 /* Linearly fit the frequency to hit the desired zero point...
273 /*struct scrubelement
277 //the amount of time left til the cursor hits this one
278 // it's incremental so that the cursor must pass previous
279 // ones before decrementing this value
283 //the time it should take to get to the next position...
285 //to prevent from writing to the same location at once... (pos, deltatime, delaystart)
288 //the queue system would provide a more accurate representation...
290 volatile double deltatime;
292 volatile double delaystart; //the amount of time we need to go before we start interpolating...
294 volatile int channel;
296 /*std::list<scrubelement> queue;
298 volatile int channel;
300 //current position is FSOUND_GetCurrentPosition and current time is always 0...
302 void add(const scrubelement &elem)
306 queue.push_back(elem);
311 //Function to safely get rid of all the old samples (dt < 0)
316 while(queue.size() && queue.front().dt < 0)
334 //All parameters and state should be set by the time we get here...
335 void scrub_dsp_process()
337 const double epsilon = 1e-5;
339 //Trivial reject... we go nowhere if we aren't playing (hit boundary...)
340 if(!FSOUND_IsPlaying(channel)) return;
342 //Get rid of all the old samples
345 //Trivial reject #2 - We also go nowhere with no future samples (pause)
346 /*if(queue.size() <= 0)
348 FSOUND_SetPaused(channel,true);
352 double dt = buffer_length_sec;
354 //Lock ourselves so we don't die
357 //printf("DSP data: delay = %.3f s, pos = %d, dt = %.3f\n", delaystart, (int)pos, deltatime);
366 dt = -delaystart; //add time back...
371 //Trivial reject for if we're past current sample...
372 if(delaystart > 0 || deltatime <= 0)
374 FSOUND_SetPaused(channel,true);
379 //Calculate stretched frequency based on delayed future sample...
381 //NOTE: BY NOT TRACKING POSITION AS A FLOAT AND JUST USING THE SOUNDS VALUE
382 // WE ARE LOSING A TINY AMOUNT OF PRECISION ACCURACY EVERY UPDATE
383 // (THIS SHOULDN'T BE A PROBLEM)
384 const double p0 = FSOUND_GetCurrentPosition(channel);
387 if(!FSOUND_GetPaused(channel))
389 curdp = FSOUND_GetFrequency(channel) * deltatime;
392 //need to rescale derivative...
394 //Extrapolate from difference in position and deltatime vs dt...
395 const double pa = p0 + curdp/2;
397 const double p1 = pos;
399 //const double pb = p0/3 + p1*2/3;
401 //will extrapolate if needed... (could be funky on a curve)
403 if(deltatime > epsilon)
408 //Decrement deltatime (we may have gone past but that's what happens when we don't get input...)
411 //we don't need to look at the current variables anymore...
414 const double invt = 1-t;
415 //double deltapos = (p1-p0)*t; //linear version
416 double deltapos = invt*invt*p0 + 2*t*invt*pa + t*t*p1 - p0; //quadratic smoothing version
418 //Attempted cubic smoothing
419 //const double invt2 = invt*invt;
420 //const double t2 = t*t;
421 //double deltapos = invt2*invt*p0 + 3*t*invt2*pa + 3*t2*invt*pb + t2*t*p1;
422 //double deltapos = p0 + t*(3*(pa-p0) + t*(3*(p0+2*pa+pb) + t*((p1-3*pb+3*ba-p0)))); //unwound cubic
424 //printf("\ttime = %.2f; p(%d,%d,%d) dp:%d - delta = %d\n",t,(int)p0,(int)p1,(int)p2,(int)curdp,(int)deltapos);
426 //Based on the delta info calculate the stretched frequency
427 const int dest_samplesize = FSOUND_DSP_GetBufferLength();
429 //rounded to nearest frequency... (hopefully...)
430 int freq = (int)(deltapos * FSOUND_GetOutputRate() / (double)dest_samplesize);
432 //NOTE: WE MIGHT WANT TO DO THIS TO BE MORE ACCURATE BUT YEAH... ISSUES WITH SMALL NUMBERS
433 //double newdp = deltapos / t;
435 //printf("\tfreq = %d Hz\n", freq);
437 // !If I failed... um assume we have to pause it... ?
440 FSOUND_SetPaused(channel,true);
443 //synfig::info("DSP f = %d Hz", freq);
444 FSOUND_SetPaused(channel,false);
445 if(!FSOUND_SetFrequency(channel,freq))
447 //ERROR WILL ROBINSON!!!...
448 printf("Error in Freq... what do I do?\n");
456 /* //for use with multiple
457 //each one is a 'handle' to a pointer that will be effected by something else
458 typedef scrubinfo** value_type;
459 typedef std::set< value_type > scrubslist;
462 //so we can lock access to the list...
465 void AddScrub(scrubinfo **i)
472 void RemoveScrub(scrubinfo **i)
479 scrubinfo * volatile * scrub;
482 //Scrubbing data structures
483 static const int default_scrub_priority = 5; //between clear and sfx/music mix
484 static scrubuserdata g_scrubdata = {0};
485 static FSOUND_DSPUNIT *scrubdspunit = 0;
487 void * scrubdspwrap(void *originalbuffer, void *newbuffer, int length, void *userdata)
489 //std::string dsp = "DSP";
492 scrubuserdata &sd = *(scrubuserdata*)userdata;
494 /* //For use with multiple scrubs...
495 //Lock so no one can write to it while we're reading from it...
498 //make a copy of it...
499 std::vector<scrubinfo**> v(sd.scrubs.begin(),sd.scrubs.end());
501 //other things can do stuff with it again...
502 sd.lock.UnLockRead();
504 //loop through the list and process all the active scrub units
505 std::vector<scrubinfo**>::iterator i = v.begin(),
509 //check to make sure this object is active...
512 (**i)->scrub_dsp_process();
517 if(sd.scrub && *sd.scrub)
519 //dsp += " processing...";
520 scrubinfo * info = (*sd.scrub);
521 info->scrub_dsp_process();
530 //------- Class for loading fmod on demand -------
532 class FMODInitializer
538 FMODInitializer():loaded(false),refcount(0) {}
549 synfig::info("Initializing FMOD on demand...");
552 FSOUND_SetOutput(AUDIO_OUTPUT);
554 /*int numdrivers = FSOUND_GetNumDrivers();
555 synfig::info("Num FMOD drivers = %d",numdrivers);
556 synfig::info("Current Driver is #%d", FSOUND_GetDriver());
558 for(int i = 0; i < numdrivers; ++i)
560 unsigned int caps = 0;
561 FSOUND_GetDriverCaps(i,&caps);
563 synfig::info(" Caps for driver %d (%s) = %x",i,FSOUND_GetDriverName(i),caps);
566 FSOUND_SetDriver(0);*/
568 //Modify buffer size...
569 //FSOUND_SetBufferSize(100);
571 if(!FSOUND_Init(44100, 32, 0))
573 synfig::warning("Unable to load FMOD");
578 //Create the DSP for processing scrubbing...
579 scrubdspunit = FSOUND_DSP_Create(&scrubdspwrap,default_scrub_priority,&g_scrubdata);
581 //Load the number of sec per buffer into the global variable...
582 buffer_length_sec = FSOUND_DSP_GetBufferLength() / (double)FSOUND_GetOutputRate();
588 //add to the refcount
590 //synfig::info("Audio: increment fmod refcount %d", refcount);
597 synfig::warning("FMOD refcount is already 0...");
601 //synfig::info("Audio: decrement fmod refcount %d", refcount);
603 //NOTE: UNCOMMENT THIS IF YOU WANT FMOD TO UNLOAD ITSELF WHEN IT ISN'T NEEDED ANYMORE...
608 bool is_loaded() const { return loaded; }
618 if(loaded && refcount <= 0)
621 synfig::info("Unloading FMOD");
622 if(scrubdspunit) FSOUND_DSP_Free(scrubdspunit);
630 //The global counter for FMOD....
631 FMODInitializer fmodinit;
635 //----- AudioProfile Implementation -----------
636 void studio::AudioProfile::clear()
642 handle<AudioContainer> studio::AudioProfile::get_parent() const
647 void studio::AudioProfile::set_parent(etl::handle<AudioContainer> i)
652 double studio::AudioProfile::get_offset() const
655 return parent->get_offset();
659 //---------- AudioContainer definitions ---------------------
661 struct studio::AudioContainer::AudioImp
663 //Sample load time information
664 FSOUND_SAMPLE * sample;
670 double offset; //time offset for playing...
672 //We don't need it now that we've adopted the play(t) time schedule...
673 //current time... and playing info....
677 //Make sure to sever our delayed start if we are stopped prematurely
678 sigc::connection delaycon;
683 etl::clock timer; //for getting the time diff between scrub input points
685 //Scrubbing information...
686 //the current position of the sound will be sufficient for normal stuff...
693 bool is_scrubbing() const {return scrptr != 0;}
695 void set_scrubbing(bool s)
697 void set_scrubbing(bool /*s*/)
708 //helper to make sure we are actually playing (and to get a new channel...)
712 if(!FSOUND_IsPlaying(channel))
716 //play sound paused etc.
717 channel = FSOUND_PlaySoundEx(FSOUND_FREE,sample,0,true);
718 if(channel < 0 || FSOUND_GetError() != FMOD_ERR_NONE)
720 synfig::warning("Could not play the sample...");
726 FSOUND_SetPaused(channel,true);
727 FSOUND_SetFrequency(channel,sfreq);
748 //reuse the channel...
750 channel = FSOUND_FREE;
759 public: //helper/accessor funcs
760 bool start_playing_now() //callback for timer...
765 //Make sure the sound is playing and if it is un pause it...
767 FSOUND_SetPaused(channel,false);
771 return false; //so the timer doesn't repeat itself
777 return FSOUND_IsPlaying(channel);
786 return FSOUND_GetPaused(channel);
793 public: //forward interface
795 //Accessors for the offset - in seconds
796 const double &get_offset() const {return offset;}
797 void set_offset(const double &d)
802 //Will override the parameter timevalue if the sound is running, and not if it's not...
804 bool get_current_time(double &out)
806 bool get_current_time(double &/*out*/)
812 unsigned int pos = FSOUND_GetCurrentPosition(channel);
814 //adjust back by 1 frame... HACK....
815 //pos -= FSOUND_DSP_GetBufferLength();
818 out = pos/(double)sfreq + offset;
826 //Big implementation functions...
827 bool load(const std::string &filename, const std::string &filedirectory);
834 //scrubbing functions
835 void start_scrubbing(double t);
836 void scrub(double t);
837 void stop_scrubbing();
845 //--------------- Audio Container definitions --------------------------
846 studio::AudioContainer::AudioContainer()
851 studio::AudioContainer::~AudioContainer()
853 if(imp) delete (imp);
856 bool studio::AudioContainer::load(const std::string &filename,const std::string &filedirectory)
863 profilevalid = false;
864 return imp->load(filename,filedirectory);
868 handle<studio::AudioProfile> studio::AudioContainer::get_profile(float samplerate)
870 handle<studio::AudioProfile> studio::AudioContainer::get_profile(float /*samplerate*/)
875 //if we already have done our work, then we're good
876 if(profilevalid && prof)
878 //synfig::info("Using already built profile");
882 //synfig::info("Before profile");
883 //make a new profile at current sample rate
885 //NOTE: We might want to reuse the structure already there...
886 prof = new AudioProfile;
887 prof->set_parent(this); //Our parent is THIS!!!
891 synfig::warning("Couldn't allocate audioprofile...");
892 return handle<studio::AudioProfile>();
895 //setting the info for the sample rate
896 //synfig::info("Setting info...");
898 synfig::info("Building Profile...");
899 prof->samplerate = samplerate;
900 if(build_profile(imp->sample,prof->samplerate,prof->samples))
902 synfig::info(" Success!");
907 return handle<studio::AudioProfile>();
912 return handle<studio::AudioProfile>();
917 void studio::AudioContainer::clear()
925 profilevalid = false;
928 void studio::AudioContainer::play(double t)
930 if(imp) imp->play(t);
933 void studio::AudioContainer::stop()
938 bool studio::AudioContainer::get_current_time(double &out)
940 if(imp) return imp->get_current_time(out);
944 void AudioContainer::set_offset(const double &s)
946 if(imp) imp->set_offset(s);
949 double AudioContainer::get_offset() const
951 static double zero = 0;
953 return imp->get_offset();
957 bool AudioContainer::is_playing() const
964 bool AudioContainer::is_scrubbing() const
967 return imp->is_scrubbing();
971 void AudioContainer::start_scrubbing(double t)
973 if(imp) imp->start_scrubbing(t);
976 void AudioContainer::stop_scrubbing()
978 if(imp) imp->stop_scrubbing();
981 void AudioContainer::scrub(double t)
983 if(imp) imp->scrub(t);
986 double AudioContainer::scrub_time() const
988 if(imp) return imp->scrub_time();
992 bool AudioContainer::isRunning() const
994 if(imp) return imp->isRunning();
998 bool AudioContainer::isPaused() const
1000 if(imp) return imp->isPaused();
1004 //----------- Audio imp information -------------------
1007 bool studio::AudioContainer::AudioImp::load(const std::string &filename,
1008 const std::string &filedirectory)
1010 bool studio::AudioContainer::AudioImp::load(const std::string &/*filename*/,
1011 const std::string &/*filedirectory*/)
1018 //And continue with the sound loading...
1019 string file = filename;
1021 //Trivial reject... (fixes stat call problem... where it just looks at directory and not file...)
1022 if(file.length() == 0) return false;
1024 //we don't need the file directory?
1025 if(!is_absolute_path(file))
1027 file=filedirectory+filename;
1028 synfig::warning("Not absolute hoooray");
1030 synfig::info("Loading Audio file: %s", file.c_str());
1032 //check to see if file exists
1035 if(stat(file.c_str(),&s) == -1 && errno == ENOENT)
1037 synfig::info("There was no audio file...");
1042 //load fmod if we can...
1043 //synfig::warning("I'm compiled with FMOD!");
1047 int ch = FSOUND_FREE;
1048 FSOUND_SAMPLE *sm = FSOUND_Sample_Load(FSOUND_FREE,file.c_str(),FSOUND_LOOP_OFF|FSOUND_MPEGACCURATE,0,0);
1052 synfig::warning("Could not open the audio file as a sample: %s",file.c_str());
1056 //synfig::warning("Opened a file as a sample! :)");
1059 int bufferlen = FSOUND_DSP_GetBufferLength();
1060 synfig::info("Buffer length = %d samples, %.3lf s",bufferlen, bufferlen / (double)FSOUND_GetOutputRate());
1063 //set all the variables since everything has worked out...
1064 //get the length of the stream
1066 length = FSOUND_Sample_GetLength(sm);
1069 FSOUND_Sample_GetDefaults(sm,&sfreq,&volume,0,0);
1071 //double len = length / (double)sfreq;
1072 //synfig::info("Sound info: %.2lf s long, %d Hz, %d Vol",(double)length,sfreq,volume);
1075 //synfig::warning("Got all info, and setting up everything, %.2f sec.", length);
1076 //synfig::warning(" BigSample: composed of %d samples", FSOUND_Sample_GetLength(sm));
1077 synfig::info("Successfully opened %s as a sample and initialized it.",file.c_str());
1079 //set up the playable info
1083 //the length and sfreq params have already been initialized
1088 if(sm) FSOUND_Sample_Free(sm);
1101 void studio::AudioContainer::AudioImp::play(double t)
1103 void studio::AudioContainer::AudioImp::play(double /*t*/)
1109 //stop scrubbing if we are...
1110 if(is_scrubbing()) stop_scrubbing();
1118 unsigned int timeout = (int)floor(-t * 1000 + 0.5);
1119 //synfig::info("Playing audio delayed by %d ms",timeout);
1120 //delay for t seconds...
1121 delaycon = Glib::signal_timeout().connect(
1122 sigc::mem_fun(*this,&studio::AudioContainer::AudioImp::start_playing_now),timeout);
1125 FSOUND_SetFrequency(channel,sfreq);
1126 FSOUND_SetCurrentPosition(channel,0);
1130 unsigned int position = (int)floor(t*sfreq + 0.5);
1132 if(position >= FSOUND_Sample_GetLength(sample))
1134 synfig::warning("Can't play audio when past length...");
1139 FSOUND_SetFrequency(channel,sfreq);
1140 FSOUND_SetCurrentPosition(channel,position);
1141 FSOUND_SetPaused(channel,false);
1143 //synfig::info("Playing audio with position %d samples",position);
1148 void studio::AudioContainer::AudioImp::stop()
1150 delaycon.disconnect();
1153 if(fmodinit.is_loaded() && playing && isRunning())
1155 FSOUND_SetPaused(channel,true);
1162 void studio::AudioContainer::AudioImp::clear()
1165 delaycon.disconnect();
1172 if(FSOUND_IsPlaying(channel))
1174 FSOUND_StopSound(channel);
1176 channel = FSOUND_FREE;
1177 FSOUND_Sample_Free(sample);
1192 void studio::AudioContainer::AudioImp::start_scrubbing(double t)
1194 void studio::AudioContainer::AudioImp::start_scrubbing(double /*t*/)
1197 //synfig::info("Start scrubbing: %lf", t);
1200 set_scrubbing(true);
1203 //make sure the other one is not scrubbing...
1204 if(g_scrubdata.scrub)
1206 *g_scrubdata.scrub = 0; //nullify the pointer...
1209 //Set up the initial state for the delayed audio position
1210 scrinfo.delaystart = 0;
1212 scrinfo.deltatime = 0;
1214 //set it to point to our pointer (dizzy...)
1215 g_scrubdata.scrub = &scrptr;
1217 //setup position info so we can know what to do on boundary conditions...
1218 curscrubpos = (t - get_offset()) * sfreq;
1220 //So we can get an accurate difference...
1223 //reposition the sound if it won't be when scrubbed (if it's already in the range...)
1224 int curi = (int)curscrubpos;
1225 if(curi >= 0 && curi < length)
1228 FSOUND_SetCurrentPosition(channel,curi);
1231 scrinfo.pos = curscrubpos;
1232 scrinfo.delaystart = delay_factor*buffer_length_sec;
1234 //synfig::info("\tStarting at %d samps, with %d p %.3f delay",
1235 // FSOUND_GetCurrentPosition(channel), (int)scrinfo.pos, scrinfo.delaystart);
1241 //synfig::info("\tActivating DSP");
1242 FSOUND_DSP_SetActive(scrubdspunit,true);
1246 void studio::AudioContainer::AudioImp::stop_scrubbing()
1248 //synfig::info("Stop scrubbing");
1252 set_scrubbing(false);
1255 g_scrubdata.scrub = 0;
1258 //synfig::info("\tDeactivating DSP");
1259 FSOUND_DSP_SetActive(scrubdspunit,false);
1260 if(FSOUND_IsPlaying(channel)) FSOUND_SetPaused(channel,true);
1268 void studio::AudioContainer::AudioImp::scrub(double t)
1270 void studio::AudioContainer::AudioImp::scrub(double /*t*/)
1274 //synfig::info("Scrub to %lf",t);
1277 //What should we do?
1279 /* Different special cases
1280 All outside, all inside,
1281 coming in (left or right),
1282 going out (left or right)
1284 double oldpos = curscrubpos;
1285 double newpos = (t - get_offset()) * sfreq;
1287 curscrubpos = newpos;
1289 //Ok the sound is running, now we need to tweak it
1292 //Outside so completely stopped...
1293 if(newpos < 0 || oldpos >= length)
1295 //synfig::info("\tOut +");
1296 if(FSOUND_IsPlaying(channel))
1298 FSOUND_SetPaused(channel,true);
1301 //Zero out the data!
1303 scrinfo.delaystart = 0;
1304 scrinfo.deltatime = 0;
1310 //going in? - start the sound at the beginning...
1311 /*else if(oldpos < 0)
1313 //Set up the sound to be playing paused at the start...
1315 FSOUND_SetCurrentPosition(channel,0);
1317 synfig::info("\tIn + %d", FSOUND_GetCurrentPosition(channel));
1321 scrinfo.delaystart = delay_factor*buffer_length_sec;
1322 scrinfo.deltatime = 0;
1325 //don't need to deal with leaving... automatically dealt with...
1327 else //We're all inside...
1329 //Set new position and decide what to do with time...
1331 scrinfo.pos = newpos;
1333 //should we restart the delay cycle... (is it done?)
1334 if(!isRunning() || (scrinfo.delaystart <= 0 && scrinfo.deltatime <= 0 && isPaused()))
1336 //synfig::info("Starting + at %d",(int)newpos);
1337 scrinfo.deltatime = 0;
1338 scrinfo.delaystart = delay_factor*buffer_length_sec;
1341 //Set up the sound paused at the current position
1343 int setpos = min(max((int)newpos,0),length);
1344 FSOUND_SetCurrentPosition(channel,setpos);
1349 //No! just increment the time delta...
1350 scrinfo.deltatime += timer.pop_time();
1352 //Nope... continue and just increment the deltatime and reset position...
1355 //set channel and unpause
1356 FSOUND_SetPaused(channel,false);
1357 scrinfo.channel = channel;
1360 }else if(newpos < oldpos)
1362 //completely stopped...
1363 if(newpos >= length || oldpos < 0)
1365 //synfig::info("Out -");
1366 if(FSOUND_IsPlaying(channel))
1368 FSOUND_SetPaused(channel,true);
1371 //Zero out the data!
1373 scrinfo.delaystart = 0;
1374 scrinfo.deltatime = 0;
1378 //going in? - start going backwards at the end...
1379 /*else if(oldpos >= length)
1381 synfig::info("In -");
1382 //Set up the sound to be playing paused at the start...
1384 FSOUND_SetCurrentPosition(channel,length-1);
1387 scrinfo.pos = length-1;
1388 scrinfo.delaystart = delay_factor*buffer_length_sec;
1389 scrinfo.deltatime = 0;
1392 //we don't have to worry about the leaving case...
1394 else //We're all inside...
1396 //Set new position and decide what to do with time...
1398 scrinfo.pos = newpos;
1400 //should we restart the delay cycle... (is it done?)
1401 if(!isRunning() ||(scrinfo.delaystart <= 0 && scrinfo.deltatime <= 0 && isPaused()))
1403 //synfig::info("Starting - at %d",(int)newpos);
1404 scrinfo.deltatime = 0;
1405 scrinfo.delaystart = delay_factor*buffer_length_sec;
1408 //reset timing so next update will be a valid diff...
1410 int setpos = min(max((int)newpos,0),length);
1411 FSOUND_SetCurrentPosition(channel,setpos);
1416 //No! just increment the time delta...
1417 scrinfo.deltatime += timer.pop_time();
1419 //Nope... continue and just increment the deltatime and reset position...
1422 //set channel and unpause
1423 FSOUND_SetPaused(channel,false);
1424 scrinfo.channel = channel;