1 /* 2 * Copyright (C) 2002 - David W. Durham 3 * 4 * This file is part of ReZound, an audio editing application. 5 * 6 * ReZound is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published 8 * by the Free Software Foundation; either version 2 of the License, 9 * or (at your option) any later version. 10 * 11 * ReZound is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 */ 20 21 #ifndef __CSound_H__ 22 #define __CSound_H__ 23 24 #include "../../config/common.h" 25 26 #include <string.h> 27 28 #include <string> 29 #include <map> 30 31 #include "CSound_defs.h" 32 #include <endian_util.h> 33 34 // it would be nice if I didn't have to include all this ??? 35 #include <TPoolFile.h> 36 #include <TPoolAccesser.h> 37 #define REZOUND_POOLFILE_BLOCKSIZE 32768 38 #define REZOUND_POOLFILE_SIGNATURE "ReZoundF" 39 #define REZOUND_WORKING_POOLFILE_SIGNATURE "ReZoundW" 40 41 typedef TStaticPoolAccesser<sample_t,TPoolFile<sample_pos_t,CMultiFile::l_addr_t> > CRezPoolAccesser; 42 43 struct RPeakChunk 44 { 45 public: 46 sample_t min; 47 sample_t max; 48 private: 49 friend class CSound; 50 bool dirty; 51 }; 52 53 class CSound 54 { 55 public: 56 // the p_addr_t needs to agree with CSound::getAudioDataSize()'s implementation too 57 typedef TPoolFile<sample_pos_t,uint64_t> PoolFile_t; 58 59 CSound(); 60 // works like createWorkingPoolFile 61 CSound(const string &_filename,const unsigned _sampleRate,const unsigned _channelCount,const sample_pos_t _size); 62 virtual ~CSound(); 63 64 // creates a poolFile with a temp name based off of originalFilename and populates the given meta-info 65 // - don't want as public except that each derivation of ASoundTranslator would have ot be a friend 66 void createWorkingPoolFile(const string originalFilename,const unsigned _sampleRate,const unsigned _channelCount,const sample_pos_t _size); 67 68 // attempts to open a poolFile with the given name and if it succeeds then it populates the data-members with the format-info 69 bool createFromWorkingPoolFileIfExists(const string originalFilename,bool promptIfFound=true); 70 71 72 73 void closeSound(); 74 75 void changeWorkingFilename(const string newOriginalFilename); 76 77 78 CRezPoolAccesser getAudio(unsigned channel); 79 const CRezPoolAccesser getAudio(unsigned channel) const; 80 81 // tempAudioPoolKey is returned from moveDataTemp or moveDataToTempAndReplaceSpace 82 CRezPoolAccesser getTempAudio(unsigned tempAudioPoolKey,unsigned channel); 83 const CRezPoolAccesser getTempAudio(unsigned tempAudioPoolKey,unsigned channel) const; 84 85 86 /* 87 * - This returns a min and max sample value of the data between [dataPos,nextDataPos) 88 * - This should be used to render the waveform as it gives a more consistance 89 * shape when scaling the data 90 */ 91 RPeakChunk getPeakData(unsigned channel,sample_pos_t dataPos,sample_pos_t nextDataPos,const CRezPoolAccesser &dataAccesser) const; 92 93 /* 94 * - Should be called by any code that modified the data in such a way that peak data needs to be modified 95 * - It's not necessary to call it for data that was touched by the methods in CSound that modify or resize 96 * the data 97 */ 98 void invalidatePeakData(unsigned channel,sample_pos_t start,sample_pos_t stop); 99 void invalidatePeakData(const bool doChannel[MAX_CHANNELS],sample_pos_t start,sample_pos_t stop); 100 void invalidateAllPeakData(); 101 102 103 getLength()104 sample_pos_t getLength() const { return size; } getChannelCount()105 unsigned getChannelCount() const { return channelCount; } getSampleRate()106 unsigned getSampleRate() const { return sampleRate; } 107 void setSampleRate(unsigned newSampleRate); isEmpty()108 bool isEmpty() const { return size==0 || channelCount==0; } 109 110 /* 111 * It is very important to lock the sound (writer's lock) before calling these methods. 112 * And except will occur if a resizeLock has not been obtained before calling these methods 113 * (??? I could make a static bool variable that says it's okay not to have a lock if I know the app isn't multi-threaded) 114 */ 115 // ??? all of the space modifier methods should make sure that a resize lock has been obtained... if it hasn't do INTERNAL_ERROR 116 117 118 119 // Structure Manipulation Members (Most require a resize lock to have been obtained) 120 121 void addChannel(bool doZeroData); // adds a new channel at the end 122 void addChannels(unsigned where,unsigned count,bool doZeroData); 123 124 void removeChannel(); // removes the last channel 125 void removeChannels(unsigned where,unsigned count); 126 127 // moves each channel specified by whichChannels to a temp pool and returns a handle (tempAudioPoolKey) to those temp pools to be restored 128 int moveChannelsToTemp(const bool whichChannels[MAX_CHANNELS]); 129 130 // moves channels back into position from a moveChannelsToTempPool() 131 // tempAudioPoolKey was returned by moveChannelsToTempPool() 132 // whichChannels MUST be the same as when moveChannelsToTempPool() was called 133 // the audio length MUST be the same as when moveChannelsToTempPool() was called 134 // the channel layout MUST be the same as after the moveChannelsToTempPool() was finished 135 void moveChannelsFromTemp(int tempAudioPoolKey,const bool whichChannels[MAX_CHANNELS]); 136 137 138 139 /* 140 * - Adds 'length' samples of space at position 'where' to all channels 141 * - If 'doZeroData' is true, then the newly created space will be initialized to zero 142 */ 143 void addSpace(sample_pos_t where,sample_pos_t length,bool doZeroData=false); 144 145 /* 146 * - Adds 'length' samples of space at position 'where' to channels where whichChannels[i] is true 147 * - Any channel that was not affected will have 'length' samples of silence appended to it 148 * - If 'doZeroData' is true, then the newly created space will be initialized to zero 149 * - If 'maxLength' is given, then any channels longer than that will be truncated, and silence appended to unaffected channels will not make the channel exceed this maximum length 150 */ 151 void addSpace(const bool whichChannels[MAX_CHANNELS],sample_pos_t where,sample_pos_t length,bool doZeroData=false,sample_pos_t maxLength=NIL_SAMPLE_POS); 152 153 154 /* 155 * - Removed 'length' samples of space from position 'where' to all channels 156 */ 157 void removeSpace(sample_pos_t where,sample_pos_t length); 158 159 /* 160 * - Removed 'length' samples of space from position 'where' to channels where whichChannels[i] is true 161 * - If all channels are not affected, then channels that were affected will have 'length' samples of silence appended to it 162 * - If 'maxLength' is given, then any channels longer than that will be truncated, and silence appended to unaffected channels will not make the channel exceed this maximum length 163 */ 164 void removeSpace(const bool whichChannels[MAX_CHANNELS],sample_pos_t where,sample_pos_t length,sample_pos_t maxLength=NIL_SAMPLE_POS); 165 166 167 /* 168 * - Moves 'length' samples of data from position 'where' for each channel where whichChannels[i] is true to a newly created temporary pool in the pool file for this sound object 169 * - If all channels were not affected, then each channel that was affected will have 'length' samples of silence appended to it 170 * - The value returned is a handle to the temporary pools created by the move, it is the tempAudioPoolKey parameter passed to getTempData, moveDataFromTemp, removeSpaceAndMoveDataFromTemp, etc 171 * - If fudgeFactor is greater than zero, then that many samples will also be appended to the temp pool by copying them not moving them 172 * - The fudgeFactor can specify lengths that extend beyond the end of the sound, silence will just result int he temp pool 173 * - This is useful for functions which may need to read ahead in a temp buffer, but don't wish to incur the cost of an if statement to check bounds for just a few needed samples 174 * - If 'maxLength' is given, then any channels longer than that will be truncated, and silence appended to unaffected channels will not make the channel exceed this maximum length 175 */ 176 unsigned moveDataToTemp(const bool whichChannels[MAX_CHANNELS],sample_pos_t where,sample_pos_t length,sample_pos_t fudgeFactor=0,sample_pos_t maxLength=NIL_SAMPLE_POS); 177 178 /* 179 * - Copies 'length' samples of data from position 'where' for each channel where whichChannels[i] is true to a newly created temporary pool in the pool file for this sound object 180 * - The value returned is a handle to the temporary pools created by the copy, it is the tempAudioPoolKey parameter passed to getTempData, moveDataFromTemp, removeSpaceAndMoveDataFromTemp, etc 181 */ 182 unsigned copyDataToTemp(const bool whichChannels[MAX_CHANNELS],sample_pos_t where,sample_pos_t length); 183 184 /* 185 * - Moves 'length' samples of data from position 'where' but replaces the space with 'replaceLength' samples, for each channel where whichChannels[i] is true to a newly created temporary pool in the pool file for this sound object 186 * - If all channels were not affected then: 187 * - if more space is moved than replaced, then each channel affected will have 'length-replaceLength' samples of silence appended to it 188 * - if more space is replaced than moved, then each channel NOT affected will have 'replaceLength-length' samples of silencs appended to it 189 * - The value returned is a handle to the temporary pools created by the move, it is the tempAudioPoolKey parameter passed to getTempData, moveDataFromTemp, removeSpaceAndMoveDataFromTemp, etc 190 * - If fudgeFactor is greater than zero, then that many samples will also be appended to the temp pool by copying them not moving them 191 * - The fudgeFactor can specify lengths that extend beyond the end of the sound, silence will just result in the temp pool 192 * - This is useful for functions which may need to read ahead in a temp buffer, but don't wish to incur the cost of an if statement to check bounds for just a few needed samples 193 * - If 'maxLength' is given, then any channels longer than that will be truncated, and silence appended to unaffected channels will not make the channel exceed this maximum length 194 */ 195 unsigned moveDataToTempAndReplaceSpace(const bool whichChannels[MAX_CHANNELS],sample_pos_t where,sample_pos_t length,sample_pos_t replaceLength,sample_pos_t fudgeFactor=0,sample_pos_t maxLength=NIL_SAMPLE_POS); 196 197 198 /* 199 * - Moves 'moveLength' samples of data from the beginning of a temporary pool specified by 'tempAudioPoolKey' to position 'moveWhere' in the normal audio data pools for each channel where whichChannels[i] is true 200 * - If all channels where not affected then, each channel that was not affected will have 'moveLength' samples of silenced appended to it 201 * - If 'removeTempAudioPools' is true, then all temporarly pools associated with 'tempAudioPoolKey' will be removed 202 * - If 'maxLength' is given, then any channels longer than that will be truncated, and silence appended to unaffected channels will not make the channel exceed this maximum length 203 */ 204 void moveDataFromTemp(const bool whichChannels[MAX_CHANNELS],unsigned tempAudioPoolKey,sample_pos_t moveWhere,sample_pos_t moveLength,bool removeTempAudioPools=true,sample_pos_t maxLength=NIL_SAMPLE_POS); 205 206 /* 207 * - Removes 'removeLength' samples of space from position 'removeWhere' and then moves 'moveLength' samples of data from the beginning of a temporary pool specified by 'tempAudioPoolKey' to position 'moveWhere' in the normal audio data pools for each channel where whichChannels[i] is true 208 * - If all channels where not affected then, each channel that was not affected will have 'moveLength' samples of silenced appended to it 209 * - If 'removeTempAudioPools' is true, then all temporarly pools associated with 'tempAudioPoolKey' will be removed 210 * - If 'maxLength' is given, then any channels longer than that will be truncated, and silence appended to unaffected channels will not make the channel exceed this maximum length 211 */ 212 void removeSpaceAndMoveDataFromTemp(const bool whichChannels[MAX_CHANNELS],sample_pos_t removeWhere,sample_pos_t removeLength,unsigned tempAudioPoolKey,sample_pos_t moveWhere,sample_pos_t moveLength,bool removeTempAudioPools=true,sample_pos_t maxLength=NIL_SAMPLE_POS); 213 214 /* 215 * - Removes all temporarly pools associated with 'tempAudioPoolKey' 216 */ 217 void removeTempAudioPools(unsigned tempAudioPoolKey); 218 219 // rotates 'amount' samples of data in the specified channel to the left or right between the 'start' and 'stop' positions 220 void rotateLeft(const bool whichChannels[MAX_CHANNELS],const sample_pos_t start,const sample_pos_t stop,const sample_pos_t amount); 221 void rotateRight(const bool whichChannels[MAX_CHANNELS],const sample_pos_t start,const sample_pos_t stop,const sample_pos_t amount); 222 223 // swaps the audio between channel A and channel B within the given region 224 void swapChannels(unsigned channelA,unsigned channelB,const sample_pos_t where,const sample_pos_t length); 225 226 227 void silenceSound(unsigned channel,sample_pos_t where,sample_pos_t length,bool doInvalidatePeakData=true,bool showProgressBar=true); 228 229 /* 230 * - mixes audio from src onto channel 'channel' starting at 'where' in this sound for 'length' samples (in this sound's sampleRate) 231 * - srcSampleRate specifies what sample rate src is in so that when it reads from src it will convert to this sound's sample rate 232 * - mixMethod specifies how to mix the data 233 * - if srcFit is no sftNone then src.getSize() samples from source will be squeezed into the [where,where+length) region in this sound using the specifed method to fit 234 */ 235 void mixSound(unsigned channel,sample_pos_t where,const CRezPoolAccesser src,sample_pos_t srcWhere,unsigned srcSampleRate,sample_pos_t length,MixMethods mixMethod,SourceFitTypes fitSrc,bool doInvalidatePeakData,bool showProgressBar); 236 237 238 const string getTimePosition(sample_pos_t samplePos,int secondsDecimalPlaces=3,bool includeUnits=true) const; 239 const sample_pos_t getPositionFromTime(const string time,bool &wasInvalid) const; 240 const string getAudioDataSize() const; 241 const string getAudioDataSize(sample_pos_t sampleCount) const; // with this object's format 242 const string getPoolFileSize() const; 243 244 void setIsModified(bool v); 245 const bool isModified() const; 246 247 // -------------------------------------------------------------------------- 248 // these members are used to manage the cues which a sound object can contain 249 // -------------------------------------------------------------------------- 250 251 #define MAX_SOUND_CUE_NAME_LENGTH 64 252 struct RCue 253 { RCueRCue254 RCue(const char _name[MAX_SOUND_CUE_NAME_LENGTH],sample_pos_t _time,bool _isAnchored) 255 { 256 strncpy(name,_name,MAX_SOUND_CUE_NAME_LENGTH); 257 name[MAX_SOUND_CUE_NAME_LENGTH]=0; 258 memset(reserved,0,sizeof(reserved)); 259 260 time=_time; 261 isAnchored=_isAnchored ? 1 : 0; 262 } 263 RCueRCue264 RCue(const RCue &src) 265 { 266 operator=(src); 267 } 268 269 RCue &operator=(const RCue &rhs) 270 { 271 strncpy(name,rhs.name,MAX_SOUND_CUE_NAME_LENGTH); 272 273 name[MAX_SOUND_CUE_NAME_LENGTH]=0; 274 time=rhs.time; 275 isAnchored=rhs.isAnchored; 276 277 return *this; 278 } 279 280 /* 281 * Instead of char I would like to have int8_t 282 * I have a test in configure.ac that makes SURE char is 1 byte, if there's 283 * ever a platform with char size other than 1, I will deal with it then 284 * because making this int8_t causes the string class and strxxx() functions 285 * to be incompatible 286 */ 287 char name[MAX_SOUND_CUE_NAME_LENGTH+1]; 288 289 290 // If for some reason, this isn't enough space in the future, 291 // I could just go with a new pool name and when loading an 292 // older version, just update to the new pool name and convert 293 // the older cues 294 uint8_t reserved[58]; 295 uint8_t isAnchored; 296 uint64_t time; 297 298 typedef uint8_t PackedChunk[ 299 MAX_SOUND_CUE_NAME_LENGTH+1+ //sizeof(name)+ 300 58+ //sizeof(reserved)+ 301 1+ //sizeof(isAnchored)+ 302 8 //sizeof(time) 303 ]; 304 packRCue305 void pack(PackedChunk &r) const 306 { 307 // pack the values of the data members into r in little-endian 308 309 register unsigned offset=0; 310 311 memcpy(r+offset,name,sizeof(name)); 312 offset+=sizeof(name); 313 314 memset(r+offset,0,sizeof(reserved)); 315 offset+=sizeof(reserved); 316 317 memcpy(r+offset,&isAnchored,sizeof(isAnchored)); 318 offset+=sizeof(isAnchored); 319 320 uint64_t tTime=hetle(time); 321 memcpy(r+offset,&tTime,sizeof(time)); 322 offset+=sizeof(time); 323 } 324 unpackRCue325 void unpack(const PackedChunk &r) 326 { 327 // unpack the little-endian values from r into the data members 328 329 register unsigned offset=0; 330 331 memcpy(&name,r+offset,sizeof(name)); 332 offset+=sizeof(name); 333 334 // no need to copy reserved 335 offset+=sizeof(reserved); 336 337 memcpy(&isAnchored,r+offset,sizeof(isAnchored)); 338 offset+=sizeof(isAnchored); 339 340 memcpy(&time,r+offset,sizeof(time)); 341 lethe(&time); 342 offset+=sizeof(time); 343 } 344 345 private: 346 friend class CrezSoundTranslator; RCueRCue347 RCue() {} 348 349 }; 350 351 const size_t getCueCount() const; 352 353 const string getCueName(size_t index) const; 354 355 const sample_pos_t getCueTime(size_t index) const; 356 void setCueTime(size_t index,sample_pos_t newTime); 357 358 const bool isCueAnchored(size_t index) const; 359 360 void addCue(const string &name,const sample_pos_t time,const bool isAnchored); 361 void insertCue(size_t index,const string &name,const sample_pos_t time,const bool isAnchored); 362 void removeCue(size_t index); 363 void clearCues(); 364 void enableCueAdjustmentsOnSpaceChanges(bool enabled); 365 366 static size_t __default_cue_index; 367 bool containsCue(const string &name,size_t &index=__default_cue_index) const; 368 // these following find methods return true if something is found else false 369 bool findCue(const sample_pos_t time,size_t &index) const; 370 bool findNearestCue(const sample_pos_t time,size_t &index,sample_pos_t &distance) const; // finds the cue nearest to the given time 371 bool findPrevCue(const sample_pos_t time,size_t &index) const; // finds the previous cue in time at the cue with the given time (false if none is found) 372 bool findNextCue(const sample_pos_t time,size_t &index) const; // finds the following cue in time at the cue with the given time (false if none is found) 373 374 bool findPrevCueInTime(const sample_pos_t time,size_t &index) const; // finds the previous cue in time from the given time (false if none is found) 375 bool findNextCueInTime(const sample_pos_t time,size_t &index) const; // finds the next cue in time from the given time (false if none is found) 376 377 const string getUnusedCueName(const string &prefix="noname") const; 378 379 // -------------------------------------------------------------------------- 380 // -------------------------------------------------------------------------- 381 // -------------------------------------------------------------------------- 382 383 384 385 // --- Methods for managing user notes 386 const string getUserNotes() const; 387 void setUserNotes(const string ¬es); 388 389 390 391 // - This method returns an accesser to a pool of the template type which can be used 392 // by other subsystems within ReZound to store any data they need to persist after 393 // the file is closed. 394 // - I prefix the pool name with "__GENERAL__ " so that they will be easily identifiable if 395 // necessary. And it means the method cannot be used to get at say one of the audio pools. 396 // - For now, the CSoundPlayerChannel class uses this to store the output routes of the 397 // channels within this sound, so a 4 channel sound can be played on a stereo sound card. getGeneralDataAccesser(const string poolName)398 template<class T> TPoolAccesser<T,PoolFile_t > getGeneralDataAccesser(const string poolName) 399 { 400 if(poolFile.containsPool("__GENERAL__ "+poolName)) 401 return poolFile.PoolFile_t::getPoolAccesser<T>("__GENERAL__ "+poolName); 402 else 403 return poolFile.PoolFile_t::createPool<T>("__GENERAL__ "+poolName); 404 } 405 getGeneralDataAccesser(const string poolName)406 template<class T> const TPoolAccesser<T,PoolFile_t > getGeneralDataAccesser(const string poolName) const 407 { 408 if(poolFile.containsPool("__GENERAL__ "+poolName)) 409 return poolFile.PoolFile_t::getPoolAccesser<T>("__GENERAL__ "+poolName); 410 else 411 throw runtime_error(string(__func__)+" -- general data pool does not exist: "+poolName); 412 } 413 containsGeneralDataPool(const string poolName)414 bool containsGeneralDataPool(const string poolName) const { return poolFile.containsPool("__GENERAL__ "+poolName); } 415 removeGeneralDataPool(const string poolName)416 void removeGeneralDataPool(const string poolName) { poolFile.removePool("__GENERAL__ "+poolName,false); } 417 418 419 void flush(); 420 421 void defragPoolFile(); 422 void printSAT(); // temporary for debugging ??? 423 void verifySAT(); // temporary for debugging ??? 424 425 private: 426 friend class ASoundTranslator; // so it can verify some things 427 friend class CrezSoundTranslator; 428 friend class ASoundRecorder; // so it can backupSAT() on the pool file when recording is done 429 430 431 typedef TPoolAccesser<sample_t,PoolFile_t > CInternalRezPoolAccesser; 432 433 CInternalRezPoolAccesser getAudioInternal(unsigned channel); 434 CInternalRezPoolAccesser getTempDataInternal(unsigned tempAudioPoolKey,unsigned channel); 435 436 PoolFile_t poolFile; 437 438 sample_pos_t size; // ??? rename to sampleCount 439 unsigned sampleRate; 440 unsigned channelCount; 441 442 // this should be called after every space modification and even loading of a file 443 // and pass NIL_SAMPLE_POS as the maxLength parameter to match to the longest channel 444 void matchUpChannelLengths(sample_pos_t maxLength,bool doZeroData=true); 445 446 void addSpaceToChannel(unsigned channel,sample_pos_t where,sample_pos_t length,bool doZeroData); 447 void removeSpaceFromChannel(unsigned channel,sample_pos_t where,sample_pos_t length); 448 void copyDataFromChannel(unsigned tempAudioPoolKey,unsigned channel,sample_pos_t where,sample_pos_t length); 449 void moveDataOutOfChannel(unsigned tempAudioPoolKey,unsigned channel,sample_pos_t where,sample_pos_t length); 450 void moveDataIntoChannel(unsigned tempAudioPoolKey,unsigned channelInTempPool,unsigned channelInAudio,sample_pos_t where,sample_pos_t length,bool removeTempAudioPool); 451 452 static void appendForFudgeFactor(CInternalRezPoolAccesser dest,const CInternalRezPoolAccesser src,sample_pos_t srcWhere,sample_pos_t fudgeFactor); 453 454 void prvAddChannel(bool addAudioSpaceForNewChannel,bool doZeroData); 455 456 struct RFormatInfo 457 { 458 uint32_t version; 459 uint64_t size; 460 uint32_t sampleRate; 461 uint32_t channelCount; 462 463 void operator=(const RFormatInfo &src) 464 { 465 version=src.version; 466 size=src.size; 467 sampleRate=src.sampleRate; 468 channelCount=src.channelCount; 469 } 470 471 }; 472 typedef TPoolAccesser<RFormatInfo,PoolFile_t > CFormatInfoPoolAccesser; 473 474 int metaInfoPoolID; 475 int channelPoolIDs[MAX_CHANNELS]; 476 477 typedef TPoolAccesser<RPeakChunk,PoolFile_t > CPeakChunkRezPoolAccesser; 478 CPeakChunkRezPoolAccesser *peakChunkAccessers[MAX_CHANNELS]; 479 480 unsigned tempAudioPoolKeyCounter; 481 482 bool _isModified; 483 484 485 typedef TPoolAccesser<RCue,PoolFile_t> CCuePoolAccesser; 486 CCuePoolAccesser *cueAccesser; 487 map<sample_pos_t,size_t> cueIndex; // index into cueAccesser by time 488 bool adjustCuesOnSpaceChanges; 489 490 void adjustCues(const sample_pos_t pos1,const sample_pos_t pos2); 491 void createCueAccesser(); 492 void deleteCueAccesser(); 493 void rebuildCueIndex(); 494 495 496 497 498 void createPeakChunkAccessers(); 499 void deletePeakChunkAccessers(); 500 501 static sample_pos_t calcPeakChunkCount(sample_pos_t givenSize); 502 503 static const string createTempAudioPoolName(unsigned tempAudioPoolKey,unsigned channel); 504 CInternalRezPoolAccesser createTempAudioPool(unsigned tempAudioPoolKey,unsigned channel); 505 void removeAllTempAudioPools(); 506 507 // saves the data-members to the meta info in the temporary poolFile 508 void saveMetaInfo(); 509 510 // called after every space modification to ensure that there is at least 1 sample of length 511 // zero length poses problems with selection positions, so I just always make sure there is at least 1 sample 512 void ensureNonZeroLength(); 513 514 515 516 517 // --- private locking methods only used by CSoundLocker ------------------------------ 518 friend class CSoundLocker; 519 520 // locks to keep the size from changing (multiple locks can be obtained of this type) 521 void lockSize() const; 522 bool trylockSize() const; 523 void unlockSize() const; 524 525 // locks to be able to change the size (only one lock can be obtained of this type) 526 void lockForResize() const; 527 bool trylockForResize() const; 528 void unlockForResize() const; 529 530 }; 531 532 class CSoundLocker { 533 const CSound *mSound; 534 const bool mLockForResize; 535 public: 536 CSoundLocker(const CSound *sound, bool lockForResize, bool trylock=false) mSound(sound)537 : mSound(sound) 538 , mLockForResize(lockForResize) 539 { 540 if(mLockForResize) { 541 if(trylock) { 542 // trylock for resize 543 if(!mSound->trylockForResize()) { 544 mSound = NULL; 545 } 546 } else { 547 // lock for resize 548 mSound->lockForResize(); 549 } 550 } else { 551 if(trylock) { 552 // trylock the size 553 if(!mSound->trylockSize()) { 554 mSound = NULL; 555 } 556 } else { 557 // lock the size 558 mSound->lockSize(); 559 } 560 } 561 } 562 ~CSoundLocker()563 ~CSoundLocker() { 564 unlock(); 565 } 566 isLocked()567 bool isLocked() const { 568 return mSound != NULL; 569 } 570 unlock()571 void unlock() { 572 if(mSound) { 573 if(mLockForResize) { 574 mSound->unlockForResize(); 575 } else { 576 mSound->unlockSize(); 577 } 578 mSound = NULL; 579 } 580 } 581 }; 582 583 #endif 584