/*************************************************************************/ /* File : WaveSeek.cpp */ /* */ /* Author : Leïla AIT KACI (www.noxaka.com) */ /* Last Modification : 15/09/07 */ /*************************************************************************/ #include "CKAll.h" CKObjectDeclaration* FillBehaviorWaveSeekDecl (); CKERROR CreateWaveSeekProto (CKBehaviorPrototype **); int WaveSeek (const CKBehaviorContext& BehContext); int WaveSeekCallback (const CKBehaviorContext& behcontext); ////////////////////////////////////////////////////////////////////// // Defines ////////////////////////////////////////////////////////////////////// #define BB_NAME "Wave Seek" #define BB_DESC "Seek in a Wave Sound File played with the Wave Player." #define BB_CAT "Sounds/Basic" #define BB_VERSION 0x00010000 #define BB_TARGET CKCID_WAVESOUND ////////////////////////////////////////////////////////////////////// // Enums for Parameter's Indexes ////////////////////////////////////////////////////////////////////// enum BB_IN { IN_IN }; enum BB_OUT { OUT_OUT }; enum BB_PIN { PIN_TIME = 0, PIN_PROGRESSION = 0 }; enum BB_LOC { SET_PROGRESSION }; ////////////////////////////////////////////////////////////////////////////// CKObjectDeclaration *FillBehaviorWaveSeekDecl() { CKObjectDeclaration *od = CreateCKObjectDeclaration(BB_NAME); od->SetType(CKDLL_BEHAVIORPROTOTYPE); od->SetCompatibleClassId(BB_TARGET); od->SetAuthorGuid(VIRTOOLS_GUID); od->SetAuthorName("Virtools"); od->SetDescription(BB_DESC); od->SetVersion(BB_VERSION); od->SetCategory(BB_CAT); od->SetGuid(CKGUID(0x43362343, 0x61f591b0)); od->SetCreationFunction(CreateWaveSeekProto); return od; } ////////////////////////////////////////////////////////////////////////////// CKERROR CreateWaveSeekProto(CKBehaviorPrototype** pproto) { CKBehaviorPrototype *proto = CreateCKBehaviorPrototype(BB_NAME); if (!proto) { return CKERR_OUTOFMEMORY; } //--- proto->DeclareInput("In"); //--- proto->DeclareOutput("Out"); //---- proto->DeclareInParameter("Time", CKPGUID_TIME); //---- proto->DeclareSetting("Use Progression", CKPGUID_BOOL, "FALSE"); proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)(CKBEHAVIOR_TARGETABLE)); proto->SetBehaviorCallbackFct(WaveSeekCallback, CKCB_BEHAVIORSETTINGSEDITED); proto->SetFunction(WaveSeek); *pproto = proto; return CK_OK; } ////////////////////////////////////////////////////////////////////////////// int WaveSeek(const CKBehaviorContext& BehContext) { CKBehavior* beh = BehContext.Behavior; CKContext* ctx = BehContext.Context; //--- beh->ActivateInput(IN_IN, FALSE); beh->ActivateOutput(OUT_OUT, TRUE); //--- CKWaveSound* wav = (CKWaveSound*) beh->GetTarget(); if ( !wav ) return CKBR_OK; //--- CKBOOL Playing = wav->IsPlaying(); //--- CKBOOL UseProgression; beh->GetLocalParameterValue(SET_PROGRESSION, &UseProgression); //--- float time = 0.0f; if ( UseProgression ) { float Progression = 0; beh->GetInputParameterValue(PIN_PROGRESSION, &Progression); time = Progression * wav->GetSoundLength(); } else beh->GetInputParameterValue(PIN_TIME, &time); if ( time < 0 ) time = 0; else if ( time > wav->GetSoundLength() ) { wav->Stop(0); return CKBR_OK; } //// Find the closest byte positioning in the file int ByteTime = (DWORD) (time * (float) wav->m_WaveFormat.nAvgBytesPerSec / 1000.0f); ByteTime -= ByteTime % wav->m_WaveFormat.nBlockAlign; //// CKSoundManager* sm = (CKSoundManager*) ctx->GetManagerByGuid(SOUND_MANAGER_GUID); if ( wav->GetFileStreaming() && !(wav->m_State & CK_WAVESOUND_STREAMFULLYLOADED) ) { CKSoundReader* reader = wav->GetReader(); if ( reader ) { // Pause the sound before modifying the reading positions if ( Playing ) sm->Pause(wav, wav->m_Source); // Seek time depends on the reader used int SeekTime = 0; CKPluginInfo* info = reader->GetReaderInfo(); if ( info->m_Summary == "DShow Reader" ) SeekTime = (int) time; else if ( info->m_Summary == "Wav Reader" ) SeekTime = ByteTime; // + 4; else { #ifdef macintosh SeekTime = (int) time; #endif } // Seek on the reader to decode the requested part // Repositiong the playing and reading times if ( reader->Seek(SeekTime) != CK_OK ) { ctx->OutputToConsoleExBeep("[Sound Seek Error] %s was unable to seek.", info->m_Summary); return CKBR_OK; } wav->m_DataPlayed = ByteTime; wav->m_DataRead = ByteTime; // Seek on the sound buffer. We position the reading head one sample before the last // readed data to avoid stream overlaping when decoding data below. This sample should // not be audible. Also change the oldcursor as we "jump" in the playing process (avoid // adding a wrong playing time). wav->m_State &= ~CK_WAVESOUND_STREAMOVERLAP; sm->SetPlayPosition(wav->m_Source, wav->m_BufferPos - wav->m_WaveFormat.wBitsPerSample/8); wav->m_OldCursorPos = sm->GetPlayPosition(wav->m_Source); // We can now decode new datas from the sound file if ( wav->WriteDataFromReader() != CK_OK ) { ctx->OutputToConsoleExBeep("[Sound Seek Error] Unable to decode sound data.", info->m_Summary); return CKBR_OK; } // Now, we can start the sound again when it was playing if ( Playing ) sm->Play(wav, wav->m_Source, wav->GetLoopMode()); } } else sm->SetPlayPosition(wav->m_Source, ByteTime); wav->m_State &= ~CK_WAVESOUND_NEEDREWIND; return CKBR_OK; } ////////////////////////////////////////////////////////////////////////////// int WaveSeekCallback(const CKBehaviorContext& BehContext) { CKBehavior* beh = BehContext.Behavior; CKContext* ctx = BehContext.Context; //--- CKBOOL UseProgression; beh->GetLocalParameterValue(SET_PROGRESSION, &UseProgression); //--- CKParameterIn* pin = beh->GetInputParameter(PIN_TIME); if ( UseProgression && strcmp(pin->GetName(),"Progression") ) { pin->SetName("Progression"); pin->SetGUID(CKPGUID_PERCENTAGE); } else if ( !UseProgression && strcmp(pin->GetName(),"Time") ) { pin->SetName("Time"); pin->SetGUID(CKPGUID_TIME); } return CKBR_OK; }