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"
59 /* === U S I N G =========================================================== */
63 using namespace synfig;
65 /* === M A C R O S ========================================================= */
68 #define AUDIO_OUTPUT FSOUND_OUTPUT_OSS
71 /* === G L O B A L S ======================================================= */
72 const double delay_factor = 3;
74 /* === P R O C E D U R E S ================================================= */
76 /* === M E T H O D S ======================================================= */
78 /* === E N T R Y P O I N T ================================================= */
80 //Help constructing stuff
82 using studio::AudioContainer;
85 bool build_profile(FSOUND_SAMPLE *sample, double &samplerate, std::vector<char> &samples)
87 bool build_profile(FSOUND_SAMPLE */*sample*/, double &/*samplerate*/, std::vector<char> &/*samples*/)
92 float sps = samplerate;
94 //trivial rejection...
95 if(!sample || sps < 1)
97 synfig::warning("build_profile: Sample rate was too low or sample was invalid");
101 //lock for all samples and process them into a subset
102 unsigned int mode = FSOUND_Sample_GetMode(sample);
104 //make sure that it's 8 bit... I hope this works...
106 //sample rate of the actual song...
107 int allsamplerate = 0;
108 FSOUND_Sample_GetDefaults(sample,&allsamplerate,0,0,0);
110 //get the size of the sample defaults from the mode
112 int channelsize = 1; //number of bytes
114 if(mode & FSOUND_16BITS) channelsize = 2; //this shouldn't happen
115 if(mode & FSOUND_STEREO) channels = 2;
117 //Get the sample information
118 int samplesize = channels*channelsize; //the only two things that increase samplesize
119 int numsamples = FSOUND_Sample_GetLength(sample); //number of samples in the sound
120 int sizeall = samplesize*numsamples; //should be the size of the entire song...
124 synfig::warning("ProfileAudio: Sample buffer cannot be size smaller than 1 (%X)",FSOUND_GetError());
128 //be sure that the new sample rate is less than or equal to the original
129 if(sps > allsamplerate) sps = allsamplerate;
131 float stride = allsamplerate/(float)sps;
133 //down sampling to 8 bit min/max values
134 synfig::warning("About to downsample from %d Hz to %.1f Hz, sample stride: %f", allsamplerate, sps, stride);
136 char *sampledata=0,*useless = 0;
137 unsigned int len1,len2;
138 // vector<char> samples;
140 if(!FSOUND_Sample_Lock(sample,0,sizeall,(void**)&sampledata,(void**)&useless,&len1,&len2))
142 synfig::warning("ProfileAudio: Unable to lock the sound buffer... (%X)",FSOUND_GetError());
145 synfig::warning("Locked: %X: %d bytes, %X: %d bytes",sampledata,len1,useless,len2);
150 char *iter = sampledata;
151 char *end = iter + sizeall;
154 float numinc = sps/(float)allsamplerate;
156 /* Loop per sample DDA alg.
161 //HACK - to prevent if statement inside inner loop
162 //synfig::warning("wo baby wo baby, inc: %d, stride: %f, size: %d", inc, stride, sizeall);
165 int maxs = 0, mins = 0;
167 for(;curaccum < 1; curaccum += numinc)
169 for(i = 0; iter < end && i < channels; ++i, iter += channelsize)
171 maxs = std::max(maxs,(int)*iter);
172 mins = std::min(mins,(int)*iter);
175 //insert onto new list
176 samples.push_back(maxs);
177 samples.push_back(mins);
179 //and flush all the used samples for curaccum
182 }else if(channelsize == 2)
185 char *iter = sampledata;
186 char *end = iter + sizeall;
189 float numinc = sps/(float)allsamplerate;
191 /* Loop per sample DDA alg.
196 //HACK - to prevent if statement inside inner loop
197 //synfig::warning("wo baby wo baby, inc: %d, stride: %f, size: %d", inc, stride, sizeall);
200 int maxs = 0, mins = 0;
202 for(;curaccum < 1; curaccum += numinc)
204 for(i = 0; iter < end && i < channels; ++i, iter += channelsize)
206 maxs = std::max(maxs,(int)*(short*)iter);
207 mins = std::min(mins,(int)*(short*)iter);
210 //insert onto new list
211 samples.push_back(maxs / 256);
212 samples.push_back(mins / 256);
214 //and flush all the used samples for curaccum
220 synfig::warning("Stats: %f seconds with %d bytes now %d bytes", (samples.size()/2)/sps, sizeall, samples.size());
221 synfig::warning(" %f seconds before", numsamples/(float)allsamplerate);
223 //we're done yay!, unlock
224 FSOUND_Sample_Unlock(sample,sampledata,useless,len1,len2);
225 synfig::info("Unlocked");
227 //FSOUND_PlaySound(FSOUND_FREE,sound); //test
230 samplerate = sps*2; //it must be x2 because we are sampling max and min
242 //FMOD Systemwide Specific data mostly here...
247 static double buffer_length_sec = 0;
249 //------- Scrubbing --------------
250 /* Scrubbing works as follows:
252 The sound is played using PlaySoundEx
253 we specify a user created DSP for scrubbing
254 set it initially to inactive
256 When the program initiates it
257 we set the initial data in the shared structure and activate the dsp unit
258 then for each cursor update we get we set the value in the shared structure
262 If IsPlaying just governs the channel play/stop value or if it also concerns the pause state
266 //so we can know where to create all this stuff
269 /* Linearly fit the frequency to hit the desired zero point...
271 /*struct scrubelement
275 //the amount of time left til the cursor hits this one
276 // it's incremental so that the cursor must pass previous
277 // ones before decrementing this value
281 //the time it should take to get to the next position...
283 //to prevent from writing to the same location at once... (pos, deltatime, delaystart)
286 //the queue system would provide a more accurate representation...
288 volatile double deltatime;
290 volatile double delaystart; //the amount of time we need to go before we start interpolating...
292 volatile int channel;
294 /*std::list<scrubelement> queue;
296 volatile int channel;
298 //current position is FSOUND_GetCurrentPosition and current time is always 0...
300 void add(const scrubelement &elem)
304 queue.push_back(elem);
309 //Function to safely get rid of all the old samples (dt < 0)
314 while(queue.size() && queue.front().dt < 0)
332 //All parameters and state should be set by the time we get here...
333 void scrub_dsp_process()
335 const double epsilon = 1e-5;
337 //Trivial reject... we go nowhere if we aren't playing (hit boundary...)
338 if(!FSOUND_IsPlaying(channel)) return;
340 //Get rid of all the old samples
343 //Trivial reject #2 - We also go nowhere with no future samples (pause)
344 /*if(queue.size() <= 0)
346 FSOUND_SetPaused(channel,true);
350 double dt = buffer_length_sec;
352 //Lock ourselves so we don't die
355 //printf("DSP data: delay = %.3f s, pos = %d, dt = %.3f\n", delaystart, (int)pos, deltatime);
364 dt = -delaystart; //add time back...
369 //Trivial reject for if we're past current sample...
370 if(delaystart > 0 || deltatime <= 0)
372 FSOUND_SetPaused(channel,true);
377 //Calculate stretched frequency based on delayed future sample...
379 //NOTE: BY NOT TRACKING POSITION AS A FLOAT AND JUST USING THE SOUNDS VALUE
380 // WE ARE LOSING A TINY AMOUNT OF PRECISION ACCURACY EVERY UPDATE
381 // (THIS SHOULDN'T BE A PROBLEM)
382 const double p0 = FSOUND_GetCurrentPosition(channel);
385 if(!FSOUND_GetPaused(channel))
387 curdp = FSOUND_GetFrequency(channel) * deltatime;
390 //need to rescale derivative...
392 //Extrapolate from difference in position and deltatime vs dt...
393 const double pa = p0 + curdp/2;
395 const double p1 = pos;
397 //const double pb = p0/3 + p1*2/3;
399 //will extrapolate if needed... (could be funky on a curve)
401 if(deltatime > epsilon)
406 //Decrement deltatime (we may have gone past but that's what happens when we don't get input...)
409 //we don't need to look at the current variables anymore...
412 const double invt = 1-t;
413 //double deltapos = (p1-p0)*t; //linear version
414 double deltapos = invt*invt*p0 + 2*t*invt*pa + t*t*p1 - p0; //quadratic smoothing version
416 //Attempted cubic smoothing
417 //const double invt2 = invt*invt;
418 //const double t2 = t*t;
419 //double deltapos = invt2*invt*p0 + 3*t*invt2*pa + 3*t2*invt*pb + t2*t*p1;
420 //double deltapos = p0 + t*(3*(pa-p0) + t*(3*(p0+2*pa+pb) + t*((p1-3*pb+3*ba-p0)))); //unwound cubic
422 //printf("\ttime = %.2f; p(%d,%d,%d) dp:%d - delta = %d\n",t,(int)p0,(int)p1,(int)p2,(int)curdp,(int)deltapos);
424 //Based on the delta info calculate the stretched frequency
425 const int dest_samplesize = FSOUND_DSP_GetBufferLength();
427 //rounded to nearest frequency... (hopefully...)
428 int freq = (int)(deltapos * FSOUND_GetOutputRate() / (double)dest_samplesize);
430 //NOTE: WE MIGHT WANT TO DO THIS TO BE MORE ACCURATE BUT YEAH... ISSUES WITH SMALL NUMBERS
431 //double newdp = deltapos / t;
433 //printf("\tfreq = %d Hz\n", freq);
435 // !If I failed... um assume we have to pause it... ?
438 FSOUND_SetPaused(channel,true);
441 //synfig::info("DSP f = %d Hz", freq);
442 FSOUND_SetPaused(channel,false);
443 if(!FSOUND_SetFrequency(channel,freq))
445 //ERROR WILL ROBINSON!!!...
446 printf("Error in Freq... what do I do?\n");
454 /* //for use with multiple
455 //each one is a 'handle' to a pointer that will be effected by something else
456 typedef scrubinfo** value_type;
457 typedef std::set< value_type > scrubslist;
460 //so we can lock access to the list...
463 void AddScrub(scrubinfo **i)
470 void RemoveScrub(scrubinfo **i)
477 scrubinfo * volatile * scrub;
480 //Scrubbing data structures
481 static const int default_scrub_priority = 5; //between clear and sfx/music mix
482 static scrubuserdata g_scrubdata = {0};
483 static FSOUND_DSPUNIT *scrubdspunit = 0;
485 void * scrubdspwrap(void *originalbuffer, void *newbuffer, int length, void *userdata)
487 //std::string dsp = "DSP";
490 scrubuserdata &sd = *(scrubuserdata*)userdata;
492 /* //For use with multiple scrubs...
493 //Lock so no one can write to it while we're reading from it...
496 //make a copy of it...
497 std::vector<scrubinfo**> v(sd.scrubs.begin(),sd.scrubs.end());
499 //other things can do stuff with it again...
500 sd.lock.UnLockRead();
502 //loop through the list and process all the active scrub units
503 std::vector<scrubinfo**>::iterator i = v.begin(),
507 //check to make sure this object is active...
510 (**i)->scrub_dsp_process();
515 if(sd.scrub && *sd.scrub)
517 //dsp += " processing...";
518 scrubinfo * info = (*sd.scrub);
519 info->scrub_dsp_process();
528 //------- Class for loading fmod on demand -------
530 class FMODInitializer
536 FMODInitializer():loaded(false),refcount(0) {}
547 synfig::info("Initializing FMOD on demand...");
550 FSOUND_SetOutput(AUDIO_OUTPUT);
552 /*int numdrivers = FSOUND_GetNumDrivers();
553 synfig::info("Num FMOD drivers = %d",numdrivers);
554 synfig::info("Current Driver is #%d", FSOUND_GetDriver());
556 for(int i = 0; i < numdrivers; ++i)
558 unsigned int caps = 0;
559 FSOUND_GetDriverCaps(i,&caps);
561 synfig::info(" Caps for driver %d (%s) = %x",i,FSOUND_GetDriverName(i),caps);
564 FSOUND_SetDriver(0);*/
566 //Modify buffer size...
567 //FSOUND_SetBufferSize(100);
569 if(!FSOUND_Init(44100, 32, 0))
571 synfig::warning("Unable to load FMOD");
576 //Create the DSP for processing scrubbing...
577 scrubdspunit = FSOUND_DSP_Create(&scrubdspwrap,default_scrub_priority,&g_scrubdata);
579 //Load the number of sec per buffer into the global variable...
580 buffer_length_sec = FSOUND_DSP_GetBufferLength() / (double)FSOUND_GetOutputRate();
586 //add to the refcount
588 //synfig::info("Audio: increment fmod refcount %d", refcount);
595 synfig::warning("FMOD refcount is already 0...");
599 //synfig::info("Audio: decrement fmod refcount %d", refcount);
601 //NOTE: UNCOMMENT THIS IF YOU WANT FMOD TO UNLOAD ITSELF WHEN IT ISN'T NEEDED ANYMORE...
606 bool is_loaded() const { return loaded; }
616 if(loaded && refcount <= 0)
619 synfig::info("Unloading FMOD");
620 if(scrubdspunit) FSOUND_DSP_Free(scrubdspunit);
628 //The global counter for FMOD....
629 FMODInitializer fmodinit;
633 //----- AudioProfile Implementation -----------
634 void studio::AudioProfile::clear()
640 handle<AudioContainer> studio::AudioProfile::get_parent() const
645 void studio::AudioProfile::set_parent(etl::handle<AudioContainer> i)
650 double studio::AudioProfile::get_offset() const
653 return parent->get_offset();
657 //---------- AudioContainer definitions ---------------------
659 struct studio::AudioContainer::AudioImp
661 //Sample load time information
662 FSOUND_SAMPLE * sample;
668 double offset; //time offset for playing...
670 //We don't need it now that we've adopted the play(t) time schedule...
671 //current time... and playing info....
675 //Make sure to sever our delayed start if we are stopped prematurely
676 sigc::connection delaycon;
681 etl::clock timer; //for getting the time diff between scrub input points
683 //Scrubbing information...
684 //the current position of the sound will be sufficient for normal stuff...
691 bool is_scrubbing() const {return scrptr != 0;}
693 void set_scrubbing(bool s)
695 void set_scrubbing(bool /*s*/)
706 //helper to make sure we are actually playing (and to get a new channel...)
710 if(!FSOUND_IsPlaying(channel))
714 //play sound paused etc.
715 channel = FSOUND_PlaySoundEx(FSOUND_FREE,sample,0,true);
716 if(channel < 0 || FSOUND_GetError() != FMOD_ERR_NONE)
718 synfig::warning("Could not play the sample...");
724 FSOUND_SetPaused(channel,true);
725 FSOUND_SetFrequency(channel,sfreq);
746 //reuse the channel...
748 channel = FSOUND_FREE;
757 public: //helper/accessor funcs
758 bool start_playing_now() //callback for timer...
763 //Make sure the sound is playing and if it is un pause it...
765 FSOUND_SetPaused(channel,false);
769 return false; //so the timer doesn't repeat itself
775 return FSOUND_IsPlaying(channel);
784 return FSOUND_GetPaused(channel);
791 public: //forward interface
793 //Accessors for the offset - in seconds
794 const double &get_offset() const {return offset;}
795 void set_offset(const double &d)
800 //Will override the parameter timevalue if the sound is running, and not if it's not...
802 bool get_current_time(double &out)
804 bool get_current_time(double &/*out*/)
810 unsigned int pos = FSOUND_GetCurrentPosition(channel);
812 //adjust back by 1 frame... HACK....
813 //pos -= FSOUND_DSP_GetBufferLength();
816 out = pos/(double)sfreq + offset;
824 //Big implementation functions...
825 bool load(const std::string &filename, const std::string &filedirectory);
832 //scrubbing functions
833 void start_scrubbing(double t);
834 void scrub(double t);
835 void stop_scrubbing();
843 //--------------- Audio Container definitions --------------------------
844 studio::AudioContainer::AudioContainer()
849 studio::AudioContainer::~AudioContainer()
851 if(imp) delete (imp);
854 bool studio::AudioContainer::load(const string &filename,const string &filedirectory)
861 profilevalid = false;
862 return imp->load(filename,filedirectory);
866 handle<studio::AudioProfile> studio::AudioContainer::get_profile(float samplerate)
868 handle<studio::AudioProfile> studio::AudioContainer::get_profile(float /*samplerate*/)
873 //if we already have done our work, then we're good
874 if(profilevalid && prof)
876 //synfig::info("Using already built profile");
880 //synfig::info("Before profile");
881 //make a new profile at current sample rate
883 //NOTE: We might want to reuse the structure already there...
884 prof = new AudioProfile;
885 prof->set_parent(this); //Our parent is THIS!!!
889 synfig::warning("Couldn't allocate audioprofile...");
890 return handle<studio::AudioProfile>();
893 //setting the info for the sample rate
894 //synfig::info("Setting info...");
896 synfig::info("Building Profile...");
897 prof->samplerate = samplerate;
898 if(build_profile(imp->sample,prof->samplerate,prof->samples))
900 synfig::info(" Success!");
905 return handle<studio::AudioProfile>();
910 return handle<studio::AudioProfile>();
915 void studio::AudioContainer::clear()
923 profilevalid = false;
926 void studio::AudioContainer::play(double t)
928 if(imp) imp->play(t);
931 void studio::AudioContainer::stop()
936 bool studio::AudioContainer::get_current_time(double &out)
938 if(imp) return imp->get_current_time(out);
942 void AudioContainer::set_offset(const double &s)
944 if(imp) imp->set_offset(s);
947 double AudioContainer::get_offset() const
949 static double zero = 0;
951 return imp->get_offset();
955 bool AudioContainer::is_playing() const
962 bool AudioContainer::is_scrubbing() const
965 return imp->is_scrubbing();
969 void AudioContainer::start_scrubbing(double t)
971 if(imp) imp->start_scrubbing(t);
974 void AudioContainer::stop_scrubbing()
976 if(imp) imp->stop_scrubbing();
979 void AudioContainer::scrub(double t)
981 if(imp) imp->scrub(t);
984 double AudioContainer::scrub_time() const
986 if(imp) return imp->scrub_time();
990 bool AudioContainer::isRunning() const
992 if(imp) return imp->isRunning();
996 bool AudioContainer::isPaused() const
998 if(imp) return imp->isPaused();
1002 //----------- Audio imp information -------------------
1005 bool studio::AudioContainer::AudioImp::load(const std::string &filename,
1006 const std::string &filedirectory)
1008 bool studio::AudioContainer::AudioImp::load(const std::string &/*filename*/,
1009 const std::string &/*filedirectory*/)
1016 //And continue with the sound loading...
1017 string file = filename;
1019 //Trivial reject... (fixes stat call problem... where it just looks at directory and not file...)
1020 if(file.length() == 0) return false;
1022 //we don't need the file directory?
1023 if(!is_absolute_path(file))
1025 file=filedirectory+filename;
1026 synfig::warning("Not absolute hoooray");
1028 synfig::info("Loading Audio file: %s", file.c_str());
1030 //check to see if file exists
1033 if(stat(file.c_str(),&s) == -1 && errno == ENOENT)
1035 synfig::info("There was no audio file...");
1040 //load fmod if we can...
1041 //synfig::warning("I'm compiled with FMOD!");
1045 int ch = FSOUND_FREE;
1046 FSOUND_SAMPLE *sm = FSOUND_Sample_Load(FSOUND_FREE,file.c_str(),FSOUND_LOOP_OFF|FSOUND_MPEGACCURATE,0,0);
1050 synfig::warning("Could not open the audio file as a sample: %s",file.c_str());
1054 //synfig::warning("Opened a file as a sample! :)");
1057 int bufferlen = FSOUND_DSP_GetBufferLength();
1058 synfig::info("Buffer length = %d samples, %.3lf s",bufferlen, bufferlen / (double)FSOUND_GetOutputRate());
1061 //set all the variables since everything has worked out...
1062 //get the length of the stream
1064 length = FSOUND_Sample_GetLength(sm);
1067 FSOUND_Sample_GetDefaults(sm,&sfreq,&volume,0,0);
1069 //double len = length / (double)sfreq;
1070 //synfig::info("Sound info: %.2lf s long, %d Hz, %d Vol",(double)length,sfreq,volume);
1073 //synfig::warning("Got all info, and setting up everything, %.2f sec.", length);
1074 //synfig::warning(" BigSample: composed of %d samples", FSOUND_Sample_GetLength(sm));
1075 synfig::info("Successfully opened %s as a sample and initialized it.",file.c_str());
1077 //set up the playable info
1081 //the length and sfreq params have already been initialized
1086 if(sm) FSOUND_Sample_Free(sm);
1099 void studio::AudioContainer::AudioImp::play(double t)
1101 void studio::AudioContainer::AudioImp::play(double /*t*/)
1107 //stop scrubbing if we are...
1108 if(is_scrubbing()) stop_scrubbing();
1116 unsigned int timeout = (int)floor(-t * 1000 + 0.5);
1117 //synfig::info("Playing audio delayed by %d ms",timeout);
1118 //delay for t seconds...
1119 delaycon = Glib::signal_timeout().connect(
1120 sigc::mem_fun(*this,&studio::AudioContainer::AudioImp::start_playing_now),timeout);
1123 FSOUND_SetFrequency(channel,sfreq);
1124 FSOUND_SetCurrentPosition(channel,0);
1128 unsigned int position = (int)floor(t*sfreq + 0.5);
1130 if(position >= FSOUND_Sample_GetLength(sample))
1132 synfig::warning("Can't play audio when past length...");
1137 FSOUND_SetFrequency(channel,sfreq);
1138 FSOUND_SetCurrentPosition(channel,position);
1139 FSOUND_SetPaused(channel,false);
1141 //synfig::info("Playing audio with position %d samples",position);
1146 void studio::AudioContainer::AudioImp::stop()
1148 delaycon.disconnect();
1151 if(fmodinit.is_loaded() && playing && isRunning())
1153 FSOUND_SetPaused(channel,true);
1160 void studio::AudioContainer::AudioImp::clear()
1163 delaycon.disconnect();
1170 if(FSOUND_IsPlaying(channel))
1172 FSOUND_StopSound(channel);
1174 channel = FSOUND_FREE;
1175 FSOUND_Sample_Free(sample);
1190 void AudioContainer::AudioImp::start_scrubbing(double t)
1192 void AudioContainer::AudioImp::start_scrubbing(double /*t*/)
1195 //synfig::info("Start scrubbing: %lf", t);
1198 set_scrubbing(true);
1201 //make sure the other one is not scrubbing...
1202 if(g_scrubdata.scrub)
1204 *g_scrubdata.scrub = 0; //nullify the pointer...
1207 //Set up the initial state for the delayed audio position
1208 scrinfo.delaystart = 0;
1210 scrinfo.deltatime = 0;
1212 //set it to point to our pointer (dizzy...)
1213 g_scrubdata.scrub = &scrptr;
1215 //setup position info so we can know what to do on boundary conditions...
1216 curscrubpos = (t - get_offset()) * sfreq;
1218 //So we can get an accurate difference...
1221 //reposition the sound if it won't be when scrubbed (if it's already in the range...)
1222 int curi = (int)curscrubpos;
1223 if(curi >= 0 && curi < length)
1226 FSOUND_SetCurrentPosition(channel,curi);
1229 scrinfo.pos = curscrubpos;
1230 scrinfo.delaystart = delay_factor*buffer_length_sec;
1232 //synfig::info("\tStarting at %d samps, with %d p %.3f delay",
1233 // FSOUND_GetCurrentPosition(channel), (int)scrinfo.pos, scrinfo.delaystart);
1239 //synfig::info("\tActivating DSP");
1240 FSOUND_DSP_SetActive(scrubdspunit,true);
1244 void AudioContainer::AudioImp::stop_scrubbing()
1246 //synfig::info("Stop scrubbing");
1250 set_scrubbing(false);
1253 g_scrubdata.scrub = 0;
1256 //synfig::info("\tDeactivating DSP");
1257 FSOUND_DSP_SetActive(scrubdspunit,false);
1258 if(FSOUND_IsPlaying(channel)) FSOUND_SetPaused(channel,true);
1266 void AudioContainer::AudioImp::scrub(double t)
1268 void AudioContainer::AudioImp::scrub(double /*t*/)
1272 //synfig::info("Scrub to %lf",t);
1275 //What should we do?
1277 /* Different special cases
1278 All outside, all inside,
1279 coming in (left or right),
1280 going out (left or right)
1282 double oldpos = curscrubpos;
1283 double newpos = (t - get_offset()) * sfreq;
1285 curscrubpos = newpos;
1287 //Ok the sound is running, now we need to tweek it
1290 //Outside so completely stopped...
1291 if(newpos < 0 || oldpos >= length)
1293 //synfig::info("\tOut +");
1294 if(FSOUND_IsPlaying(channel))
1296 FSOUND_SetPaused(channel,true);
1299 //Zero out the data!
1301 scrinfo.delaystart = 0;
1302 scrinfo.deltatime = 0;
1308 //going in? - start the sound at the beginning...
1309 /*else if(oldpos < 0)
1311 //Set up the sound to be playing paused at the start...
1313 FSOUND_SetCurrentPosition(channel,0);
1315 synfig::info("\tIn + %d", FSOUND_GetCurrentPosition(channel));
1319 scrinfo.delaystart = delay_factor*buffer_length_sec;
1320 scrinfo.deltatime = 0;
1323 //don't need to deal with leaving... automatically dealt with...
1325 else //We're all inside...
1327 //Set new position and decide what to do with time...
1329 scrinfo.pos = newpos;
1331 //should we restart the delay cycle... (is it done?)
1332 if(!isRunning() || (scrinfo.delaystart <= 0 && scrinfo.deltatime <= 0 && isPaused()))
1334 //synfig::info("Starting + at %d",(int)newpos);
1335 scrinfo.deltatime = 0;
1336 scrinfo.delaystart = delay_factor*buffer_length_sec;
1339 //Set up the sound paused at the current position
1341 int setpos = min(max((int)newpos,0),length);
1342 FSOUND_SetCurrentPosition(channel,setpos);
1347 //No! just increment the time delta...
1348 scrinfo.deltatime += timer.pop_time();
1350 //Nope... continue and just increment the deltatime and reset position...
1353 //set channel and unpause
1354 FSOUND_SetPaused(channel,false);
1355 scrinfo.channel = channel;
1358 }else if(newpos < oldpos)
1360 //completely stopped...
1361 if(newpos >= length || oldpos < 0)
1363 //synfig::info("Out -");
1364 if(FSOUND_IsPlaying(channel))
1366 FSOUND_SetPaused(channel,true);
1369 //Zero out the data!
1371 scrinfo.delaystart = 0;
1372 scrinfo.deltatime = 0;
1376 //going in? - start going backwards at the end...
1377 /*else if(oldpos >= length)
1379 synfig::info("In -");
1380 //Set up the sound to be playing paused at the start...
1382 FSOUND_SetCurrentPosition(channel,length-1);
1385 scrinfo.pos = length-1;
1386 scrinfo.delaystart = delay_factor*buffer_length_sec;
1387 scrinfo.deltatime = 0;
1390 //we don't have to worry about the leaving case...
1392 else //We're all inside...
1394 //Set new position and decide what to do with time...
1396 scrinfo.pos = newpos;
1398 //should we restart the delay cycle... (is it done?)
1399 if(!isRunning() ||(scrinfo.delaystart <= 0 && scrinfo.deltatime <= 0 && isPaused()))
1401 //synfig::info("Starting - at %d",(int)newpos);
1402 scrinfo.deltatime = 0;
1403 scrinfo.delaystart = delay_factor*buffer_length_sec;
1406 //reset timing so next update will be a valid diff...
1408 int setpos = min(max((int)newpos,0),length);
1409 FSOUND_SetCurrentPosition(channel,setpos);
1414 //No! just increment the time delta...
1415 scrinfo.deltatime += timer.pop_time();
1417 //Nope... continue and just increment the deltatime and reset position...
1420 //set channel and unpause
1421 FSOUND_SetPaused(channel,false);
1422 scrinfo.channel = channel;