Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

# StreamPlayer.cpp

Go to the documentation of this file.

    00001 //------------------------------------------------------------------------------
    00002 // Lamp : Open source game middleware
    00003 // Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
    00004 //
    00005 // This library is free software; you can redistribute it and/or
    00006 // modify it under the terms of the GNU Lesser General Public
    00007 // License as published by the Free Software Foundation; either
    00008 // version 2.1 of the License, or (at your option) any later version.
    00009 //
    00010 // This library is distributed in the hope that it will be useful,
    00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013 // Lesser General Public License for more details.
    00014 //
    00015 // You should have received a copy of the GNU Lesser General Public
    00016 // License along with this library; if not, write to the Free Software
    00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00018 //------------------------------------------------------------------------------
    00019
    00020 /** @file
    00021  * ストリームプレーヤ実装
    00022  * @author Junpee
    00023  */
    00024
    00025 #include "LampBasic.h"
    00026 #include "Sound/Utility/StreamPlayer.h"
    00027 #include "Sound/System/SoundBuffer.h"
    00028 #include "Sound/Reader/SoundReader.h"
    00029 #include "Core/Thread/SynchronizedBlock.h"
    00030
    00031 namespace Lamp{
    00032
    00033 //------------------------------------------------------------------------------
    00034 // コンストラクタ
    00035 StreamPlayer::StreamPlayer() :
    00036     directSoundNotify_(NULL), soundBuffer_(NULL), soundReader_(NULL),
    00037     cursor_(0), loopCursor_(0), initialized_(false){
    00038     for(int i = 0; i < eventCount_; i++){ event_[i] = NULL; }
    00039 }
    00040 //------------------------------------------------------------------------------
    00041 // デストラクタ
    00042 StreamPlayer::~StreamPlayer(){
    00043     soundBuffer_->stop();
    00044     // スレッド停止を待つ、SetEventは再生せずに削除する場合に必要
    00045     requestStop();
    00046     ::SetEvent(event_[2]);
    00047     join();
    00048     for(int i = 0; i < eventCount_; i++){
    00049         if(event_[i] != NULL){ CloseHandle(event_[i]); }
    00050     }
    00051     SafeRelease(directSoundNotify_);
    00052 }
    00053 //------------------------------------------------------------------------------
    00054 // 初期化
    00055 bool StreamPlayer::initialize(
    00056     SoundBuffer* soundBuffer, SoundReader* soundReader){
    00057     if(initialized_){ Assert(false); return true; }
    00058     soundBuffer_ = soundBuffer;
    00059     soundReader_ = soundReader;
    00060     Assert((soundBuffer_ != NULL) && (soundReader_ != NULL));
    00061     // 通知インターフェース初期化
    00062     if(DirectXFailed(soundBuffer_->getSoundBuffer()->QueryInterface(
    00063         DirectSoundNotifyInterfaceID, (void**)&directSoundNotify_))){
    00064         ErrorOut("StreamPlayer::initialize() "
    00065             "通知インターフェースの取得に失敗しました。");
    00066         return false;
    00067     }
    00068     // イベント初期化
    00069     for(int i = 0; i < eventCount_; i++){
    00070         event_[i] = ::CreateEvent(NULL, false, false, NULL);
    00071     }
    00072     DSBPOSITIONNOTIFY cursorNotify[eventCount_];
    00073     cursorNotify[0].dwOffset = 0;
    00074     cursorNotify[0].hEventNotify = event_[0];
    00075     cursorNotify[1].dwOffset = soundBuffer_->getBufferSize() / 2;
    00076     cursorNotify[1].hEventNotify = event_[1];
    00077     cursorNotify[2].dwOffset = DSBPN_OFFSETSTOP;
    00078     cursorNotify[2].hEventNotify = event_[2];
    00079     if(DirectXFailed(directSoundNotify_->SetNotificationPositions(
    00080         eventCount_, cursorNotify))){
    00081         ErrorOut("StreamPlayer::initialize() "
    00082             "通知イベントの設定に失敗しました。");
    00083     }
    00084     // ロード前に再生されるとまずいので最初にバッファを半分読み込む
    00085     reset();
    00086     initialized_ = true;
    00087     // 実行
    00088     start();
    00089     return true;
    00090 }
    00091 //------------------------------------------------------------------------------
    00092 // リセット
    00093 void StreamPlayer::reset(){
    00094     bool result = writeStream(0);
    00095     Assert(result);
    00096 }
    00097 //------------------------------------------------------------------------------
    00098 // 実行
    00099 void StreamPlayer::run(Thread* thread){
    00100     Assert(initialized_);
    00101     while(!isStopRequested()){
    00102         u_long flag = ::WaitForMultipleObjects(
    00103             eventCount_, event_, false, INFINITE);
    00104         switch(flag){
    00105             case WAIT_OBJECT_0 + 0:
    00106                 // 停止命令が無い状態で書き込みが成功するまでループ
    00107                 while((!isStopRequested()) && (!writeStream(1))){ yield(); }
    00108                 break;
    00109             case WAIT_OBJECT_0 + 1:
    00110                 // 停止命令が無い状態で書き込みが成功するまでループ
    00111                 while((!isStopRequested()) && (!writeStream(0))){ yield(); }
    00112                 break;
    00113             case WAIT_OBJECT_0 + 2:
    00114                 break;
    00115         }
    00116     }
    00117 }
    00118 //------------------------------------------------------------------------------
    00119 // ストリーム書き込み
    00120 bool StreamPlayer::writeStream(int offset){
    00121     u_int size = soundBuffer_->getSize();
    00122     bool isLoop = soundBuffer_->isLoop();
    00123     u_int writeSize = soundBuffer_->getBufferSize() / 2;
    00124     u_int writeOffset = writeSize * (offset & 1);
    00125     // 最後に書き込んだバッファが再生されてから停止する
    00126     if((!isLoop) && (cursor_ == size)){
    00127         soundBuffer_->stop();
    00128         return true;
    00129     }
    00130     // ロック
    00131     SoundBuffer::Lock& lock = soundBuffer_->lock(writeOffset, writeSize);
    00132     if(!lock.isValid()){ return false; }
    00133     // バッファ後半にはロックがかからないはず
    00134     Assert((lock.getAddress0() != NULL) && (lock.getSize0() == writeSize));
    00135     Assert((lock.getAddress1() == NULL) && (lock.getSize1() == 0));
    00136     // パラメータの確保
    00137     u_int cursor, loopCursor;
    00138     {
    00139         SynchronizedBlock synchronizedBlock(this);
    00140         cursor = cursor_;
    00141         loopCursor = loopCursor_;
    00142         cursor_ += writeSize;
    00143         // ループ処理
    00144         if(cursor_ > size){
    00145             if(isLoop){ cursor_ = loopCursor + (cursor_ - size); }
    00146             else{ cursor_ = size; }
    00147         }
    00148     }
    00149     Assert(soundReader_->getCursor() == cursor);
    00150     // ストリーム前半書き込み
    00151     int preWriteSize = writeSize;
    00152     int postWriteSize = (cursor + writeSize) - size;
    00153     if(postWriteSize > 0){ preWriteSize -= postWriteSize; }
    00154     int result = soundReader_->read(lock.getAddress0(), preWriteSize);
    00155     Assert(result == preWriteSize);
    00156     // ストリーム後半書き込み
    00157     char* postWriteAddress = (((char*)lock.getAddress0()) + preWriteSize);
    00158     if(postWriteSize > 0){
    00159         if(isLoop){
    00160             // ループ位置に戻る
    00161             soundReader_->setCursor(loopCursor);
    00162             result = soundReader_->read(postWriteAddress, postWriteSize);
    00163             Assert(result == postWriteSize);
    00164         }else{
    00165             // 残りを0(16bit)か128(8bit)で埋める
    00166             u_char value = 0;
    00167             if(soundBuffer_->getBit() == 8){ value = 128; }
    00168             ::memset(postWriteAddress, 0, postWriteSize);
    00169         }
    00170     }
    00171     soundBuffer_->unlock();
    00172     return true;
    00173 }
    00174 //------------------------------------------------------------------------------
    00175 // 再生位置
    00176 //------------------------------------------------------------------------------
    00177 // 再生位置設定
    00178 void StreamPlayer::setCursor(u_int cursor){
    00179     Assert(cursor <= soundBuffer_->getSize());
    00180     // 1サンプル以下のバイト数は切り捨てる
    00181     u_int fixedCursor =
    00182         cursor - (cursor % soundBuffer_->getOneSampleBytes());
    00183     {
    00184         SynchronizedBlock synchronizedBlock(this);
    00185         cursor_ = fixedCursor;
    00186         soundReader_->setCursor(cursor_);
    00187     }
    00188 }
    00189 //------------------------------------------------------------------------------
    00190 // ループ
    00191 //------------------------------------------------------------------------------
    00192 // ループ位置の設定
    00193 void StreamPlayer::setLoopCursor(u_int loopCursor){
    00194     Assert(loopCursor <= soundBuffer_->getSize());
    00195     // 1サンプル以下のバイト数は切り捨てる
    00196     u_int fixedLoopCursor =
    00197         loopCursor - (loopCursor % soundBuffer_->getOneSampleBytes());
    00198     {
    00199         SynchronizedBlock synchronizedBlock(this);
    00200         loopCursor_ = fixedLoopCursor;
    00201     }
    00202 }
    00203 //------------------------------------------------------------------------------
    00204 } // End of namespace Lamp
    00205 //------------------------------------------------------------------------------