OSDN Git Service

非同期エージェントライブラリでスレッド部分を書き換えてみた。
authorsfpg <sfpg@users.sourceforge.jp>
Mon, 12 Nov 2012 10:52:10 +0000 (19:52 +0900)
committersfpg <sfpg@users.sourceforge.jp>
Mon, 12 Nov 2012 10:52:10 +0000 (19:52 +0900)
wasapi2/agent_base.cpp [new file with mode: 0644]
wasapi2/agent_base.h [new file with mode: 0644]
wasapi2/input_agent.cpp [new file with mode: 0644]
wasapi2/input_agent.h [new file with mode: 0644]
wasapi2/mixer_agent.cpp [new file with mode: 0644]
wasapi2/mixer_agent.h [new file with mode: 0644]
wasapi2/output_agent.cpp [new file with mode: 0644]
wasapi2/output_agent.h [new file with mode: 0644]
wasapi2/reader_agent.cpp [new file with mode: 0644]
wasapi2/reader_agent.h [new file with mode: 0644]

diff --git a/wasapi2/agent_base.cpp b/wasapi2/agent_base.cpp
new file mode 100644 (file)
index 0000000..7ec0b46
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+==============================================================================
+
+This file is part of the async
+Copyright 2005-10 by Satoshi Fujiwara.
+
+async can be redistributed and/or modified under the terms of the
+GNU General Public License, as published by the Free Software Foundation;
+either version 2 of the License, or (at your option) any later version.
+
+async is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with async; if not, visit www.gnu.org/licenses or write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
+Boston, MA 02111-1307 USA
+
+==============================================================================
+*/
+#include "StdAfx.h"
+#include <commctrl.h>
+
+#if _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
+#endif
+
+#include "message_loop.h"
+#include "sf_com.h"
+#include "dout.h"
+#include "async_reader.h"
+#include "application.h"
+#include "agent_base.h"
+
+using namespace std;
+
+namespace sf {
+
+    void agent_base::init_buffer()
+    {
+      audio_base& out(application::instance()->output_device());
+      ringbuffer_.reset();
+      for(int i = 0,size = buffer_.size();i < size;++i)
+      {
+        buffer_[i].reset(reinterpret_cast<uint8_t*>(_aligned_malloc(sizeof(uint8_t) * out.get_buffer_byte_size(),16)));
+      }
+      index_ = 0;
+    }
+
+}
+
+
diff --git a/wasapi2/agent_base.h b/wasapi2/agent_base.h
new file mode 100644 (file)
index 0000000..d4ff3e8
--- /dev/null
@@ -0,0 +1,120 @@
+#pragma once
+/*
+  ==============================================================================
+
+   This file is part of the async
+   Copyright 2005-10 by Satoshi Fujiwara.
+
+   async can be redistributed and/or modified under the terms of the
+   GNU General Public License, as published by the Free Software Foundation;
+   either version 2 of the License, or (at your option) any later version.
+
+   async is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with async; if not, visit www.gnu.org/licenses or write to the
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
+   Boston, MA 02111-1307 USA
+
+  ==============================================================================
+*/
+#include "singleton.h"
+#include "exception.h"
+#include "ring_buffer.h"
+#include "sf_memory.h"
+namespace sf 
+{
+  struct agent_base : public Concurrency::agent
+  {
+    struct wait_exception
+      : public sf::exception 
+    {
+      wait_exception() : exception(L"wait_error") {}
+    };
+
+    agent_base()  // : event_((::CreateEventEx(NULL, NULL, 0,EVENT_MODIFY_STATE | SYNCHRONIZE))
+    {
+      status_.store(0, std::memory_order_seq_cst);
+    }
+
+    virtual ~agent_base(){};
+
+    //void execute()
+    //{
+    //  //g.run(std::bind(&agent_base::thread_main,this));
+    //  thread_ = std::thread(boost::bind(&agent_base::thread_main,this));
+    //}
+
+
+    //void join ()
+    //{
+    //  if(thread_.joinable())
+    //  {
+    //    thread_.join();
+    //  }
+    //}
+
+    // \8fó\91Ô\82Ì\95Ï\8dX
+    void change_status(int value,std::memory_order o = std::memory_order_seq_cst)
+    {
+      event_.reset();
+      status_.store(value,o);
+      event_.set();
+      DOUT(L"change_status()" << std::endl);
+    }
+
+    void wait_event()
+    {
+      event_.wait();
+    }
+
+    void change_and_wait(int value,int wait_value,std::memory_order o = std::memory_order_seq_cst)
+    {
+      change_status(value,o);
+      //PulseEvent(event_.get());
+      wait_status(wait_value);
+    }
+
+    int status(std::memory_order o = std::memory_order_seq_cst)
+    {
+      return status_.load(o);
+    };
+
+    virtual void init_buffer();
+
+    void wait_status(int value,int ms = 1,std::memory_order o = std::memory_order_seq_cst)
+    {
+      DOUT(L"wait_status()" << std::endl);
+      int s;
+      while(s = status_.load(o),s != value)
+      {
+        if(s < STATUS_ERROR)
+        {
+          throw wait_exception();
+        };
+        Sleep(ms);
+      }
+    };
+
+    ringbuffer_t& ringbuffer() {return ringbuffer_;}
+
+    static const int STATUS_ERROR = -1;
+    static const size_t Q_SIZE = 8;
+    static const int WAIT_TIMEOUT_DEFAULT = 100; 
+
+  protected:
+    virtual void run() = 0;
+
+    //std::thread thread_;
+    std::atomic<int> status_;
+    buffer_t buffer_;
+    Concurrency::event event_;
+    //handle_holder event_;
+    uint32_t index_;
+    ringbuffer_t  ringbuffer_;
+    std::wstring error_;
+  };
+}
diff --git a/wasapi2/input_agent.cpp b/wasapi2/input_agent.cpp
new file mode 100644 (file)
index 0000000..f8d06f6
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+==============================================================================
+
+This file is part of the async
+Copyright 2005-10 by Satoshi Fujiwara.
+
+async can be redistributed and/or modified under the terms of the
+GNU General Public License, as published by the Free Software Foundation;
+either version 2 of the License, or (at your option) any later version.
+
+async is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with async; if not, visit www.gnu.org/licenses or write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
+Boston, MA 02111-1307 USA
+
+==============================================================================
+*/
+#include "StdAfx.h"
+#include <commctrl.h>
+
+#if _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
+#endif
+
+#include "message_loop.h"
+#include "sf_com.h"
+#include "application.h"
+#include "input_agent.h"
+#include "dout.h"
+#include "async_reader.h"
+
+using namespace std;
+
+namespace sf {
+
+  void input_agent_t::run()
+  {
+    // COMの初期化
+    sf::com_initialize init(0,multi_threaded);
+
+    // MMCSSの初期化
+    sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));
+    avmm.set_priority(AVRT_PRIORITY_HIGH);
+
+    //// input デバイスの初期化
+    //wasapi_device_manager::ptr m(wasapi_device_manager::instance());
+    //apply_config_(
+    // m->current_input_device_index(),
+    // m->current_input_device().params
+    //);
+    change_status(status_pause);
+    application& app(*application::instance());
+    int status = STATUS_ERROR;
+    BYTE *buffer = 0;
+    index_ = 0;
+    int source_counter ,dest_counter;
+    source_counter  = dest_counter = 0;
+    //// 出力デバイスが稼働するまで待つ
+    //app.output_thread().wait_status(output_agent_t::status_processing,10);
+    //apply_config_(
+    //wasapi_device_manager::instance()->current_input_device_index(),
+    //wasapi_device_manager::instance()->current_input_device().params);
+    change_status(status_device_config);
+    while(status = status_.load(),status != status_exit)
+    {
+      // イベントを待つ
+      switch(status)
+      {
+      case status_device_config:
+        if(wasapi_input_)
+        {
+          wasapi_input_->stop();
+          dest_counter = 0;
+        }
+        change_status(status_device_config_ok);
+        break;
+      case status_process:
+        if(!wasapi_input_->is_start()){
+          wasapi_input_->start();
+        }
+        change_status(status_processing);
+      case status_processing:
+        {
+          wasapi_input_->wait();// 入力待ち
+          //try{
+          //  get_buffer g(*wasapi_input_);// キャプチャバッファの取得
+          //  if(g.size() && g != 0)
+          //  {
+          //    source_counter = 0;
+          //    while(source_counter != g.size())
+          //    {
+          //      BYTE * src = g + source_counter * wasapi_input_->get_frame_size();
+          //      int size_byte_src = g.size_byte() - source_counter * wasapi_input_->get_frame_size();
+          //      int size_src = g.size() - source_counter;
+
+          //      BYTE * dest = buffer_[index_].get() + dest_counter * app.output_device().get_frame_size();
+          //      int size_byte_dest = app.output_device().get_buffer_byte_size() - dest_counter * app.output_device().get_frame_size();
+          //      int size_dest = app.output_device().get_buffer_size() - dest_counter;
+
+          //      if(size_src <= size_dest)
+          //      {
+          //        ::CopyMemory(dest,src,size_byte_src);
+          //        source_counter += size_src;
+          //        dest_counter += size_src;
+          //      } else if(size_src > size_dest)
+          //      {
+          //        ::CopyMemory(dest,src,size_byte_dest);
+          //        source_counter += size_dest;
+          //        dest_counter += size_dest;
+          //      }
+          //      if(dest_counter == app.output_device().get_buffer_size())
+          //      {
+          //        if(ringbuffer_.enqueue(buffer_[index_].get()))
+          //        {
+          //          index_ = (index_ + 1) & (buffer_.size() - 1);
+          //        }
+          //        dest_counter = 0;
+          //      }
+          //    }
+          //  }
+          //} catch (...) {
+          //  ;
+          //}
+        }
+
+        break;
+      case status_pause:
+        if(wasapi_input_)
+        {
+          wasapi_input_->stop();
+        }
+        change_status(status_pause_ok);
+        break;
+      default:
+        wait_event();
+//        WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT);
+        break;
+      }
+    }
+loop_end:
+    ;
+    DOUT(L"##### input_threadは終了!" << endl);
+    if(wasapi_input_ && wasapi_input_->is_start())
+    {
+      wasapi_input_->stop();
+    }
+    wasapi_input_.reset();
+
+    agent::done();
+  };
+
+  void input_agent_t::apply_config(int device_index,wasapi_device_manager::device_info::params_t& params)
+  {
+    if(status() != status_device_config_ok){
+      change_and_wait(status_device_config,status_device_config_ok);
+    }
+    apply_config_(device_index,params);
+    init_buffer();
+    change_and_wait(status_process,status_processing);
+  }
+
+  void input_agent_t::apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params)
+  {
+
+    WAVEFORMATEXTENSIBLE form;
+    if(wasapi_input_)
+    {
+      if(wasapi_input_->is_start())
+      {
+        wasapi_input_->stop();
+      }
+      wasapi_input_.reset();
+    };
+
+    //bits_pair bits = {params.bits,params.valid_bits};
+    //make_wave_format(form,params.sample_rate,params.channel,bits);
+
+    try {
+      if(params.exclusive_mode)
+      {
+        if(params.event_mode){
+          wasapi_input_.reset(new sf::wasapi_capture_exclusive_event(device_index,params));
+        } else {
+          wasapi_input_.reset(new sf::wasapi_capture_exclusive_timer(device_index,params));
+        };
+      } else {
+        if(params.event_mode)
+        {
+          wasapi_input_.reset(new sf::wasapi_capture_shared_event(device_index,params));
+        } else {
+          wasapi_input_.reset(new sf::wasapi_capture_shared_timer(device_index,params));
+        }
+      }
+    } catch (win32_error_exception& e)
+    {
+
+      //window_->message_box((boost::wformat(L"WASAPI初期化エラーが発生しました。設定パラメータを見なおしてください。%s") % e.error()).str(),wstring(L"WASAPI初期化エラー"));
+      throw;
+    }
+
+    wasapi_device_manager::instance()->select_input_device(device_index);
+    wasapi_device_manager::instance()->current_input_device().params = params;
+
+  }
+
+  //void input_agent_t::init_buffer()
+  //{
+  //  audio_base& in(application::instance()->input_device());
+  //  for(int i = 0,size = buffer_.size();i < size;++i)
+  //  {
+  //    buffer_[i].reset(reinterpret_cast<uint8_t*>(_aligned_malloc(sizeof(uint8_t) * in.get_buffer_byte_size(),16)));
+  //  }
+  //}
+
+
+}
+
diff --git a/wasapi2/input_agent.h b/wasapi2/input_agent.h
new file mode 100644 (file)
index 0000000..bac16fd
--- /dev/null
@@ -0,0 +1,60 @@
+#pragma once
+/*
+  ==============================================================================
+
+   This file is part of the async
+   Copyright 2005-10 by Satoshi Fujiwara.
+
+   async can be redistributed and/or modified under the terms of the
+   GNU General Public License, as published by the Free Software Foundation;
+   either version 2 of the License, or (at your option) any later version.
+
+   async is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with async; if not, visit www.gnu.org/licenses or write to the
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
+   Boston, MA 02111-1307 USA
+
+  ==============================================================================
+*/
+#include "agent_base.h"
+
+namespace sf {
+struct input_agent_t : public agent_base
+{
+  input_agent_t(){};
+  ~input_agent_t(){};
+// -----------------------------  
+// WASAPI入力関係
+// -----------------------------  
+  enum input_status
+  {
+    status_device_config,
+    status_device_config_ok,
+    status_wait_output_active,
+    status_wait_output_active_ok,
+    status_process,
+    status_processing,
+    status_pause,
+    status_pause_ok,
+    status_exit,
+    status_error = STATUS_ERROR
+  };
+
+  void apply_config(int device_index,wasapi_device_manager::device_info::params_t& params);
+  //void init_buffer();
+
+  audio_base& device() {return *wasapi_input_.get();}
+protected:
+  void run();
+private:
+  // 入力デバイスの設定・変更
+  void apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params);
+  std::unique_ptr<audio_base> wasapi_input_;
+};
+}
+
diff --git a/wasapi2/mixer_agent.cpp b/wasapi2/mixer_agent.cpp
new file mode 100644 (file)
index 0000000..16b2e9a
--- /dev/null
@@ -0,0 +1,124 @@
+/*\r
+==============================================================================\r
+\r
+This file is part of the async\r
+Copyright 2005-10 by Satoshi Fujiwara.\r
+\r
+async can be redistributed and/or modified under the terms of the\r
+GNU General Public License, as published by the Free Software Foundation;\r
+either version 2 of the License, or (at your option) any later version.\r
+\r
+async is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with async; if not, visit www.gnu.org/licenses or write to the\r
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, \r
+Boston, MA 02111-1307 USA\r
+\r
+==============================================================================\r
+*/\r
+#include "StdAfx.h"\r
+#include <commctrl.h>\r
+\r
+#if _DEBUG\r
+#define _CRTDBG_MAP_ALLOC\r
+#include <crtdbg.h>\r
+#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)\r
+#endif\r
+\r
+#include "message_loop.h"\r
+#include "sf_com.h"\r
+#include "application.h"\r
+#include "mixer_agent.h"\r
+#include "dout.h"\r
+#include "async_reader.h"\r
+\r
+using namespace std;\r
+\r
+namespace sf {\r
+\r
+\r
+void mixer_agent_t::run()\r
+{\r
+  // TODO:ミキサーの実装\r
+  // COMの初期化\r
+  sf::com_initialize init(0,multi_threaded);\r
+\r
+  // MMCSSの初期化\r
+  //av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));\r
+  //avmm.set_priority(AVRT_PRIORITY::AVRT_PRIORITY_HIGH);\r
+  int status;\r
+  application& app(*application::instance());\r
+\r
+  // 出力デバイスが稼働するまで待つ\r
+  //app.output_thread().wait_status(output_agent_t::status_processing,10);\r
+  // バッファ初期化\r
+  //init_buffer();\r
+  change_status(status_config);\r
+  while(status = status_.load(),status !=status_exit)\r
+  {\r
+  switch(status)\r
+  {\r
+  case status_config:\r
+    {\r
+      change_status(status_config_ok);\r
+    }\r
+    break;\r
+  case status_process:\r
+    {\r
+      init_buffer();\r
+      change_status(status_processing);\r
+    }\r
+  case status_processing:\r
+    {\r
+      Sleep(app.output_device().get_buffer_duration() / 20000);\r
+      BYTE *in(0),*reader(0);\r
+      app.input_ringbuffer().dequeue(in);\r
+      app.reader_ringbuffer().dequeue(reader);\r
+      int size(app.output_device().get_buffer_byte_size());\r
+      BYTE *dest(buffer_[index_].get());\r
+      if(in != 0 && reader != 0)\r
+      {\r
+        ::CopyMemory(dest,in,size);\r
+        size = size / app.output_device().get_frame_size();\r
+        WORD *destw((WORD*)dest),*srcw((WORD*)reader);\r
+        for(int i = 0;i < size;++i)\r
+        {\r
+          *destw++ += *srcw++;\r
+          *destw++ += *srcw++;\r
+        }\r
+      } else if(in != 0)\r
+      {\r
+        ::CopyMemory(dest,in,size);\r
+      } else if(reader != 0)\r
+      {\r
+        ::CopyMemory(dest,reader,size);\r
+      } else {\r
+        ::ZeroMemory(dest,size);\r
+      }\r
+      \r
+      while(!ringbuffer_.enqueue(buffer_[index_].get()))\r
+      {\r
+        Sleep(app.output_device().get_buffer_duration() / 20000);\r
+      }\r
+\r
+      index_ = (index_ + 1) & (buffer_.size() -1 );\r
+\r
+    }\r
+    break;\r
+  case status_pause:\r
+    change_status(status_pause_ok);\r
+    break;\r
+  default:\r
+        wait_event();\r
+//        WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT);\r
+  }\r
+  }\r
+    DOUT(L"***** mixerは終了!" << std::endl);\r
+  agent::done();\r
+}\r
+}\r
+\r
diff --git a/wasapi2/mixer_agent.h b/wasapi2/mixer_agent.h
new file mode 100644 (file)
index 0000000..7aaeec6
--- /dev/null
@@ -0,0 +1,47 @@
+#pragma once
+/*
+  ==============================================================================
+
+   This file is part of the async
+   Copyright 2005-10 by Satoshi Fujiwara.
+
+   async can be redistributed and/or modified under the terms of the
+   GNU General Public License, as published by the Free Software Foundation;
+   either version 2 of the License, or (at your option) any later version.
+
+   async is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with async; if not, visit www.gnu.org/licenses or write to the
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
+   Boston, MA 02111-1307 USA
+
+  ==============================================================================
+*/
+#include "agent_base.h"
+
+namespace sf {
+struct mixer_agent_t : public agent_base
+{
+  mixer_agent_t(){};
+  ~mixer_agent_t(){};
+  enum mixer_status
+  {
+    status_config,
+    status_config_ok,
+    status_process,
+    status_processing,
+    status_pause,
+    status_pause_ok,
+    status_exit,
+    status_error = STATUS_ERROR
+  };
+protected:
+  void run();
+private:
+};
+}
+
diff --git a/wasapi2/output_agent.cpp b/wasapi2/output_agent.cpp
new file mode 100644 (file)
index 0000000..1d76849
--- /dev/null
@@ -0,0 +1,301 @@
+/*\r
+==============================================================================\r
+\r
+This file is part of the async\r
+Copyright 2005-10 by Satoshi Fujiwara.\r
+\r
+async can be redistributed and/or modified under the terms of the\r
+GNU General Public License, as published by the Free Software Foundation;\r
+either version 2 of the License, or (at your option) any later version.\r
+\r
+async is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with async; if not, visit www.gnu.org/licenses or write to the\r
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, \r
+Boston, MA 02111-1307 USA\r
+\r
+==============================================================================\r
+*/\r
+#include "StdAfx.h"\r
+#include <commctrl.h>\r
+\r
+#if _DEBUG\r
+#define _CRTDBG_MAP_ALLOC\r
+#include <crtdbg.h>\r
+#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)\r
+#endif\r
+\r
+#include "message_loop.h"\r
+#include "sf_com.h"\r
+#include "application.h"\r
+#include "dout.h"\r
+#include "async_reader.h"\r
+#include "output_agent.h"\r
+\r
+\r
+using namespace std;\r
+using namespace boost;\r
+\r
+namespace sf {\r
+\r
+  /// WASAPI出力スレッド\r
+  void output_agent_t::run()\r
+  {\r
+    // COMの初期化\r
+    sf::com_initialize init(0,multi_threaded);\r
+\r
+    // MMCSSの初期化\r
+    sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));\r
+    avmm.set_priority(AVRT_PRIORITY_HIGH);\r
+    //apply_config_(\r
+    //  wasapi_device_manager::instance()->current_output_device_index(),\r
+    //  wasapi_device_manager::instance()->current_output_device().params);\r
+    BYTE* reader_buffer,*input_buffer,*mix_buffer;\r
+    uint32_t status;\r
+    size_t size_of_buffer = 0;\r
+    size_t remaining_of_buffer =  0;\r
+    BYTE* wasapi_buffer = 0;\r
+    size_t remaining_of_wasapi_buffer = 0;\r
+    memory_block_t mix_work;\r
+\r
+    bool wasapi_ready = false;\r
+\r
+    //if(wasapi_output_->is_enabled())\r
+    //{\r
+    //  change_status(status_processing);\r
+    //} else {\r
+      change_status(status_device_config);\r
+    //}\r
+\r
+    application& app(*application::instance());\r
+\r
+\r
+    while(status = status_.load(std::memory_order_acquire), (status != status_exit ))\r
+    { \r
+      try {\r
+        switch (status)\r
+        {\r
+        case status_device_config:\r
+          // 出力デバイスの変更\r
+          if(wasapi_output_ && wasapi_output_->is_start())\r
+          {\r
+            wasapi_output_->stop();\r
+          }\r
+          remaining_of_buffer = 0;\r
+          change_status(status_device_config_ok);\r
+          break;\r
+        case status_process:\r
+          mix_work.reset(reinterpret_cast<BYTE*>(_aligned_malloc(sizeof(uint8_t) * wasapi_output_->get_buffer_byte_size(),16))); \r
+          change_status(status_processing);\r
+          // fall through\r
+        case status_processing:\r
+          {\r
+            size_of_buffer = wasapi_output_->get_buffer_size();\r
+            assert(wasapi_output_->is_enabled());\r
+            // 処理されたバイト数\r
+            if(remaining_of_buffer == 0) // データ残り0なら\r
+            {\r
+              //リングバッファから新たにデータを読み込む\r
+              //if(!app.mixer_ringbuffer().dequeue(reader_buffer)) // 読み込めない場合\r
+              int size = wasapi_output_->get_buffer_byte_size();\r
+              if(!app.reader_ringbuffer().dequeue(reader_buffer)) reader_buffer = 0;\r
+              if(!app.input_ringbuffer().dequeue(input_buffer)) input_buffer = 0;\r
+              if(input_buffer != 0 && reader_buffer != 0)\r
+              {\r
+                ::CopyMemory(mix_work.get(),input_buffer,size);\r
+                size = size / app.output_device().get_frame_size();\r
+                WORD *destw((WORD*)mix_work.get()),*srcw((WORD*)reader_buffer);\r
+                for(int i = 0;i < size;++i)\r
+                {\r
+                  *destw++ += *srcw++;\r
+                  *destw++ += *srcw++;\r
+                }\r
+              } else if(input_buffer != 0)\r
+              {\r
+                ::CopyMemory(mix_work.get(),input_buffer,size);\r
+              } else if(reader_buffer != 0)\r
+              {\r
+                ::CopyMemory(mix_work.get(),reader_buffer,size);\r
+              } else {\r
+                get_buffer g(*wasapi_output_.get(),size_of_buffer);\r
+                               if(g.size() != 0){\r
+                                       ::ZeroMemory(g.get(),g.size_byte());\r
+                               }\r
+                goto copy_end;\r
+              }\r
+              mix_buffer = mix_work.get();\r
+              remaining_of_buffer = size_of_buffer;\r
+            }\r
+\r
+            // WASAPIからバッファアドレスを取得する\r
+            { get_buffer g(*wasapi_output_.get(),size_of_buffer);\r
+            wasapi_buffer = g;\r
+            remaining_of_wasapi_buffer = g.size();// バッファのサイズ必ずしも\r
+            // 要求したバイトが取得できるとはかぎらない\r
+\r
+            if(remaining_of_buffer == remaining_of_wasapi_buffer)\r
+            {\r
+              // バッファの残りとWASAPIバッファの残りが同じとき\r
+              const uint32_t size_copy(remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
+              ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
+              remaining_of_buffer = 0;\r
+              remaining_of_wasapi_buffer = 0; \r
+            } else if(remaining_of_buffer > remaining_of_wasapi_buffer)\r
+            {\r
+              // バッファの残り>WASAPIバッファの残り\r
+              const uint32_t size_copy(remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
+              ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
+              mix_buffer += size_copy;\r
+              remaining_of_buffer -= remaining_of_wasapi_buffer;\r
+              remaining_of_wasapi_buffer = 0;\r
+            } else if(remaining_of_buffer < remaining_of_wasapi_buffer)\r
+            {\r
+              // バッファの残り<WASAPIバッファの残り\r
+              const uint32_t size_copy(remaining_of_buffer * wasapi_output_->get_frame_size());\r
+              ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
+              wasapi_buffer +=  size_copy;\r
+              remaining_of_wasapi_buffer -= remaining_of_buffer;\r
+\r
+              int size = wasapi_output_->get_buffer_byte_size();\r
+              if(!app.reader_ringbuffer().dequeue(reader_buffer)) reader_buffer = 0;\r
+              if(!app.output_ringbuffer().dequeue(input_buffer)) input_buffer = 0;\r
+\r
+              if(input_buffer != 0 && reader_buffer != 0)\r
+              {\r
+                ::CopyMemory(mix_work.get(),input_buffer,size_of_buffer);\r
+                size = size_of_buffer / app.output_device().get_frame_size();\r
+                WORD *destw((WORD*)mix_work.get()),*srcw((WORD*)reader_buffer);\r
+                for(int i = 0;i < size;++i)\r
+                {\r
+                  *destw++ += *srcw++;\r
+                  *destw++ += *srcw++;\r
+                }\r
+              } else if(input_buffer != 0)\r
+              {\r
+                ::CopyMemory(mix_work.get(),input_buffer,size);\r
+              } else if(reader_buffer != 0)\r
+              {\r
+                ::CopyMemory(mix_work.get(),reader_buffer,size);\r
+              } else {\r
+                memset(wasapi_buffer,0,remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
+                continue;\r
+              }\r
+              mix_buffer = mix_work.get();\r
+              {\r
+                const uint32_t size_copy(remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
+                ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
+                mix_buffer += size_copy;\r
+                remaining_of_buffer = size_of_buffer - remaining_of_wasapi_buffer;\r
+              }\r
+            }\r
+            }\r
+copy_end:\r
+            if(!wasapi_output_->is_start())\r
+            {\r
+              wasapi_output_->start();\r
+            }\r
+\r
+            if(wasapi_output_->get_current_padding() == size_of_buffer)\r
+            {\r
+              wasapi_output_->wait();\r
+            } else {\r
+              DOUT(L"XXXX No Wait !!!! XXXX" << std::endl);\r
+            }\r
+          }\r
+          break;\r
+        default:\r
+        wait_event();\r
+//        WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT);\r
+          break;\r
+        }\r
+      } catch (win32_error_exception& e) {\r
+        error_ = (wformat(L"出力スレッドでエラーが発生しました。:%s %x") % e.error() % e.hresult()).str();\r
+        change_status(status_error);\r
+      } catch (...) {\r
+        error_ = L"出力スレッドで不明なエラーが発生しました。";\r
+        change_status(status_error);\r
+      }\r
+    }\r
+loop_end:\r
+    if(wasapi_output_){\r
+      if(wasapi_output_->is_start())\r
+      {\r
+        wasapi_output_->stop();\r
+      }\r
+      wasapi_output_.reset();\r
+    }\r
+    DOUT(L"***** output_threadは終了!" << std::endl);\r
+    agent::done();\r
+  };\r
+\r
+  void output_agent_t::apply_config(int device_index,wasapi_device_manager::device_info::params_t& params)\r
+  {\r
+    if(status() != status_device_config_ok){ \r
+      change_and_wait(status_device_config,status_device_config_ok);\r
+    }\r
+\r
+    apply_config_(device_index,params);\r
+\r
+    change_and_wait(status_process,status_processing);\r
+\r
+    //if(reader_ && status_.load() == reader_ready){\r
+    //  reader_->reset_data_position();\r
+    //  reader_index_ = 0;\r
+    //}\r
+  }\r
+\r
+  void output_agent_t::apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params)\r
+  {\r
+\r
+    //  assert(status_.load() == reader_stop);\r
+\r
+    // 出力スレッドを設定変更状態にする\r
+\r
+    WAVEFORMATEXTENSIBLE form;\r
+\r
+    if(wasapi_output_)\r
+    {\r
+      if(wasapi_output_->is_start())\r
+      {\r
+        wasapi_output_->stop();\r
+      }\r
+      wasapi_output_.reset();\r
+    };\r
+\r
+    try {\r
+      if(params.exclusive_mode)\r
+      {\r
+        if(params.event_mode){\r
+          wasapi_output_.reset(new sf::wasapi_exclusive_event(device_index,params));\r
+        } else {\r
+          wasapi_output_.reset(new sf::wasapi_exclusive_timer(device_index,params));\r
+        };\r
+      } else {\r
+        if(params.event_mode)\r
+        {\r
+          wasapi_output_.reset(new sf::wasapi_shared_event(device_index,params));\r
+        } else {\r
+          wasapi_output_.reset(new sf::wasapi_shared_timer(device_index,params));\r
+        }\r
+      }\r
+    } catch (win32_error_exception& e)\r
+    {\r
+\r
+      //window_->message_box((boost::wformat(L"WASAPI初期化エラーが発生しました。設定パラメータを見なおしてください。%s") % e.error()).str(),wstring(L"WASAPI初期化エラー"));\r
+      throw;\r
+    }\r
+\r
+    wasapi_device_manager::instance()->select_output_device(device_index);\r
+    wasapi_device_manager::instance()->current_output_device().params = params;\r
+\r
+    // バッファのアロケート\r
+    init_buffer();\r
+\r
+\r
+  }\r
+}\r
+\r
diff --git a/wasapi2/output_agent.h b/wasapi2/output_agent.h
new file mode 100644 (file)
index 0000000..4150235
--- /dev/null
@@ -0,0 +1,69 @@
+#pragma once\r
+/*\r
+  ==============================================================================\r
+\r
+   This file is part of the async\r
+   Copyright 2005-10 by Satoshi Fujiwara.\r
+\r
+   async can be redistributed and/or modified under the terms of the\r
+   GNU General Public License, as published by the Free Software Foundation;\r
+   either version 2 of the License, or (at your option) any later version.\r
+\r
+   async is distributed in the hope that it will be useful,\r
+   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+   GNU General Public License for more details.\r
+\r
+   You should have received a copy of the GNU General Public License\r
+   along with async; if not, visit www.gnu.org/licenses or write to the\r
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, \r
+   Boston, MA 02111-1307 USA\r
+\r
+  ==============================================================================\r
+*/\r
+#include "singleton.h"\r
+#include "exception.h"\r
+#include "ring_buffer.h"\r
+#include "wasapi.h"\r
+#include "agent_base.h"\r
+\r
+namespace sf {\r
+struct output_agent_t : public agent_base\r
+{\r
+public:\r
+  struct exception\r
+    : public sf::win32_error_exception \r
+  {\r
+    exception(uint32_t hr) : win32_error_exception(hr) {};\r
+    exception() : win32_error_exception() {} ;\r
+  };\r
+\r
+  output_agent_t() {};\r
+  ~output_agent_t(){};\r
+\r
+\r
+// ----------------------------\r
+// WASAPI出力関係\r
+// ----------------------------\r
+// 出力デバイスの設定・変更\r
+  enum output_status\r
+  {\r
+    status_device_config,\r
+    status_device_config_ok,\r
+    status_process,\r
+    status_processing,\r
+    status_pause,\r
+    status_exit,\r
+    status_error = STATUS_ERROR\r
+  };\r
+  void apply_config(int device_index,wasapi_device_manager::device_info::params_t& params);\r
+  audio_base& device() {return *wasapi_output_.get();}\r
+protected:\r
+  void run();\r
+private:\r
+  void apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params);\r
+\r
+  std::unique_ptr<audio_base> wasapi_output_;\r
+};\r
+}\r
+\r
diff --git a/wasapi2/reader_agent.cpp b/wasapi2/reader_agent.cpp
new file mode 100644 (file)
index 0000000..5983538
--- /dev/null
@@ -0,0 +1,216 @@
+/*\r
+==============================================================================\r
+\r
+This file is part of the async\r
+Copyright 2005-10 by Satoshi Fujiwara.\r
+\r
+async can be redistributed and/or modified under the terms of the\r
+GNU General Public License, as published by the Free Software Foundation;\r
+either version 2 of the License, or (at your option) any later version.\r
+\r
+async is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with async; if not, visit www.gnu.org/licenses or write to the\r
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, \r
+Boston, MA 02111-1307 USA\r
+\r
+==============================================================================\r
+*/\r
+#include "StdAfx.h"\r
+#include <commctrl.h>\r
+\r
+#if _DEBUG\r
+#define _CRTDBG_MAP_ALLOC\r
+#include <crtdbg.h>\r
+#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)\r
+#endif\r
+\r
+#include "message_loop.h"\r
+#include "sf_com.h"\r
+#include "dout.h"\r
+#include "async_reader.h"\r
+#include "application.h"\r
+#include "reader_agent.h"\r
+\r
+using namespace std;\r
+\r
+namespace sf {\r
+\r
+  void reader_agent_t::run()\r
+  {\r
+    // COMの初期化\r
+    sf::com_initialize init(0,multi_threaded);\r
+    application& app(*application::instance().get());\r
+    while(true)\r
+    {\r
+      switch(status_.load(std::memory_order_acquire))\r
+      {\r
+      case status_config:\r
+        change_status(status_config_ok);\r
+        break;\r
+      case status_ready:\r
+        DOUT(L"@@@@ reader_agent_t:ready @@@@  " << std::endl);\r
+        change_status(status_ready_ok);\r
+        break;\r
+      case status_exit:\r
+        DOUT(L"@@@@ reader_agent_t:exit @@@@  " << std::endl);\r
+        goto loop_end;\r
+        break;\r
+      case status_play:\r
+        {\r
+//          init_buffer();\r
+          change_status(status_play_ok);\r
+        }\r
+      case status_play_ok:\r
+        {\r
+          DOUT(L"@@@@ reader_agent_t:read_file @@@@  " << std::endl);\r
+          audio_base& out(app.output_device());\r
+          while(status_.load(std::memory_order_acquire) == status_play_ok)\r
+          {\r
+            if(reader_->more_data_available() || not_enqueue_)\r
+            {\r
+              if(!not_enqueue_){              \r
+                uint32_t size = reader_->data_bytes_remaining() >  out.get_buffer_byte_size()\r
+                  ?  out.get_buffer_byte_size() : reader_->data_bytes_remaining();\r
+                if(size == 0 && repeat_mode_)\r
+                {\r
+                  reader_->reset_data_position();\r
+                  size = (reader_->data_bytes_remaining() >  out.get_buffer_byte_size())\r
+                    ?  out.get_buffer_byte_size() : reader_->data_bytes_remaining();\r
+                }\r
+\r
+                reader_->read_data(buffer_[index_].get(),sizeof(uint8_t) * size);\r
+                //reader_->\r
+\r
+                // ここに変換処理を入れる\r
+                position_ += size;\r
+                if(position_ > reader_->total_data_bytes() && repeat_mode_)\r
+                {\r
+                  position_ -= reader_->total_data_bytes();\r
+                };\r
+\r
+                reader_->wait();\r
+                if(size < out.get_buffer_byte_size())\r
+                {\r
+                  memset(buffer_[index_].get() + size,0,out.get_buffer_byte_size() - size);\r
+                }\r
+              }\r
+\r
+              not_enqueue_ = false;\r
+\r
+              while(!ringbuffer_.enqueue(buffer_[index_].get()))\r
+              {\r
+                //wdout << L"++++ queue max ++++ : " << index_ << std::endl;\r
+                if(status_.load() != status_play_ok)\r
+                {\r
+                  if(status_.load(std::memory_order_relaxed) == status_pause_ok)\r
+                  {\r
+                    not_enqueue_ = true;\r
+                  }\r
+                  break;\r
+                } else {\r
+                  Sleep(1);\r
+                }\r
+              }\r
+\r
+              ;\r
+              //#ifdef _DEBUG\r
+              //            wdout << boost::wformat(L"index:%d address:%x 差分:%x") \r
+              //            % index_ % buffer_[index_].get()\r
+              //            % (buffer_[(index_ + 1) & (buffer_.size() - 1)].get() - buffer_[index_].get())\r
+              //            << std::endl; \r
+              //#endif\r
+              if(!not_enqueue_){\r
+                index_ = (++index_) & (buffer_.size() - 1);\r
+              }\r
+\r
+            } else {\r
+              status_.store(status_end);\r
+              break;\r
+            }\r
+          }\r
+        }\r
+        break;\r
+      case status_pause:\r
+        DOUT(boost::wformat(L"**pause** index:%d address:%x") % index_ % buffer_[index_].get() << std::endl);\r
+        change_status(status_pause_ok);\r
+        break;\r
+      case status_end:\r
+        app.reader_end();\r
+        reader_->reset_data_position();\r
+        ringbuffer_.reset();\r
+        position_ = 0;\r
+        change_status(status_end_ok);\r
+        break;\r
+      case status_seek:\r
+        reader_->seek(position_);\r
+        ringbuffer_.reset();\r
+        index_ = 0;\r
+        change_status(status_seek_ok);\r
+        break;\r
+      case status_stop:\r
+        DOUT(L"reader_agent_t **stop**" << std::endl);\r
+        reader_->reset_data_position();\r
+        ringbuffer_.reset();\r
+        position_ = 0;\r
+        change_status(status_stop_ok);\r
+        break;\r
+      default:\r
+        wait_event();\r
+//        WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT);\r
+        break;\r
+      }\r
+    }\r
+loop_end:\r
+    ;\r
+    DOUT(L"##### reader_agent_tは終了!" << std::endl);\r
+    agent::done();\r
+  }\r
+\r
+  void reader_agent_t::setup(const std::wstring& file_path)\r
+  {\r
+    change_and_wait(status_config,status_config_ok);\r
+    source_file_path_ = file_path;\r
+    reader_.reset(new async_reader(file_path,repeat_mode_));\r
+    init_buffer();\r
+    position_ = 0;\r
+    change_and_wait(status_ready,status_ready_ok);\r
+  };\r
+\r
+  void reader_agent_t::position(uint64_t pos)\r
+  {\r
+    uint64_t  div = reader_->get_wave_format().Format.nChannels * reader_->get_wave_format().Format.wBitsPerSample / 8;\r
+    position_ = (pos / div) * div;\r
+    status_backup_ = status_.load();\r
+\r
+    change_and_wait(status_seek,status_seek_ok);\r
+    change_and_wait(status_backup_ - 1,status_backup_);\r
+  }\r
+\r
+  void reader_agent_t::pause()\r
+  {\r
+    if(status_.load() == status_pause_ok)\r
+    {\r
+      read_file();\r
+    } else {\r
+      change_and_wait(status_pause,status_pause_ok);\r
+    }\r
+  }\r
+\r
+  void reader_agent_t::read_file()\r
+  {\r
+    change_and_wait(status_play,status_play_ok);\r
+  }\r
+\r
+  void reader_agent_t::stop()\r
+  {\r
+    change_and_wait(status_stop,status_stop_ok);\r
+  }\r
+\r
+}\r
+\r
+\r
diff --git a/wasapi2/reader_agent.h b/wasapi2/reader_agent.h
new file mode 100644 (file)
index 0000000..b36e1b3
--- /dev/null
@@ -0,0 +1,91 @@
+#pragma once\r
+/*\r
+  ==============================================================================\r
+\r
+   This file is part of the async\r
+   Copyright 2005-10 by Satoshi Fujiwara.\r
+\r
+   async can be redistributed and/or modified under the terms of the\r
+   GNU General Public License, as published by the Free Software Foundation;\r
+   either version 2 of the License, or (at your option) any later version.\r
+\r
+   async is distributed in the hope that it will be useful,\r
+   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+   GNU General Public License for more details.\r
+\r
+   You should have received a copy of the GNU General Public License\r
+   along with async; if not, visit www.gnu.org/licenses or write to the\r
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, \r
+   Boston, MA 02111-1307 USA\r
+\r
+  ==============================================================================\r
+*/\r
+#include "agent_base.h"\r
+\r
+namespace sf {\r
+struct reader_agent_t : public agent_base\r
+{\r
+public:\r
+  struct exception\r
+    : public sf::win32_error_exception \r
+  {\r
+    exception(uint32_t hr) : win32_error_exception(hr) {};\r
+    exception() : win32_error_exception() {} ;\r
+  };\r
+\r
+  reader_agent_t() : repeat_mode_(false) {};\r
+  ~reader_agent_t(){};\r
+\r
+\r
+//  void init_buffer(buffer_t& buffer);\r
+  \r
+//---------------------------------------\r
+// ファイル読取り関係\r
+//---------------------------------------\r
+public:\r
+  enum reader_status\r
+  {\r
+    status_config,\r
+    status_config_ok,\r
+    status_ready,\r
+    status_ready_ok,\r
+    status_stop,\r
+    status_stop_ok,\r
+    status_play,\r
+    status_play_ok,\r
+    status_end,\r
+    status_end_ok,\r
+    status_pause,\r
+    status_pause_ok,\r
+    status_seek,\r
+    status_seek_ok,\r
+    status_rew,\r
+    status_rew_ok,\r
+    status_ff,\r
+    status_ff_ok,\r
+    status_exit,\r
+    status_fail = STATUS_ERROR\r
+  }; \r
+\r
+  void setup(const std::wstring& file_path);\r
+  void read_file();\r
+  void pause();\r
+  void stop();\r
+  uint64_t position() { return position_;};\r
+  void position(uint64_t pos);\r
+  uint64_t size() { return reader_->total_data_bytes(); }\r
+  void repeat_mode(bool v) { repeat_mode_ = v ;reader_->repeat_mode(v);}\r
+  const bool repeat_mode() const {return repeat_mode_;}\r
+protected:\r
+  void run();\r
+private:\r
+  std::wstring source_file_path_;\r
+  std::unique_ptr<async_reader> reader_;\r
+  uint64_t position_;//,output_counter_;\r
+  uint32_t status_backup_;\r
+  bool repeat_mode_;// リピートモード\r
+  bool not_enqueue_;\r
+};\r
+}\r
+\r