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;
84 bool build_profile(FSOUND_SAMPLE *sample, double &samplerate, std::vector<char> &samples)
88 float sps = samplerate;
90 //trivial rejection...
91 if(!sample || sps < 1)
93 synfig::warning("build_profile: Sample rate was too low or sample was invalid");
97 //lock for all samples and process them into a subset
98 unsigned int mode = FSOUND_Sample_GetMode(sample);
100 //make sure that it's 8 bit... I hope this works...
102 //sample rate of the actual song...
103 int allsamplerate = 0;
104 FSOUND_Sample_GetDefaults(sample,&allsamplerate,0,0,0);
106 //get the size of the sample defaults from the mode
108 int channelsize = 1; //number of bytes
110 if(mode & FSOUND_16BITS) channelsize = 2; //this shouldn't happen
111 if(mode & FSOUND_STEREO) channels = 2;
113 //Get the sample information
114 int samplesize = channels*channelsize; //the only two things that increase samplesize
115 int numsamples = FSOUND_Sample_GetLength(sample); //number of samples in the sound
116 int sizeall = samplesize*numsamples; //should be the size of the entire song...
120 synfig::warning("ProfileAudio: Sample buffer cannot be size smaller than 1 (%X)",FSOUND_GetError());
124 //be sure that the new sample rate is less than or equal to the original
125 if(sps > allsamplerate) sps = allsamplerate;
127 float stride = allsamplerate/(float)sps;
129 //down sampling to 8 bit min/max values
130 synfig::warning("About to downsample from %d Hz to %.1f Hz, sample stride: %f", allsamplerate, sps, stride);
132 char *sampledata=0,*useless = 0;
133 unsigned int len1,len2;
134 // vector<char> samples;
136 if(!FSOUND_Sample_Lock(sample,0,sizeall,(void**)&sampledata,(void**)&useless,&len1,&len2))
138 synfig::warning("ProfileAudio: Unable to lock the sound buffer... (%X)",FSOUND_GetError());
141 synfig::warning("Locked: %X: %d bytes, %X: %d bytes",sampledata,len1,useless,len2);
146 char *iter = sampledata;
147 char *end = iter + sizeall;
150 float numinc = sps/(float)allsamplerate;
152 /* Loop per sample DDA alg.
157 //HACK - to prevent if statement inside inner loop
158 //synfig::warning("wo baby wo baby, inc: %d, stride: %f, size: %d", inc, stride, sizeall);
161 int maxs = 0, mins = 0;
163 for(;curaccum < 1; curaccum += numinc)
165 for(i = 0; iter < end && i < channels; ++i, iter += channelsize)
167 maxs = std::max(maxs,(int)*iter);
168 mins = std::min(mins,(int)*iter);
171 //insert onto new list
172 samples.push_back(maxs);
173 samples.push_back(mins);
175 //and flush all the used samples for curaccum
178 }else if(channelsize == 2)
181 char *iter = sampledata;
182 char *end = iter + sizeall;
185 float numinc = sps/(float)allsamplerate;
187 /* Loop per sample DDA alg.
192 //HACK - to prevent if statement inside inner loop
193 //synfig::warning("wo baby wo baby, inc: %d, stride: %f, size: %d", inc, stride, sizeall);
196 int maxs = 0, mins = 0;
198 for(;curaccum < 1; curaccum += numinc)
200 for(i = 0; iter < end && i < channels; ++i, iter += channelsize)
202 maxs = std::max(maxs,(int)*(short*)iter);
203 mins = std::min(mins,(int)*(short*)iter);
206 //insert onto new list
207 samples.push_back(maxs / 256);
208 samples.push_back(mins / 256);
210 //and flush all the used samples for curaccum
216 synfig::warning("Stats: %f seconds with %d bytes now %d bytes", (samples.size()/2)/sps, sizeall, samples.size());
217 synfig::warning(" %f seconds before", numsamples/(float)allsamplerate);
219 //we're done yay!, unlock
220 FSOUND_Sample_Unlock(sample,sampledata,useless,len1,len2);
221 synfig::info("Unlocked");
223 //FSOUND_PlaySound(FSOUND_FREE,sound); //test
226 samplerate = sps*2; //it must be x2 because we are sampling max and min
238 //FMOD Systemwide Specific data mostly here...
243 static double buffer_length_sec = 0;
245 //------- Scrubbing --------------
246 /* Scrubbing works as follows:
248 The sound is played using PlaySoundEx
249 we specify a user created DSP for scrubbing
250 set it initially to inactive
252 When the program initiates it
253 we set the initial data in the shared structure and activate the dsp unit
254 then for each cursor update we get we set the value in the shared structure
258 If IsPlaying just governs the channel play/stop value or if it also concerns the pause state
262 //so we can know where to create all this stuff
265 /* Linearly fit the frequency to hit the desired zero point...
267 /*struct scrubelement
271 //the amount of time left til the cursor hits this one
272 // it's incremental so that the cursor must pass previous
273 // ones before decrementing this value
277 //the time it should take to get to the next position...
279 //to prevent from writing to the same location at once... (pos, deltatime, delaystart)
282 //the queue system would provide a more accurate representation...
284 volatile double deltatime;
286 volatile double delaystart; //the amount of time we need to go before we start interpolating...
288 volatile int channel;
290 /*std::list<scrubelement> queue;
292 volatile int channel;
294 //current position is FSOUND_GetCurrentPosition and current time is always 0...
296 void add(const scrubelement &elem)
300 queue.push_back(elem);
305 //Function to safely get rid of all the old samples (dt < 0)
310 while(queue.size() && queue.front().dt < 0)
328 //All parameters and state should be set by the time we get here...
329 void scrub_dsp_process()
331 const double epsilon = 1e-5;
333 //Trivial reject... we go nowhere if we aren't playing (hit boundary...)
334 if(!FSOUND_IsPlaying(channel)) return;
336 //Get rid of all the old samples
339 //Trivial reject #2 - We also go nowhere with no future samples (pause)
340 /*if(queue.size() <= 0)
342 FSOUND_SetPaused(channel,true);
346 double dt = buffer_length_sec;
348 //Lock ourselves so we don't die
351 //printf("DSP data: delay = %.3f s, pos = %d, dt = %.3f\n", delaystart, (int)pos, deltatime);
360 dt = -delaystart; //add time back...
365 //Trivial reject for if we're past current sample...
366 if(delaystart > 0 || deltatime <= 0)
368 FSOUND_SetPaused(channel,true);
373 //Calculate stretched frequency based on delayed future sample...
375 //NOTE: BY NOT TRACKING POSITION AS A FLOAT AND JUST USING THE SOUNDS VALUE
376 // WE ARE LOSING A TINY AMOUNT OF PRECISION ACCURACY EVERY UPDATE
377 // (THIS SHOULDN'T BE A PROBLEM)
378 const double p0 = FSOUND_GetCurrentPosition(channel);
381 if(!FSOUND_GetPaused(channel))
383 curdp = FSOUND_GetFrequency(channel) * deltatime;
386 //need to rescale derivative...
388 //Extrapolate from difference in position and deltatime vs dt...
389 const double pa = p0 + curdp/2;
391 const double p1 = pos;
393 //const double pb = p0/3 + p1*2/3;
395 //will extrapolate if needed... (could be funky on a curve)
397 if(deltatime > epsilon)
402 //Decrement deltatime (we may have gone past but that's what happens when we don't get input...)
405 //we don't need to look at the current variables anymore...
408 const double invt = 1-t;
409 //double deltapos = (p1-p0)*t; //linear version
410 double deltapos = invt*invt*p0 + 2*t*invt*pa + t*t*p1 - p0; //quadratic smoothing version
412 //Attempted cubic smoothing
413 //const double invt2 = invt*invt;
414 //const double t2 = t*t;
415 //double deltapos = invt2*invt*p0 + 3*t*invt2*pa + 3*t2*invt*pb + t2*t*p1;
416 //double deltapos = p0 + t*(3*(pa-p0) + t*(3*(p0+2*pa+pb) + t*((p1-3*pb+3*ba-p0)))); //unwound cubic
418 //printf("\ttime = %.2f; p(%d,%d,%d) dp:%d - delta = %d\n",t,(int)p0,(int)p1,(int)p2,(int)curdp,(int)deltapos);
420 //Based on the delta info calculate the stretched frequency
421 const int dest_samplesize = FSOUND_DSP_GetBufferLength();
423 //rounded to nearest frequency... (hopefully...)
424 int freq = (int)(deltapos * FSOUND_GetOutputRate() / (double)dest_samplesize);
426 //NOTE: WE MIGHT WANT TO DO THIS TO BE MORE ACCURATE BUT YEAH... ISSUES WITH SMALL NUMBERS
427 //double newdp = deltapos / t;
429 //printf("\tfreq = %d Hz\n", freq);
431 // !If I failed... um assume we have to pause it... ?
434 FSOUND_SetPaused(channel,true);
437 //synfig::info("DSP f = %d Hz", freq);
438 FSOUND_SetPaused(channel,false);
439 if(!FSOUND_SetFrequency(channel,freq))
441 //ERROR WILL ROBINSON!!!...
442 printf("Error in Freq... what do I do?\n");
450 /* //for use with multiple
451 //each one is a 'handle' to a pointer that will be effected by something else
452 typedef scrubinfo** value_type;
453 typedef std::set< value_type > scrubslist;
456 //so we can lock access to the list...
459 void AddScrub(scrubinfo **i)
466 void RemoveScrub(scrubinfo **i)
473 scrubinfo * volatile * scrub;
476 //Scrubbing data structures
477 static const int default_scrub_priority = 5; //between clear and sfx/music mix
478 static scrubuserdata g_scrubdata = {0};
479 static FSOUND_DSPUNIT *scrubdspunit = 0;
481 void * scrubdspwrap(void *originalbuffer, void *newbuffer, int length, void *userdata)
483 //std::string dsp = "DSP";
486 scrubuserdata &sd = *(scrubuserdata*)userdata;
488 /* //For use with multiple scrubs...
489 //Lock so no one can write to it while we're reading from it...
492 //make a copy of it...
493 std::vector<scrubinfo**> v(sd.scrubs.begin(),sd.scrubs.end());
495 //other things can do stuff with it again...
496 sd.lock.UnLockRead();
498 //loop through the list and process all the active scrub units
499 std::vector<scrubinfo**>::iterator i = v.begin(),
503 //check to make sure this object is active...
506 (**i)->scrub_dsp_process();
511 if(sd.scrub && *sd.scrub)
513 //dsp += " processing...";
514 scrubinfo * info = (*sd.scrub);
515 info->scrub_dsp_process();
524 //------- Class for loading fmod on demand -------
526 class FMODInitializer
532 FMODInitializer():loaded(false),refcount(0) {}
543 synfig::info("Initializing FMOD on demand...");
546 FSOUND_SetOutput(AUDIO_OUTPUT);
548 /*int numdrivers = FSOUND_GetNumDrivers();
549 synfig::info("Num FMOD drivers = %d",numdrivers);
550 synfig::info("Current Driver is #%d", FSOUND_GetDriver());
552 for(int i = 0; i < numdrivers; ++i)
554 unsigned int caps = 0;
555 FSOUND_GetDriverCaps(i,&caps);
557 synfig::info(" Caps for driver %d (%s) = %x",i,FSOUND_GetDriverName(i),caps);
560 FSOUND_SetDriver(0);*/
562 //Modify buffer size...
563 //FSOUND_SetBufferSize(100);
565 if(!FSOUND_Init(44100, 32, 0))
567 synfig::warning("Unable to load FMOD");
572 //Create the DSP for processing scrubbing...
573 scrubdspunit = FSOUND_DSP_Create(&scrubdspwrap,default_scrub_priority,&g_scrubdata);
575 //Load the number of sec per buffer into the global variable...
576 buffer_length_sec = FSOUND_DSP_GetBufferLength() / (double)FSOUND_GetOutputRate();
582 //add to the refcount
584 //synfig::info("Audio: increment fmod refcount %d", refcount);
591 synfig::warning("FMOD refcount is already 0...");
595 //synfig::info("Audio: decrement fmod refcount %d", refcount);
597 //NOTE: UNCOMMENT THIS IF YOU WANT FMOD TO UNLOAD ITSELF WHEN IT ISN'T NEEDED ANYMORE...
602 bool is_loaded() const { return loaded; }
612 if(loaded && refcount <= 0)
615 synfig::info("Unloading FMOD");
616 if(scrubdspunit) FSOUND_DSP_Free(scrubdspunit);
624 //The global counter for FMOD....
625 FMODInitializer fmodinit;
629 //----- AudioProfile Implementation -----------
630 void studio::AudioProfile::clear()
636 handle<AudioContainer> studio::AudioProfile::get_parent() const
641 void studio::AudioProfile::set_parent(etl::handle<AudioContainer> i)
646 double studio::AudioProfile::get_offset() const
649 return parent->get_offset();
653 //---------- AudioContainer definitions ---------------------
655 struct studio::AudioContainer::AudioImp
657 //Sample load time information
658 FSOUND_SAMPLE * sample;
664 double offset; //time offset for playing...
666 //We don't need it now that we've adopted the play(t) time schedule...
667 //current time... and playing info....
671 //Make sure to sever our delayed start if we are stopped prematurely
672 sigc::connection delaycon;
677 etl::clock timer; //for getting the time diff between scrub input points
679 //Scrubbing information...
680 //the current position of the sound will be sufficient for normal stuff...
687 bool is_scrubbing() const {return scrptr != 0;}
688 void set_scrubbing(bool s)
698 //helper to make sure we are actually playing (and to get a new channel...)
702 if(!FSOUND_IsPlaying(channel))
706 //play sound paused etc.
707 channel = FSOUND_PlaySoundEx(FSOUND_FREE,sample,0,true);
708 if(channel < 0 || FSOUND_GetError() != FMOD_ERR_NONE)
710 synfig::warning("Could not play the sample...");
716 FSOUND_SetPaused(channel,true);
717 FSOUND_SetFrequency(channel,sfreq);
738 //reuse the channel...
740 channel = FSOUND_FREE;
749 public: //helper/accessor funcs
750 bool start_playing_now() //callback for timer...
755 //Make sure the sound is playing and if it is un pause it...
757 FSOUND_SetPaused(channel,false);
761 return false; //so the timer doesn't repeat itself
767 return FSOUND_IsPlaying(channel);
776 return FSOUND_GetPaused(channel);
783 public: //forward interface
785 //Accessors for the offset - in seconds
786 const double &get_offset() const {return offset;}
787 void set_offset(const double &d)
792 //Will override the parameter timevalue if the sound is running, and not if it's not...
793 bool get_current_time(double &out)
798 unsigned int pos = FSOUND_GetCurrentPosition(channel);
800 //adjust back by 1 frame... HACK....
801 //pos -= FSOUND_DSP_GetBufferLength();
804 out = pos/(double)sfreq + offset;
812 //Big implementation functions...
813 bool load(const std::string &filename, const std::string &filedirectory);
820 //scrubbing functions
821 void start_scrubbing(double t);
822 void scrub(double t);
823 void stop_scrubbing();
831 //--------------- Audio Container definitions --------------------------
832 studio::AudioContainer::AudioContainer()
837 studio::AudioContainer::~AudioContainer()
839 if(imp) delete (imp);
842 bool studio::AudioContainer::load(const string &filename,const string &filedirectory)
849 profilevalid = false;
850 return imp->load(filename,filedirectory);
853 handle<studio::AudioProfile> studio::AudioContainer::get_profile(float samplerate)
857 //if we already have done our work, then we're good
858 if(profilevalid && prof)
860 //synfig::info("Using already built profile");
864 //synfig::info("Before profile");
865 //make a new profile at current sample rate
867 //NOTE: We might want to reuse the structure already there...
868 prof = new AudioProfile;
869 prof->set_parent(this); //Our parent is THIS!!!
873 synfig::warning("Couldn't allocate audioprofile...");
874 return handle<studio::AudioProfile>();
877 //setting the info for the sample rate
878 //synfig::info("Setting info...");
880 synfig::info("Building Profile...");
881 prof->samplerate = samplerate;
882 if(build_profile(imp->sample,prof->samplerate,prof->samples))
884 synfig::info(" Success!");
889 return handle<studio::AudioProfile>();
894 return handle<studio::AudioProfile>();
899 void studio::AudioContainer::clear()
907 profilevalid = false;
910 void studio::AudioContainer::play(double t)
912 if(imp) imp->play(t);
915 void studio::AudioContainer::stop()
920 bool studio::AudioContainer::get_current_time(double &out)
922 if(imp) return imp->get_current_time(out);
926 void AudioContainer::set_offset(const double &s)
928 if(imp) imp->set_offset(s);
931 double AudioContainer::get_offset() const
933 static double zero = 0;
935 return imp->get_offset();
939 bool AudioContainer::is_playing() const
946 bool AudioContainer::is_scrubbing() const
949 return imp->is_scrubbing();
953 void AudioContainer::start_scrubbing(double t)
955 if(imp) imp->start_scrubbing(t);
958 void AudioContainer::stop_scrubbing()
960 if(imp) imp->stop_scrubbing();
963 void AudioContainer::scrub(double t)
965 if(imp) imp->scrub(t);
968 double AudioContainer::scrub_time() const
970 if(imp) return imp->scrub_time();
974 bool AudioContainer::isRunning() const
976 if(imp) return imp->isRunning();
980 bool AudioContainer::isPaused() const
982 if(imp) return imp->isPaused();
986 //----------- Audio imp information -------------------
988 bool studio::AudioContainer::AudioImp::load(const std::string &filename,
989 const std::string &filedirectory)
995 //And continue with the sound loading...
996 string file = filename;
998 //Trivial reject... (fixes stat call problem... where it just looks at directory and not file...)
999 if(file.length() == 0) return false;
1001 //we don't need the file directory?
1002 if(!is_absolute_path(file))
1004 file=filedirectory+filename;
1005 synfig::warning("Not absolute hoooray");
1007 synfig::info("Loading Audio file: %s", file.c_str());
1009 //check to see if file exists
1012 if(stat(file.c_str(),&s) == -1 && errno == ENOENT)
1014 synfig::info("There was no audio file...");
1019 //load fmod if we can...
1020 //synfig::warning("I'm compiled with FMOD!");
1024 int ch = FSOUND_FREE;
1025 FSOUND_SAMPLE *sm = FSOUND_Sample_Load(FSOUND_FREE,file.c_str(),FSOUND_LOOP_OFF|FSOUND_MPEGACCURATE,0,0);
1029 synfig::warning("Could not open the audio file as a sample: %s",file.c_str());
1033 //synfig::warning("Opened a file as a sample! :)");
1036 int bufferlen = FSOUND_DSP_GetBufferLength();
1037 synfig::info("Buffer length = %d samples, %.3lf s",bufferlen, bufferlen / (double)FSOUND_GetOutputRate());
1040 //set all the variables since everything has worked out...
1041 //get the length of the stream
1043 length = FSOUND_Sample_GetLength(sm);
1046 FSOUND_Sample_GetDefaults(sm,&sfreq,&volume,0,0);
1048 //double len = length / (double)sfreq;
1049 //synfig::info("Sound info: %.2lf s long, %d Hz, %d Vol",(double)length,sfreq,volume);
1052 //synfig::warning("Got all info, and setting up everything, %.2f sec.", length);
1053 //synfig::warning(" BigSample: composed of %d samples", FSOUND_Sample_GetLength(sm));
1054 synfig::info("Successfully opened %s as a sample and initialized it.",file.c_str());
1056 //set up the playable info
1060 //the length and sfreq params have already been initialized
1065 if(sm) FSOUND_Sample_Free(sm);
1077 void studio::AudioContainer::AudioImp::play(double t)
1082 //stop scrubbing if we are...
1083 if(is_scrubbing()) stop_scrubbing();
1091 unsigned int timeout = (int)floor(-t * 1000 + 0.5);
1092 //synfig::info("Playing audio delayed by %d ms",timeout);
1093 //delay for t seconds...
1094 delaycon = Glib::signal_timeout().connect(
1095 sigc::mem_fun(*this,&studio::AudioContainer::AudioImp::start_playing_now),timeout);
1098 FSOUND_SetFrequency(channel,sfreq);
1099 FSOUND_SetCurrentPosition(channel,0);
1103 unsigned int position = (int)floor(t*sfreq + 0.5);
1105 if(position >= FSOUND_Sample_GetLength(sample))
1107 synfig::warning("Can't play audio when past length...");
1112 FSOUND_SetFrequency(channel,sfreq);
1113 FSOUND_SetCurrentPosition(channel,position);
1114 FSOUND_SetPaused(channel,false);
1116 //synfig::info("Playing audio with position %d samples",position);
1121 void studio::AudioContainer::AudioImp::stop()
1123 delaycon.disconnect();
1126 if(fmodinit.is_loaded() && playing && isRunning())
1128 FSOUND_SetPaused(channel,true);
1135 void studio::AudioContainer::AudioImp::clear()
1138 delaycon.disconnect();
1145 if(FSOUND_IsPlaying(channel))
1147 FSOUND_StopSound(channel);
1149 channel = FSOUND_FREE;
1150 FSOUND_Sample_Free(sample);
1164 void AudioContainer::AudioImp::start_scrubbing(double t)
1166 //synfig::info("Start scrubbing: %lf", t);
1169 set_scrubbing(true);
1172 //make sure the other one is not scrubbing...
1173 if(g_scrubdata.scrub)
1175 *g_scrubdata.scrub = 0; //nullify the pointer...
1178 //Set up the initial state for the delayed audio position
1179 scrinfo.delaystart = 0;
1181 scrinfo.deltatime = 0;
1183 //set it to point to our pointer (dizzy...)
1184 g_scrubdata.scrub = &scrptr;
1186 //setup position info so we can know what to do on boundary conditions...
1187 curscrubpos = (t - get_offset()) * sfreq;
1189 //So we can get an accurate difference...
1192 //reposition the sound if it won't be when scrubbed (if it's already in the range...)
1193 int curi = (int)curscrubpos;
1194 if(curi >= 0 && curi < length)
1197 FSOUND_SetCurrentPosition(channel,curi);
1200 scrinfo.pos = curscrubpos;
1201 scrinfo.delaystart = delay_factor*buffer_length_sec;
1203 //synfig::info("\tStarting at %d samps, with %d p %.3f delay",
1204 // FSOUND_GetCurrentPosition(channel), (int)scrinfo.pos, scrinfo.delaystart);
1210 //synfig::info("\tActivating DSP");
1211 FSOUND_DSP_SetActive(scrubdspunit,true);
1215 void AudioContainer::AudioImp::stop_scrubbing()
1217 //synfig::info("Stop scrubbing");
1221 set_scrubbing(false);
1224 g_scrubdata.scrub = 0;
1227 //synfig::info("\tDeactivating DSP");
1228 FSOUND_DSP_SetActive(scrubdspunit,false);
1229 if(FSOUND_IsPlaying(channel)) FSOUND_SetPaused(channel,true);
1236 void AudioContainer::AudioImp::scrub(double t)
1239 //synfig::info("Scrub to %lf",t);
1242 //What should we do?
1244 /* Different special cases
1245 All outside, all inside,
1246 coming in (left or right),
1247 going out (left or right)
1249 double oldpos = curscrubpos;
1250 double newpos = (t - get_offset()) * sfreq;
1252 curscrubpos = newpos;
1254 //Ok the sound is running, now we need to tweek it
1257 //Outside so completely stopped...
1258 if(newpos < 0 || oldpos >= length)
1260 //synfig::info("\tOut +");
1261 if(FSOUND_IsPlaying(channel))
1263 FSOUND_SetPaused(channel,true);
1266 //Zero out the data!
1268 scrinfo.delaystart = 0;
1269 scrinfo.deltatime = 0;
1275 //going in? - start the sound at the beginning...
1276 /*else if(oldpos < 0)
1278 //Set up the sound to be playing paused at the start...
1280 FSOUND_SetCurrentPosition(channel,0);
1282 synfig::info("\tIn + %d", FSOUND_GetCurrentPosition(channel));
1286 scrinfo.delaystart = delay_factor*buffer_length_sec;
1287 scrinfo.deltatime = 0;
1290 //don't need to deal with leaving... automatically dealt with...
1292 else //We're all inside...
1294 //Set new position and decide what to do with time...
1296 scrinfo.pos = newpos;
1298 //should we restart the delay cycle... (is it done?)
1299 if(!isRunning() || (scrinfo.delaystart <= 0 && scrinfo.deltatime <= 0 && isPaused()))
1301 //synfig::info("Starting + at %d",(int)newpos);
1302 scrinfo.deltatime = 0;
1303 scrinfo.delaystart = delay_factor*buffer_length_sec;
1306 //Set up the sound paused at the current position
1308 int setpos = min(max((int)newpos,0),length);
1309 FSOUND_SetCurrentPosition(channel,setpos);
1314 //No! just increment the time delta...
1315 scrinfo.deltatime += timer.pop_time();
1317 //Nope... continue and just increment the deltatime and reset position...
1320 //set channel and unpause
1321 FSOUND_SetPaused(channel,false);
1322 scrinfo.channel = channel;
1325 }else if(newpos < oldpos)
1327 //completely stopped...
1328 if(newpos >= length || oldpos < 0)
1330 //synfig::info("Out -");
1331 if(FSOUND_IsPlaying(channel))
1333 FSOUND_SetPaused(channel,true);
1336 //Zero out the data!
1338 scrinfo.delaystart = 0;
1339 scrinfo.deltatime = 0;
1343 //going in? - start going backwards at the end...
1344 /*else if(oldpos >= length)
1346 synfig::info("In -");
1347 //Set up the sound to be playing paused at the start...
1349 FSOUND_SetCurrentPosition(channel,length-1);
1352 scrinfo.pos = length-1;
1353 scrinfo.delaystart = delay_factor*buffer_length_sec;
1354 scrinfo.deltatime = 0;
1357 //we don't have to worry about the leaving case...
1359 else //We're all inside...
1361 //Set new position and decide what to do with time...
1363 scrinfo.pos = newpos;
1365 //should we restart the delay cycle... (is it done?)
1366 if(!isRunning() ||(scrinfo.delaystart <= 0 && scrinfo.deltatime <= 0 && isPaused()))
1368 //synfig::info("Starting - at %d",(int)newpos);
1369 scrinfo.deltatime = 0;
1370 scrinfo.delaystart = delay_factor*buffer_length_sec;
1373 //reset timing so next update will be a valid diff...
1375 int setpos = min(max((int)newpos,0),length);
1376 FSOUND_SetCurrentPosition(channel,setpos);
1381 //No! just increment the time delta...
1382 scrinfo.deltatime += timer.pop_time();
1384 //Nope... continue and just increment the deltatime and reset position...
1387 //set channel and unpause
1388 FSOUND_SetPaused(channel,false);
1389 scrinfo.channel = channel;