Skip to main content

Topic: Trying to compile ASIO output plugin and... (Read 506 times) previous topic - next topic

0 Members and 1 Guest are viewing this topic.
  • arnaudf
  • [*]
Trying to compile ASIO output plugin and...
Dear all,

I currently try to convert and compile ASIO source code from Otachan with ASIOSDK2.3 and latest Foobar SDK.
I almost manage to make it works.

However, I don't undertstand how to register the output service with the current SDK.
I currently have the code below and I have the following errors in VS console.
Would a nice soul do help me ?

Regards.

Code: [Select]
1>------ Build started: Project: foo_output_asio, Configuration: Debug Win32 ------
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppBuild.targets(936,5): warning MSB8027: Two or more files with the name of stdafx.cpp will produce outputs to the same location. This can lead to an incorrect build result.  The files involved are ..\..\pfc\stdafx.cpp, ..\..\SDK\stdafx.cpp.
1>  foo_output_asio.cpp
1>c:\sdk\fb2k\foo_output_asio(dll)_051\shared\fb2kdebug.h(80): warning C4838: conversion from 'int' to 'const ULONG_PTR' requires a narrowing conversion
1>c:\sdk\fb2k\sdk\output.h(175): error C2039: 'g_advanced_settings_query': is not a member of 'output_asio'
1>  c:\sdk\fb2k\foo_output_asio(dll)_051\source\foo_output_asio.h(56): note: see declaration of 'output_asio'
1>  c:\sdk\fb2k\sdk\output.h(173): note: while compiling class template member function 't_uint32 output_entry_impl_t<T,output_entry>::get_config_flags(void)'
1>          with
1>          [
1>              T=output_asio
1>          ]
1>  c:\sdk\fb2k\sdk\service.h(620): note: see reference to class template instantiation 'output_entry_impl_t<T,output_entry>' being compiled
1>          with
1>          [
1>              T=output_asio
1>          ]
1>  c:\sdk\fb2k\sdk\output.h(186): note: see reference to class template instantiation 'service_factory_single_t<output_entry_impl_t<T,output_entry>>' being compiled
1>          with
1>          [
1>              T=output_asio
1>          ]
1>  c:\sdk\fb2k\foo_output_asio(dll)_051\source\foo_output_asio.cpp(25): note: see reference to class template instantiation 'output_factory_t<output_asio>' being compiled
1>c:\sdk\fb2k\sdk\output.h(175): error C3861: 'g_advanced_settings_query': identifier not found
1>c:\sdk\fb2k\sdk\output.h(176): error C2039: 'g_needs_bitdepth_config': is not a member of 'output_asio'
1>  c:\sdk\fb2k\foo_output_asio(dll)_051\source\foo_output_asio.h(56): note: see declaration of 'output_asio'
1>c:\sdk\fb2k\sdk\output.h(176): error C3861: 'g_needs_bitdepth_config': identifier not found
1>c:\sdk\fb2k\sdk\output.h(177): error C2039: 'g_needs_dither_config': is not a member of 'output_asio'
1>  c:\sdk\fb2k\foo_output_asio(dll)_051\source\foo_output_asio.h(56): note: see declaration of 'output_asio'
1>c:\sdk\fb2k\sdk\output.h(177): error C3861: 'g_needs_dither_config': identifier not found
1>c:\sdk\fb2k\sdk\output.h(178): error C2039: 'g_needs_device_list_prefixes': is not a member of 'output_asio'
1>  c:\sdk\fb2k\foo_output_asio(dll)_051\source\foo_output_asio.h(56): note: see declaration of 'output_asio'
1>c:\sdk\fb2k\sdk\output.h(178): error C3861: 'g_needs_device_list_prefixes': identifier not found

Code: [Select]
/*
** foo_output_asio - ASIO output for foobar2000
**
** 2006/2/25 Written by Otachan
** http://otachan.com/
*/

#define STRICT

#include <windows.h>
#include <process.h>

#include "foo_output_asio.h"
#include "pcmasio.h"

extern HINSTANCE WSLhInstance;

extern AsioDrivers* asioDrivers;

//service_factory_single_t<initquit, initquit_output_asio> foo;
//service_factory_t<output, output_asio> foo2;

initquit_factory_t<initquit_output_asio> foo;
output_factory_t<output_asio> foo2;

//service_factory_single_t<initquit_output_asio> foo;
//service_factory_t<output_asio> foo2;

DECLARE_COMPONENT_VERSION(
NAME,
VER,
NAME " v" VER "\n\n"
"Copyright (C) 2003-2006 Otachan\n"
"http://otachan.com/\n\n"
"ASIO Technology by Steinberg.");

// {38B5B07D-532B-472B-B406-A484630A5021}
static const GUID guid_cfg_device =
{ 0x38b5b07d, 0x532b, 0x472b,{ 0xb4, 0x6, 0xa4, 0x84, 0x63, 0xa, 0x50, 0x21 } };

// {1D2540D2-5941-4787-AA60-E756ABCF32E5}
static const GUID guid_cfg_thread_priority =
{ 0x1d2540d2, 0x5941, 0x4787,{ 0xaa, 0x60, 0xe7, 0x56, 0xab, 0xcf, 0x32, 0xe5 } };

// {FD8C6045-CF61-4188-A0EA-12BB9D69062F}
static const GUID guid_cfg_buffer_size =
{ 0xfd8c6045, 0xcf61, 0x4188,{ 0xa0, 0xea, 0x12, 0xbb, 0x9d, 0x69, 0x6, 0x2f } };

// {8F295CD2-55AD-4771-95CA-3242871D5A4C}
static const GUID guid_cfg_shift_channels =
{ 0x8f295cd2, 0x55ad, 0x4771,{ 0x95, 0xca, 0x32, 0x42, 0x87, 0x1d, 0x5a, 0x4c } };

// {9E3A57CF-5D71-4667-AAFF-2F6E95212612}
static const GUID guid_direct_input_monitor =
{ 0x9e3a57cf, 0x5d71, 0x4667,{ 0xaa, 0xff, 0x2f, 0x6e, 0x95, 0x21, 0x26, 0x12 } };


cfg_int cfg_device(guid_cfg_device, 0);
cfg_int cfg_thread_priority(guid_cfg_thread_priority, 3);
cfg_int cfg_buffer_size(guid_cfg_buffer_size, 7);
cfg_int cfg_shift_channels(guid_cfg_shift_channels, 0);
cfg_int cfg_direct_input_monitor(guid_direct_input_monitor, 0);

CRITICAL_SECTION CriticalSectionInit;

PcmAsio* pPcmAsio;

HANDLE hThread;
HANDLE EventReadyThread;
HANDLE EventDestroyThread;

bool InitDLL;

BOOL WINAPI
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
{
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
::InitializeCriticalSection(&CriticalSectionInit);

WSLhInstance = hinstDLL;

InitDLL = false;
break;
case DLL_PROCESS_DETACH:
::DeleteCriticalSection(&CriticalSectionInit);
break;
}

return true;
}

unsigned int __stdcall
ThreadProc(void* /*Param*/)
{
asioDrivers = new AsioDrivers;
pPcmAsio = new PcmAsio;

::SetEvent(EventReadyThread);

while(::WaitForSingleObjectEx(EventDestroyThread, INFINITE, true) != WAIT_OBJECT_0);

delete pPcmAsio;
delete asioDrivers;

_endthreadex(0);

return 0;
}

void CALLBACK
ApcProc(ULONG_PTR dwParam)
{
ParamMsg* const Param = reinterpret_cast<ParamMsg*>(dwParam);

switch(Param->Msg) {
case MSG_CLOSE_DRIVER:
pPcmAsio->CloseDriver();
break;
case MSG_OPEN:
Param->RetMsg = pPcmAsio->MsgOpen(Param->Param1, Param->Param2, Param->Param3, Param->Param4);
break;
case MSG_CAN_WRITE:
Param->RetMsg = pPcmAsio->MsgCanWrite();
break;
case MSG_WRITE:
Param->RetMsg = pPcmAsio->MsgWrite(Param->Param1, Param->Buff);
break;
case MSG_PAUSE:
pPcmAsio->MsgPause(Param->Param1);
break;
case MSG_PLAY:
pPcmAsio->MsgPlay();
break;
case MSG_FLUSH:
Param->RetMsg = pPcmAsio->MsgFlush();
break;
}

Param->UnPause();
}

ParamMsg::ParamMsg(int _Msg)
{
Msg = _Msg;
}

ParamMsg::ParamMsg(int _Msg, int _Param1)
{
Msg = _Msg;
Param1 = _Param1;
}

ParamMsg::ParamMsg(int _Msg, int _Param1, int _Param2, int _Param3, int _Param4)
{
Msg = _Msg;
Param1 = _Param1;
Param2 = _Param2;
Param3 = _Param3;
Param4 = _Param4;
}

ParamMsg::ParamMsg(int _Msg, int _Param1, unsigned char* _Buff)
{
Msg = _Msg;
Param1 = _Param1;
Buff = _Buff;
}

int
ParamMsg::Call(void)
{
EventWaitThread = ::CreateEvent(NULL, false, false, NULL);

::QueueUserAPC(&ApcProc, hThread, reinterpret_cast<ULONG_PTR>(this));
::WaitForSingleObject(EventWaitThread, INFINITE);

::CloseHandle(EventWaitThread);

return RetMsg;
}

void
ParamMsg::UnPause(void)
{
::SetEvent(EventWaitThread);
}

void
Init(void)
{
::EnterCriticalSection(&CriticalSectionInit);

if(InitDLL == false) {
EventDestroyThread = ::CreateEvent(NULL, false, false, NULL);
EventReadyThread = ::CreateEvent(NULL, false, false, NULL);

unsigned int dwThread;

hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, ThreadProc, NULL, 0, &dwThread));

::WaitForSingleObject(EventReadyThread, INFINITE);

::CloseHandle(EventReadyThread);

InitDLL = true;
}

::LeaveCriticalSection(&CriticalSectionInit);
}

inline void
Quit(void)
{
::SetEvent(EventDestroyThread);

if(::WaitForSingleObject(hThread, 5000) != WAIT_OBJECT_0) {
if(::TerminateThread(hThread, 0)) {
::WaitForSingleObject(hThread, 3000);
}
}

::CloseHandle(hThread);
::CloseHandle(EventDestroyThread);
}


void
initquit_output_asio::on_init(void)
{
Init();
}

void
initquit_output_asio::on_quit(void)
{
Quit();
}

// ********************************** /
// output_asio
//

output_asio::output_asio(void)
{
Init();
OpenDriver = false;
}

output_asio::~output_asio(void)
{
if(OpenDriver) ParamMsg(MSG_CLOSE_DRIVER).Call();
}

int
output_asio::open_ex(int srate, int bps, int nch, int format_code)
{
const int RetCode = ParamMsg(MSG_OPEN, srate, format_code, bps, nch).Call();
OpenDriver = RetCode != 0;
return RetCode;
}

int
output_asio::can_write(void)
{
return ParamMsg(MSG_CAN_WRITE).Call();
}

int
output_asio::write(const char* data, int bytes)
{
return ParamMsg(MSG_WRITE, bytes,
reinterpret_cast<unsigned char*>(const_cast<char*>(data))).Call();
}

int
output_asio::get_latency_bytes(void)
{
return pPcmAsio->MsgGetLatency();
}

void
output_asio::pause(int state)
{
ParamMsg(MSG_PAUSE, state).Call();
}

void
output_asio::force_play(void)
{
ParamMsg(MSG_PLAY).Call();
}

int
output_asio::do_flush(void)
{
return ParamMsg(MSG_FLUSH).Call();
}

int
output_asio::is_playing(void)
{
return !!pPcmAsio->MsgGetLatency();
}
  • Last Edit: 19 November, 2017, 11:43:54 AM by arnaudf

  • 3dyd
  • [*][*][*][*]
  • Developer
Re: Trying to compile ASIO output plugin and...
Reply #1
Comment prepending class output_entry_impl_t from SDK/output.h states that "output_entry methods are forwarded to static methods of your output class". And in its code you can find calls like
Code: [Select]
if (T::g_advanced_settings_query()) flags |= output_entry::flag_needs_advanced_config;
'T' there is your output_asio class. In other words, output_asio implementation should contain static methods like
Code: [Select]
class output_asio {
public:
  static bool g_advanced_settings_query() { ... }
  static bool g_needs_bitdepth_config() { ... }
  // etc.

  • arnaudf
  • [*]
Re: Trying to compile ASIO output plugin and...
Reply #2
Hi,

Thank you for your answer. It was done in the meantime.
I think i'm not so far from the goal.

However when I try to register the class, I have these errors, and my current code is below.
It speaks about a reinterpret_cast, but i'm surprised to use that to be able to register the output.
Any idea ?

Regards.

Code: [Select]
c:\sdk\fb2k\pfc\primitives.h(186): error C2440: 'return': cannot convert from 'service_impl_t<output_asio_instance> *' to 'output::t_interface *'
1>  c:\sdk\fb2k\pfc\primitives.h(186): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>  c:\sdk\fb2k\sdk\service.h(82): note: see reference to function template instantiation 't_ret *pfc::safe_ptr_cast<T,t_source>(t_param *)' being compiled
1>          with
1>          [
1>              t_ret=output::t_interface,
1>              T=output::t_interface,
1>              t_source=service_impl_t<output_asio_instance>,
1>              t_param=service_impl_t<output_asio_instance>
1>          ]

Code: [Select]
// ********************************** /
// class output_asio_instance
//

class output_asio_instance : public output_entry_asio
{
public:


output_asio_instance(const GUID & p_device, double p_buffer_length, bool p_dither, t_uint32 p_bitdepth)
{
Init();
OpenDriver = false;
}

~output_asio_instance(void)
{
if (OpenDriver) ParamMsg(MSG_CLOSE_DRIVER).Call();
}

static void g_advanced_settings_popup(HWND p_parent, POINT p_menupoint) {};
static int g_advanced_settings_query() { return output_entry::flag_needs_advanced_config; };
static int g_needs_dither_config() { return output_entry::flag_needs_dither_config; };
static int g_needs_bitdepth_config() { return output_entry::flag_needs_bitdepth_config; };
static int g_needs_device_list_prefixes() { return output_entry::flag_needs_device_list_prefixes; };
static const GUID g_get_guid(void)
{
// {3A5EDE8E-840D-497c-9774-156A12FC4275}
static const GUID guid =
{ 0x3a5ede8e, 0x840d, 0x497c,{ 0x97, 0x74, 0x15, 0x6a, 0x12, 0xfc, 0x42, 0x75 } };

return guid;
}

static const char* g_get_name(void)
{
return NAME2;
}

virtual const char* get_config_page_name(void)
{
return NAME2;
}

void instantiate(service_ptr_t<output> & p_out, const GUID & p_device, double p_buffer_length, bool p_dither, t_uint32 p_bitdepth) {

p_out = new service_impl_t<output_asio_instance>(p_device, p_buffer_length, p_dither, p_bitdepth);
};

void enum_devices(output_device_enum_callback &) {};
GUID get_guid() { g_get_guid(); };
const char *get_name(void) { g_get_name(); };
void advanced_settings_popup(HWND, POINT) {};
t_uint32 output_entry::get_config_flags(void) {};

void
output_asio_instance::open(const t_samplespec &) {};
void
output_asio_instance::pause(bool) {};
void
output_asio_instance::on_flush(void) {};
void
output_asio_instance::volume_set(double) {};
void
output_asio_instance::on_update(void) {};
void
output_asio_instance::write(const audio_chunk &) {};
t_size
output_asio_instance::can_write_samples(void) {
t_size val;
return val;
};
t_size
output_asio_instance::get_latency_samples(void) {
t_size val;
return val;
};


int
output_asio_instance::open_ex(int srate, int bps, int nch, int format_code)
{
const int RetCode = ParamMsg(MSG_OPEN, srate, format_code, bps, nch).Call();
OpenDriver = RetCode != 0;
return RetCode;
}

int
output_asio_instance::can_write(void)
{
return ParamMsg(MSG_CAN_WRITE).Call();
}

int
output_asio_instance::write(const char* data, int bytes)
{
return ParamMsg(MSG_WRITE, bytes,
reinterpret_cast<unsigned char*>(const_cast<char*>(data))).Call();
}

int
output_asio_instance::get_latency_bytes(void)
{
return pPcmAsio->MsgGetLatency();
}

void
output_asio_instance::pause(int state)
{
ParamMsg(MSG_PAUSE, state).Call();
}

void
output_asio_instance::force_play(void)
{
ParamMsg(MSG_PLAY).Call();
}

int
output_asio_instance::do_flush(void)
{
return ParamMsg(MSG_FLUSH).Call();
}

int
output_asio_instance::is_playing(void)
{
return !!pPcmAsio->MsgGetLatency();
}

};

output_factory_t<output_asio_instance> foo2;

  • 3dyd
  • [*][*][*][*]
  • Developer
Re: Trying to compile ASIO output plugin and...
Reply #3
Here
Code: [Select]
void instantiate(service_ptr_t<output> & p_out, const GUID & p_device, double p_buffer_length, bool p_dither, t_uint32 p_bitdepth) {
    p_out = new service_impl_t<output_asio_instance>(p_device, p_buffer_length, p_dither, p_bitdepth);
};
you need to return instance of class derived from output (or output_v2), not from output_entry_asio.

  • arnaudf
  • [*]
Re: Trying to compile ASIO output plugin and...
Reply #4
Hello,

I follow advices and with the code below : this compile.
However, the output entry does not appear in FB2K output combobox.
I probably miss something, but I don't know what...

(output_asio derives from output_v2).

Code: [Select]
class output_asio_instance : public output_asio
{

public:

output_asio_instance()
{
Init();
OpenDriver = false;
};

output_asio_instance(const GUID & p_device, double p_buffer_length, bool p_dither, t_uint32 p_bitdepth)
{
Init();
OpenDriver = false;
}

~output_asio_instance(void)
{
if (OpenDriver) ParamMsg(MSG_CLOSE_DRIVER).Call();
}

static bool g_advanced_settings_query() { return FALSE; };
static bool g_needs_dither_config() { return TRUE; };
static bool g_needs_bitdepth_config() { return TRUE; };
static bool g_needs_device_list_prefixes() { return TRUE; };

static void g_advanced_settings_popup(HWND p_parent, POINT p_menupoint) {};

static const char* g_get_name(void) { return NAME2; }
static const GUID g_get_guid(void) { return g_guid; }

static t_uint32 get_config_flags(void) {
//return ;
};

static void g_enum_devices(output_device_enum_callback & p_callback) {
p_callback = output_device_enum_callback_impl();
};

void
open(const t_samplespec & sspec) {
//const int RetCode = ParamMsg(MSG_OPEN, sspec.m_sample_rate, format_code, bps, sspec.m_channels).Call();
//OpenDriver = RetCode != 0;
//return RetCode;
};
void
pause(bool) {};
void
flush(void) {
ParamMsg(MSG_FLUSH).Call();
};
void
volume_set(double) {};
void
update(bool &) {};
void
process_samples(const audio_chunk &) {};
t_size
can_write_samples(void) {
return ParamMsg(MSG_CAN_WRITE).Call();
};

double
get_latency() {
return pPcmAsio->MsgGetLatency();
}


int
open_ex(int srate, int bps, int nch, int format_code)
{
const int RetCode = ParamMsg(MSG_OPEN, srate, format_code, bps, nch).Call();
OpenDriver = RetCode != 0;
return RetCode;
}

//int
// output_asio_instance::can_write(void)
//{
// return ParamMsg(MSG_CAN_WRITE).Call();
//}

int
write(const char* data, int bytes)
{
return ParamMsg(MSG_WRITE, bytes,
reinterpret_cast<unsigned char*>(const_cast<char*>(data))).Call();
}

//int
// output_asio_instance::get_latency_bytes(void)
//{
// return pPcmAsio->MsgGetLatency();
//}

void
pause(int state)
{
ParamMsg(MSG_PAUSE, state).Call();
}

void
force_play(void)
{
ParamMsg(MSG_PLAY).Call();
}

//int
// output_asio_instance::do_flush(void)
//{
// return ParamMsg(MSG_FLUSH).Call();
//}

int
is_playing(void)
{
return !!pPcmAsio->MsgGetLatency();
}

protected:
class output_device_enum_callback_impl : public output_device_enum_callback {

public:
output_device_enum_callback_impl() {};
~output_device_enum_callback_impl() {};

void on_device(const GUID &p_guid, const char *p_name, unsigned p_name_length) {

//p_guid = p_device;
p_name = output_asio_instance::g_get_name();
p_name_length = 20;
}
};

};


class output_entry_impl : public output_entry {

output_entry_impl();

~output_entry_impl() {};

public:

void instantiate(service_ptr_t<output> & p_out, const GUID & p_device, double p_buffer_length, bool p_dither, t_uint32 p_bitdepth) {
p_out = new service_impl_t<output_asio_instance>(p_device, p_buffer_length, p_dither, p_bitdepth);
};

void enum_devices(output_device_enum_callback &) {};
GUID get_guid() { return output_asio_instance::g_get_guid(); };
const char *get_name(void) { return output_asio_instance::g_get_name(); };
void advanced_settings_popup(HWND, POINT) {  };

t_uint32 get_config_flags(){
output_asio_instance::get_config_flags();
};

};


output_factory_t<output_asio_instance> foo2;