--- /dev/null
+/*
+==============================================================================
+
+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;
+ }
+
+}
+
+
--- /dev/null
+#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_;
+ };
+}
--- /dev/null
+/*
+==============================================================================
+
+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)));
+ // }
+ //}
+
+
+}
+
--- /dev/null
+#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_;
+};
+}
+
--- /dev/null
+/*\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
--- /dev/null
+#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:
+};
+}
+
--- /dev/null
+/*\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
--- /dev/null
+#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
--- /dev/null
+/*\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
--- /dev/null
+#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