/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2008/X/X - 2015/11/11
/// 
/// @brief  DirectSound 静的バッファ周り。
/// 
/// ****************************************************************************
#pragma once

#include "../Core/Base/CPL_Core_Encryption.h"
#include "CPL_DX_SoundBase.h"
#include "../CPL_Setup.h"

#include "CPL_DX_SoundBase.cpp"


namespace CPL {
namespace DX {
namespace Audio {


// _____________________________________________________________________________
/// @brief SoundPlayerEntity_for_Stream実体定義
///
// *****************************************************************************
class SoundPlayerEntity_for_Stream
  : public baseSoundPlayer::Entity_
{
public:
  //static const int    CSc_CHANNEL_BUF_SIZE = Core::CSC_BLOCK_SIZE * 512;
  //static const int    WAVe_CHANNEL_BUF_SIZE = 256 * 512;


  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static int CalculatePcmBufSize( _in<Core::WaveFormatEx> wfex )
  {
    const int channel         = wfex.nChannels;
    const int sample_per_sec  = static_cast<int>(wfex.nSamplesPerSec);
    const int byte_per_sample = wfex.wBitsPerSample / 8;

    // とりあえず１秒とする。
    return channel * sample_per_sec * byte_per_sample * 1;
  }
    
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  struct ThreadRead
    : public Core::ThreadEx
  {
    using atomic_int_ = std::atomic<int>;

    SoundPlayerEntity_for_Stream* m_ptr_dxsnd_player;
    Core::WaveFormatEx            m_wfex;
    sdptr<Core::BaseSoundManager> m_sp_snd_mng;
    atomic_int_                   m_flag_finish;

    bool IsFinish() const { return m_flag_finish.load() > 0; }
    void SetExit(){ m_flag_finish.store( -1 ); } // 強制終了用フラグをセット
    bool IsExit() const { return m_flag_finish.load() == -1; }

    // _____________________________________________________________________________
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ThreadRead
    ( _in<SoundPlayerEntity_for_Stream*> in_ptr_dxsnd_player
    , _in<Core::WaveFormatEx           > in_wfex
    , _in<sdptr<Core::BaseSoundManager>> in_sp_snd_mng
    , pin<char                         > in_thread_name = "" )
      : Core::ThreadEx( in_thread_name )
      , m_ptr_dxsnd_player( in_ptr_dxsnd_player )
      , m_wfex( in_wfex )
      , m_sp_snd_mng( in_sp_snd_mng )
      , m_flag_finish( 0 )
    {}
    // _____________________________________________________________________________
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~ThreadRead()
    {
      SetExit();
      // Join(); 基底デストラクタで呼ばれるので呼んじゃいけない。
    }
    // _____________________________________________________________________________
    /// @brief メインスレッド。
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    size_t operator()()
    {
      const int wait_step    = 100;
      const int pcm_buf_size = CalculatePcmBufSize( m_wfex ); // とりあえず1秒分のバッファサイズとする。
      Core::DefaultBuffer tmp_buf( pcm_buf_size );
      char* tmp_buf_addr = static_cast<char*>(tmp_buf.GetDataAddr());

      // 最初のブロックを読み込み。
      m_sp_snd_mng->SeekSetPCM( 0 );
      // 前半部分に書き込み。
      auto read_size =
        m_ptr_dxsnd_player->WriteDsBuffer( 0, *m_sp_snd_mng, pcm_buf_size );

      //
      char flag[ 2 ] = { true, false }; // 読み込み済みフラグ。前半部分は、既に読み込んでいなければならない

      while( true )
      {
        CPL::CPL_Sleep( td_time_msec(wait_step) );

        if( IsExit() ) // 強制終了検査
        {
          break;
        }

        SDEF pos   = m_ptr_dxsnd_player->GetPos();
        int  f_idx = ((pos / pcm_buf_size)!=0); // 本来の演算結果も0or1になるが、警告回避のため論理判定。

        if( !flag[ !f_idx ] ) // もう一つの領域が未読み込みの場合。
        {
          flag[ !f_idx  ] = true;
          flag[ f_idx ]   = false;

          // データ読み込み
          read_size = m_sp_snd_mng->ReadPCM( tmp_buf_addr, pcm_buf_size );

          // 読み込んだサイズが指定サイズを下回った場合（おそらく終端に達した）
          if( read_size < pcm_buf_size )
          {
            // 先頭に戻って、続きを読み込む。
            m_sp_snd_mng->SeekSetPCM( 0 );
            read_size +=
              m_sp_snd_mng->ReadPCM
              ( tmp_buf_addr + read_size,
                pcm_buf_size - read_size );
          }

          switch( f_idx )
          {
          case 0:
            // 後半部分に書き込み
            m_ptr_dxsnd_player->WriteDsBuffer
              ( pcm_buf_size, tmp_buf_addr, pcm_buf_size );
            break;
          case 1:
            // 前半部分に書き込み
            m_ptr_dxsnd_player->WriteDsBuffer
              ( 0, tmp_buf_addr, pcm_buf_size );
            break;
          }
        }


        //// 読み込みサイズが指定サイズと違う場合（終端まで読みきった）
        //if( m_sp_snd_stream->IsEOF() )
        //{
        //  int ms_time = static_cast<int>(1000 * read_size / pcm_buf_size) - 10;
        //  if( ms_time > 0 )
        //  {
        //    CPL_Sleep( ms_time );
        //  }
        //  // 待機したあと、読み込み位置を初期へ戻す
        //  m_sp_snd_mng->SeekSetPCM( 0 );
        //}
      }
      return 0;
    }
  };

  
  //// _____________________________________________________________________________
  //struct baseThread
  //  : public WIN::Thread
  //{
  //  volatile int m_flag_finish;

  //  bool IsFinish() const { return m_flag_finish > 0; }
  //  void SetExit(){ m_flag_finish = -1; } // 強制終了用フラグをセット
  //  bool IsExit() const { return m_flag_finish == -1; }

  //  baseThread() : m_flag_finish(false) {}
  //  ~baseThread()
  //  {
  //    SetExit();
  //    WaitFinish();
  //  }
  //};
  //
  //// _____________________________________________________________________________
  ///// @brief WAVE読み込み用スレッド
  /////
  //// *****************************************************************************
  //struct ThreadReadWAVE
  //  : public baseThread
  //{
  //  const WAVEFORMATEX m_wfex;
  //  const int          m_data_offset;

  //  int Call( void* in_arglist );

  //  ThreadReadWAVE
  //  ( SoundPlayerEntity_for_Stream* in_ptr_snd_buf_stm,
  //    int                     data_offs_,
  //    const WAVEFORMATEX&     wfex_ )
  //    : m_wfex( wfex_ )
  //    , m_data_offset( data_offs_ )
  //  {
  //    Create( nullptr, 0, in_ptr_snd_buf_stm );
  //  }
  //};

  //// _____________________________________________________________________________
  ///// @brief CSC読み込み用スレッド
  /////
  //// *****************************************************************************
  //struct ThreadReadCSC
  //  : public baseThread
  //{
  //  int Call( void* in_arglist );

  //  ThreadReadCSC( SoundPlayerEntity_for_Stream* in_ptr_snd_buf_stm )
  //  {
  //    Create( nullptr, 0, in_ptr_snd_buf_stm );
  //  }
  //};

  std::shared_ptr<Core::ThreadEx>  m_sp_read_thread;


public:
  // _____________________________________________________________________________
  /// @brief サウンドバッファの作成。
  /// 
  /// @param[in] in_cp_dx_sound : DirectSoundオブジェクトのスマポ。
  /// @param[in] in_sp_snd_mng  : ストリームクラス。
  /// @param[in] in_flags       : DSBUFFERDESC構造体のdwFlagsに渡す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  bool
    Create
      ( _in<CpDXSound                    > in_cp_dx_sound
      , _in<sdptr<Core::BaseSoundManager>> in_sp_snd_mng
      , _in<DWORD                        > in_flags
      )
  {
    m_cp_dsound_buf = nullptr; // 解放＆初期化

    m_cp_dsound  = in_cp_dx_sound;
    m_sp_snd_mng = in_sp_snd_mng;

    // フォーマット取得。
    auto* ptr_wfex  = in_sp_snd_mng->GetWaveFormatEx();
    int   data_size = in_sp_snd_mng->GetBufferSizePCM();
    if( data_size <= 0 )
    {
      return false;
    }
    int pcm_block_size = CalculatePcmBufSize( *ptr_wfex );
    int dx_buf_size    = Min( pcm_block_size * 2, data_size );

    // DirectSoundBuffer設定
    DSBUFFERDESC desc;
    ::memset( &desc, 0, sizeof(desc) );
    desc.dwSize        = sizeof(desc);
    desc.dwFlags       = in_flags;
    desc.dwBufferBytes = dx_buf_size;
    desc.lpwfxFormat   = reinterpret_cast<WAVEFORMATEX*>(ptr_wfex);
    // DirectSoundバッファ作成。
    IDirectSoundBuffer* ptr_dsb_tmp = nullptr;
    HRESULT hr = m_cp_dsound->CreateSoundBuffer( &desc, &ptr_dsb_tmp, nullptr );
    if( ptr_dsb_tmp )
    {
      hr = ptr_dsb_tmp->QueryInterface
             ( IID_IDirectSoundBuffer8, (void**)&m_cp_dsound_buf );
    }
    ptr_dsb_tmp->Release();

    if( FAILED(hr) )
    {
      CPL_THROW("サウンドバッファの作成に失敗");
      return false;
    }

    // サウンドの長さをチェック。
    // ２ブロック(現仕様で２秒)以下の場合は全てのデータを展開する。
    if( pcm_block_size * 2 > dx_buf_size )
    {
      WriteDsBuffer( 0, *m_sp_snd_mng, dx_buf_size );
    }
    else
    {
      // スレッド作成
      m_sp_read_thread =
        CPL_MAKE_SHARED( ThreadRead, this, *ptr_wfex, m_sp_snd_mng );
      m_sp_read_thread->Start();
    }

    return true;
  }


  //// _____________________________________________________________________________
  ///// @brief サウンドバッファの作成　※ CSC指定バージョン
  ///// 
  ///// @param[in] in_cp_dx_sound : DirectSoundオブジェクトのスマポ。
  ///// @param[in] in_csc_stm     : CSCストリームクラス。
  ///// @param[in] in_flags       : DSBUFFERDESC構造体のdwFlagsに渡す。
  //// _____________________________________________________________________________
  //bool
  //  Create
  //  ( cref<CpDXSound>          in_cp_dx_sound,
  //    Core::CscFileStream_cref in_csc_stm,
  //    DWORD                    in_flags )
  //{
  //  m_cp_dsound_buf = nullptr; // 解放＆初期化

  //  m_cp_dsound   = in_cp_dx_sound;
  //  m_sp_file_stm = CPL_MAKE_SHARED(Core::CscFileStream)( in_csc_stm );

  //  // フォーマット取得
  //#if (CPL_CSC_VERSION == 1)
  //  const Core::CscHeaderInfo info = in_csc_stm.GetHeader();
  //#elif (CPL_CSC_VERSION == 2)
  //  const Core::CscHeaderInfo2 info = in_csc_stm.GetHeader2();
  //#endif
  //  const int data_size = info.sample_num * info.channel * info.bits / 8;

  //  // WAVEフォーマット設定
  //  WAVEFORMATEX wfex;
  //  wfex.wFormatTag      = WAVE_FORMAT_PCM;
  //  wfex.nChannels       = info.channel;
  //  wfex.nSamplesPerSec  = info.sample_per_sec;
  //  wfex.wBitsPerSample  = info.bits;
  //  wfex.nBlockAlign     = wfex.nChannels * wfex.wBitsPerSample / 8;
  //  wfex.nAvgBytesPerSec = info.sample_per_sec * wfex.nBlockAlign;
  //  wfex.cbSize          = 0;

  //  int read_def_size = Min<int>( CSc_CHANNEL_BUF_SIZE * info.channel * 2, data_size );

  //  // DirectSoundBuffer設定
  //  DSBUFFERDESC desc;
  //  ::memset( &desc, 0, sizeof(desc) );
  //  desc.dwSize        = sizeof(desc);
  //  desc.dwFlags       = in_flags;
  //  desc.dwBufferBytes = read_def_size;
  //  desc.lpwfxFormat   = &wfex;
  //  // バッファ作成
  //  IDirectSoundBuffer* ptr_dsb_tmp = nullptr;
  //  HRESULT hr = m_cp_dsound->CreateSoundBuffer( &desc, &ptr_dsb_tmp, nullptr );
  //  if( ptr_dsb_tmp )
  //  {
  //    hr = ptr_dsb_tmp->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_cp_dsound_buf );
  //  }
  //  ptr_dsb_tmp->Release();

  //  if( FAILED(hr) )
  //  {
  //    CPL_THROW("サウンドバッファの作成に失敗");
  //    return false;
  //  }

  //  Core::Array::Constant<U8> tmp_buf( CSc_CHANNEL_BUF_SIZE * info.channel * 2, 0 );
  //#if (CPL_CSC_VERSION == 1)
  //  // ブロックデータ読み込み
  //  Array::Constant<WIN::CscBlockInfo> BlockBuf( info.block_num );
  //  in_csc_stm.SeekSet( sizeof(Core::CscHeaderInfo) - sizeof(WIN::CscBlockInfo) );
  //  in_csc_stm.Read( &BlockBuf[0], BlockBuf.GetSize() );

  //  // ブロック情報を復号化
  //  Decryption(
  //    &BlockBuf[ 0 ],
  //    sizeof(WIN::CscBlockInfo) * in_csc_stm.GetHeader().block_num,
  //    in_csc_stm.GetMask(),
  //    in_csc_stm.GetMask().GetLength() );


  //  // CSC -> WAVE
  //  try {
  //    in_csc_stm.Decode( &BlockBuf[0], &tmp_buf[0], 0, desc.dwBufferBytes / info.channel / (info.bits/8), true, nullptr );
  //  }
  //  catch(...)
  //  {
  //    return false;
  //  }
  //#elif (CPL_CSC_VERSION == 2)
  //  // ブロックオフセット情報読み込み
  //  Core::Array::Constant<Core::CscBlockInfo2> block_info_table( info.block_num );
  //  in_csc_stm.SeekSet( sizeof(info) );
  //  in_csc_stm.Read( &block_info_table[0], block_info_table.GetSize() );

  //  // 復号化
  //  Decryption(
  //    &block_info_table[ 0 ],
  //    block_info_table.GetSize(),
  //    in_csc_stm.GetMask(),
  //    static_cast<int>(in_csc_stm.GetMask().GetLength()) );

  //  // CSC -> WAVE
  //  try {
  //    in_csc_stm.Decode2_Range(
  //      &block_info_table[ 0 ],
  //      &tmp_buf[0],
  //      0,
  //      desc.dwBufferBytes / info.channel / (info.bits/8),
  //      true,
  //      nullptr );
  //  }
  //  catch(...)
  //  {
  //    return false;
  //  }

  //#endif

  //  // データ書き込み
  //  WriteDsBuffer( 0, &tmp_buf[0], read_def_size );

  //  // スレッド作成
  //  if( data_size > read_def_size )
  //  {
  //    m_sp_read_thread = CPL_MAKE_SHARED(ThreadReadCSC)( this );
  //  }

  //  return true;
  //}


  // _____________________________________________________________________________
  /// @brief サウンドバッファの作成　※ ファイル指定バージョン。
  /// 
  /// @param[in] in_cp_dx_sound : DirectSoundオブジェクトのスマポ。
  /// @param[in] in_path        : ファイルへのパス。
  /// @param[in] in_mask        : ファイルがCSCの場合、
  /// @param[in] in_flags       : DSBUFFERDESC構造体のdwFlagsに渡す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  bool
    Create
      ( _in<CpDXSound    > in_cp_dx_sound
      , pin<str_type     > in_path
      , _in<Core::StringA> in_mask
      , _in<DWORD        > in_flags
      )
  {
    // 拡張子取得
    Core::String str = in_path;
    Core::String ext;
    str.FindEndBack( ext, SwS('.'), false );

    if( _tcsicmp( ext, SwS("wav") ) == 0  ||
        _tcsicmp( ext, SwS("wave") ) == 0 )
    {
      auto sp_snd_buf  = CPL_MAKE_SHARED( Core::FileStream, in_path, Core::FileStream::kREAD_BINARY );
      auto sp_wave_mng = CPL_MAKE_SHARED( Core::WaveManager, sp_snd_buf );

      return Create( in_cp_dx_sound, sp_wave_mng, in_flags );
    }
#ifdef CPL_USE_OGG_VORBIS
    else
    if( _tcsicmp( ext, SwS("ogg") ) == 0  ||
        _tcsicmp( ext, SwS("oga") ) == 0 )
    {
      auto sp_snd_buf = CPL_MAKE_SHARED( Core::FileStream, in_path, Core::FileStream::kREAD_BINARY );
      auto sp_ov_mng  = CPL_MAKE_SHARED( Core::OvManager, sp_snd_buf );

      return Create( in_cp_dx_sound, sp_ov_mng, in_flags );
    }
#endif
  //  ef( ext == SwS("csc")  ||  ext == SwS("csc") )
  //  {
  //    Core::CscFileStream csc_stream( in_path, true, in_mask );

  //    return Create( in_cp_dx_sound, csc_stream, in_flags );
  ////    return true;
  //  }
    return false;
  }

  // _____________________________________________________________________________
  /// @brief デフォルトコンストラクタ。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SoundPlayerEntity_for_Stream()
  {}

  // _____________________________________________________________________________
  /// @brief WAVEストリーム対応コンストラクタ
  /// @copydetails Create(_in<CpDXSound>,_in<sdptr<Core::BaseSoundManager>>,_in<DWORD>)
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SoundPlayerEntity_for_Stream
  ( _in<CpDXSound                    > in_cp_dx_sound
  , _in<sdptr<Core::BaseSoundManager>> in_sp_snd_mng
  , _in<DWORD                        > in_flags )
  {
    CPL_THROW_IF(
      !Create( in_cp_dx_sound, in_sp_snd_mng, in_flags ),
      "実体の生成に失敗" );
  }

  //// _____________________________________________________________________________
  ///// @brief CSCストリーム対応コンストラクタ。
  ///// @copydetails Create(cref<CpDXSound>,Core::CscFileStream_cref,DWORD)
  //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //SoundPlayerEntity_for_Stream
  //( cref<CpDXSound>          in_cp_dx_sound,
  //  Core::CscFileStream_cref in_csc_stm,
  //  DWORD                    in_flags )
  //{
  //  CPL_THROW_IF(
  //    !Create( in_cp_dx_sound, in_csc_stm, in_flags ),
  //    "実体の生成に失敗" );
  //}

  // _____________________________________________________________________________
  /// @brief ファイル読み込み対応コンストラクタ。
  /// @copydetails Create(_in<CpDXSound>,pin<str_type>,_in<Core::StringA>,_in<DWORD>)
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SoundPlayerEntity_for_Stream
  ( _in<CpDXSound    > in_cp_dx_sound
  , pin<str_type     > in_path
  , _in<Core::StringA> in_mask
  , _in<DWORD        > in_flags )
  {
    CPL_THROW_IF(
      !Create( in_cp_dx_sound, in_path, in_mask, in_flags ),
      "実体の生成に失敗" );
  }
};



///// @copydoc SoundPlayerEntity_for_Stream::GetFileStream
//Core::FileStreamCell::shared_ptr
//  SoundStreamPlayer::GetFileStream()
//{
//  return getEntity<Entity_>()->GetFileStream();
//}



//// _____________________________________________________________________________
//// WAVE用読み込みスレッド
//// _____________________________________________________________________________
//int SoundPlayerEntity_for_Stream::ThreadReadWAVE::Call( void* in_arglist )
//{
//  {
//    auto*
//      ptr_sndbuf_stream =
//        reinterpret_cast<Entity_*>(in_arglist);
//    auto
//      m_sp_snd_stream =
//        ptr_sndbuf_stream->GetFileStream()->CreateStreamCell( m_data_offset, -1 );
//
//    const int wait_step = 100;
//    const int wave_buf_size = WAVe_CHANNEL_BUF_SIZE * m_wfex.nChannels;
//    Core::Array::Dynamic<U8> tmp_buf( wave_buf_size * 2 );
//    char flag[ 2 ] = { true, false }; // 読み込み済みフラグ。前半部分は、既に読み込んでいなければならない
//
//    m_sp_snd_stream->SeekSet( wave_buf_size );
//
//    while( true )
//    {
//      CPL::CPL_Sleep( wait_step );
//      
//      if( IsExit() ) // 強制終了検査
//      {
//        break;
//      }
//
//      SDEF pos = ptr_sndbuf_stream->GetPos();
//      SDEF read_size = 0;
//      bool f_idx = ((pos / wave_buf_size)!=0); // 本来の演算結果も0or1になるが、警告回避のため論理判定。
//
//      if( !flag[ !f_idx ] ) // 別の領域が
//      {
//        flag[ !f_idx  ] = true;
//        flag[ f_idx ] = false;
//
//        // データ読み込み
//        read_size = m_sp_snd_stream->Read( &tmp_buf[0], wave_buf_size );
//
//        if( read_size < wave_buf_size ) // 読み込んだサイズが指定サイズを下回った場合（おそらく終端に達した）
//        {
//          // 先頭に戻って、続きを読み込む
//          m_sp_snd_stream->SeekSet( 0 );
//          read_size += m_sp_snd_stream->Read( &tmp_buf[ read_size ], wave_buf_size - read_size );
//        }
//
//        switch( f_idx )
//        {
//        case 0:
//          ptr_sndbuf_stream->WriteDsBuffer( wave_buf_size, &tmp_buf[0], wave_buf_size ); // 後半部分に書き込み
//          break;
//        case 1:
//          ptr_sndbuf_stream->WriteDsBuffer( 0, &tmp_buf[0], wave_buf_size ); // 前半部分に書き込み
//          break;
//        }
//      }
//
//
//      // 読み込みサイズが指定サイズと違う場合（終端まで読みきった）
//      if( m_sp_snd_stream->IsEOF() )
//      {
//        int ms_time = static_cast<int>(1000 * read_size / wave_buf_size) - 10;
//        if( ms_time > 0 )
//        {
//          CPL_Sleep( ms_time );
//        }
//        // 待機したあと、読み込み位置を初期へ戻す
//        m_sp_snd_stream->SeekSet( 0 );
//      }
//    }
//  }
//
//  _endthreadex( 0 );
//
//  return 0;
//}


//// _____________________________________________________________________________
//// WAVE用読み込みスレッド
//// _____________________________________________________________________________
//int SoundPlayerEntity_for_Stream::ThreadReadCSC::Call( void* in_arglist )
//{
//  {
//    auto*
//      ptr_sndbuf_stream =
//        reinterpret_cast<Entity_*>(in_arglist);
//    auto
//      m_sp_snd_stream =
//        ptr_sndbuf_stream->GetFileStream();
//
//    const Core::CscFileStream*
//      ptr_csc_stream = dynamic_cast<Core::CscFileStream const*>(&*m_sp_snd_stream);
//
//    if( !ptr_csc_stream )
//    {
//      CPL_OUTPUT( SwS("CSC読み込みスレッドにおいて、CscFileStreamポインタの取得に失敗しました\n") );
//      CPL_BREAK(true);
//      return 0;
//    }
//
//    try {
//#if (CPL_CSC_VERSION == 1)
//      // ヘッダ情報
//      Core::CscHeaderInfo csc_info = ptr_csc_stream->GetHeader();
//      ptr_csc_stream->SeekSet( 0 );
//      ptr_csc_stream->Read( &csc_info, sizeof(csc_info) );
//      // ブロック情報
//      Array::Constant<WIN::CscBlockInfo> BlockTbl( csc_info.block_num );
//      ptr_csc_stream->SeekSet( sizeof(Core::CscHeaderInfo) - sizeof(WIN::CscBlockInfo) );
//      ptr_csc_stream->Read( &BlockTbl[ 0 ], sizeof(WIN::CscBlockInfo) * csc_info.block_num );
//      
//      // ブロック情報を復号化
//      Decryption(
//        &BlockTbl[ 0 ],
//        sizeof(WIN::CscBlockInfo) * csc_info.block_num,
//        ptr_csc_stream->GetMask(),
//        ptr_csc_stream->GetMask().GetLength() );
//#elif (CPL_CSC_VERSION == 2)
//      // ヘッダ
//      Core::CscHeaderInfo2 csc_info = ptr_csc_stream->GetHeader2();
//      ptr_csc_stream->SeekSet( 0 );
//      ptr_csc_stream->Read( &csc_info, sizeof(csc_info) );
//      // ブロック情報
//      Core::Array::Constant<Core::CscBlockInfo2> block_info_table( csc_info.block_num );
//      ptr_csc_stream->SeekSet( sizeof(Core::CscHeaderInfo2) );
//      ptr_csc_stream->Read( &block_info_table[ 0 ], block_info_table.GetSize() );
//      
//      // ブロック情報を復号化
//      Decryption(
//        &block_info_table[ 0 ],
//        block_info_table.GetSize(),
//        ptr_csc_stream->GetMask(),
//        static_cast<int>(ptr_csc_stream->GetMask().GetLength()) );
//#endif
//
//      const int channel_num = csc_info.channel;
//      const int w_byte      = csc_info.bits / 8;
//      const int wait_step = 100;
//      const int data_offset = static_cast<int>(ptr_csc_stream->GetPos());
//      const int csc_buf_size = CSc_CHANNEL_BUF_SIZE * channel_num;
//      Core::Array::Constant<U8> tmp_buf( csc_buf_size * 2 );
//      char flag[ 2 ] = { false, true }; // 読み込み済みフラグ。初期状態ではバッファ全体分は読み込み済み
//
//      int read_sample_num = csc_buf_size / channel_num / w_byte;
//      int read_sample_idx = read_sample_num * 2;
//
//      while( true )
//      {
//        CPL::CPL_Sleep( wait_step );
//        
//        if( IsExit() ) // 強制終了検査
//        {
//          break;
//        }
//
//        size_t  pos = ptr_sndbuf_stream->GetPos();
//        size_t  read_size = 0;
//        bool    f_idx = ((pos / csc_buf_size)!=0); // 本来の演算結果も0or1になるが、警告回避のため論理判定。
//
//        if( !flag[ !f_idx ] )
//        {
//          flag[ !f_idx ] = true;
//          flag[ f_idx ] = false;
//          // データ読み込み
//#if (CPL_CSC_VERSION == 1)
//          read_size =
//            ptr_csc_stream->Decode(
//              &BlockTbl[0],
//              tmp_buf,
//              read_sample_idx,
//              read_sample_num,
//              true,
//              &read_sample_idx );
//#elif (CPL_CSC_VERSION == 2)
//          read_size =
//            ptr_csc_stream->Decode2_Range(
//              &block_info_table[ 0 ],
//              &tmp_buf[ 0 ],
//              read_sample_idx,
//              read_sample_num,
//              true,
//              &read_sample_idx );
//#endif
//
//          //int stm_pos = ptr_csc_stream->GetPos();
//          switch( f_idx )
//          {
//          case 0:
//            ptr_sndbuf_stream->WriteDsBuffer( csc_buf_size, &tmp_buf[0], csc_buf_size ); // 後半部分に書き込み
//            break;
//          case 1:
//            ptr_sndbuf_stream->WriteDsBuffer( 0, &tmp_buf[0], csc_buf_size ); // 前半部分に書き込み
//            break;
//          }
//        }
//
//
//        // 終端に達した場合
//        if( ptr_csc_stream->IsEOF() )
//        {
//          int ms_time =
//            static_cast<int>(1000 * (read_size / channel_num / w_byte) / csc_buf_size)-10;
//          if( ms_time > 0 )
//          {
//            CPL_Sleep( ms_time );
//          }
//          // 待機したあと、読み込み位置を初期へ戻す
//          ptr_csc_stream->SeekSet( data_offset );
//        }
//      }
//    }
//    catch(...)
//    {
//      CPL_OUTPUT( SwS("CSC読み込みスレッドにおいて、CscFileStreamポインタの取得に失敗しました\n") );
//
//    }
//  }
//
//  _endthreadex( 0 );
//
//  return 0;
//}



} // namespace Audio
} // namespace DX
} // namespace CPL
