Bundle libOpenMPT as a dynamic framework, which should be safe once again, now that there is only one version to bundle. Also, now it is using the versions of libvorbisfile and libmpg123 that are bundled with the player, instead of compiling minimp3 and stbvorbis. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
587 lines
17 KiB
C++
587 lines
17 KiB
C++
/*
|
|
* in_openmpt.cpp
|
|
* --------------
|
|
* Purpose: libopenmpt winamp input plugin implementation
|
|
* Notes : (currently none)
|
|
* Authors: OpenMPT Devs
|
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
|
*/
|
|
|
|
#ifndef NO_WINAMP
|
|
|
|
#if defined(_MFC_VER) || 1
|
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#if !defined(WINVER) && !defined(_WIN32_WINDOWS)
|
|
#ifndef _WIN32_WINNT
|
|
#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
|
|
#endif
|
|
#endif
|
|
#if !defined(MPT_BUILD_RETRO)
|
|
#if defined(_MSC_VER)
|
|
#define MPT_WITH_MFC
|
|
#endif
|
|
#else
|
|
#if defined(_WIN32_WINNT)
|
|
#if (_WIN32_WINNT >= 0x0501)
|
|
#if defined(_MSC_VER)
|
|
#define MPT_WITH_MFC
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#if defined(MPT_WITH_MFC)
|
|
#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls
|
|
#endif // MPT_WITH_MFC
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
#if defined(MPT_WITH_MFC)
|
|
#include <afxwin.h>
|
|
#include <afxcmn.h>
|
|
#endif // MPT_WITH_MFC
|
|
#include <windows.h>
|
|
#endif // _MFC_VER
|
|
|
|
#ifdef LIBOPENMPT_BUILD_DLL
|
|
#undef LIBOPENMPT_BUILD_DLL
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#ifndef _SCL_SECURE_NO_WARNINGS
|
|
#define _SCL_SECURE_NO_WARNINGS
|
|
#endif
|
|
#endif // _MSC_VER
|
|
|
|
#include "libopenmpt.hpp"
|
|
|
|
#include "libopenmpt_plugin_settings.hpp"
|
|
|
|
#include "libopenmpt_plugin_gui.hpp"
|
|
|
|
#include "svn_version.h"
|
|
#if defined(OPENMPT_VERSION_REVISION)
|
|
static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION);
|
|
#else
|
|
static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING;
|
|
#endif
|
|
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
#include <windows.h>
|
|
|
|
#ifdef UNICODE
|
|
#define UNICODE_INPUT_PLUGIN
|
|
#endif
|
|
#ifndef _MSC_VER
|
|
#define _MSC_VER 1300
|
|
#endif
|
|
#include "winamp/Winamp/IN2.H"
|
|
#include "winamp/Winamp/wa_ipc.h"
|
|
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
|
|
#include <cstring>
|
|
|
|
#include <tchar.h>
|
|
|
|
#define BPS 16
|
|
|
|
#define WINAMP_DSP_HEADROOM_FACTOR 2
|
|
#define WINAMP_BUFFER_SIZE_FRAMES 576
|
|
|
|
#define WM_OPENMPT_SEEK (WM_USER+3)
|
|
|
|
#define SHORT_TITLE "in_openmpt"
|
|
|
|
static void apply_options();
|
|
|
|
static std::string StringEncode( const std::wstring &src, UINT codepage )
|
|
{
|
|
int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, NULL, 0, NULL, NULL );
|
|
if(required_size <= 0)
|
|
{
|
|
return std::string();
|
|
}
|
|
std::vector<CHAR> encoded_string( required_size );
|
|
WideCharToMultiByte( codepage, 0, src.c_str(), -1, &encoded_string[0], encoded_string.size(), NULL, NULL );
|
|
return &encoded_string[0];
|
|
}
|
|
|
|
static std::wstring StringDecode( const std::string & src, UINT codepage )
|
|
{
|
|
int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, NULL, 0 );
|
|
if(required_size <= 0)
|
|
{
|
|
return std::wstring();
|
|
}
|
|
std::vector<WCHAR> decoded_string( required_size );
|
|
MultiByteToWideChar( codepage, 0, src.c_str(), -1, &decoded_string[0], decoded_string.size() );
|
|
return &decoded_string[0];
|
|
}
|
|
|
|
#if defined(UNICODE)
|
|
|
|
static std::wstring StringToWINAPI( const std::wstring & src )
|
|
{
|
|
return src;
|
|
}
|
|
|
|
#else
|
|
|
|
static std::string StringToWINAPI( const std::wstring & src )
|
|
{
|
|
return StringEncode( src, CP_ACP );
|
|
}
|
|
|
|
#endif
|
|
|
|
template <typename Tstring, typename Tstring2, typename Tstring3>
|
|
static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) {
|
|
std::size_t pos = 0;
|
|
const Tstring oldStr = oldStr_;
|
|
const Tstring newStr = newStr_;
|
|
while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) {
|
|
str.replace( pos, oldStr.length(), newStr );
|
|
pos += newStr.length();
|
|
}
|
|
return str;
|
|
}
|
|
|
|
struct self_winamp_t {
|
|
std::vector<char> filetypes_string;
|
|
libopenmpt::plugin::settings settings;
|
|
int samplerate;
|
|
int channels;
|
|
std::basic_string<TCHAR> cached_filename;
|
|
std::basic_string<TCHAR> cached_title;
|
|
int cached_length;
|
|
std::basic_string<TCHAR> cached_infotext;
|
|
std::int64_t decode_position_frames;
|
|
openmpt::module * mod;
|
|
HANDLE PlayThread;
|
|
DWORD PlayThreadID;
|
|
bool paused;
|
|
std::vector<std::int16_t> buffer;
|
|
std::vector<std::int16_t> interleaved_buffer;
|
|
self_winamp_t() : settings(TEXT(SHORT_TITLE), true) {
|
|
filetypes_string.clear();
|
|
settings.changed = apply_options;
|
|
settings.load();
|
|
std::vector<std::string> extensions = openmpt::get_supported_extensions();
|
|
for ( std::vector<std::string>::iterator ext = extensions.begin(); ext != extensions.end(); ++ext ) {
|
|
std::copy( (*ext).begin(), (*ext).end(), std::back_inserter( filetypes_string ) );
|
|
filetypes_string.push_back('\0');
|
|
std::copy( SHORT_TITLE, SHORT_TITLE + std::strlen(SHORT_TITLE), std::back_inserter( filetypes_string ) );
|
|
filetypes_string.push_back('\0');
|
|
}
|
|
filetypes_string.push_back('\0');
|
|
samplerate = settings.samplerate;
|
|
channels = settings.channels;
|
|
cached_filename = std::basic_string<TCHAR>();
|
|
cached_title = std::basic_string<TCHAR>();
|
|
cached_length = 0;
|
|
cached_infotext = std::basic_string<TCHAR>();
|
|
decode_position_frames = 0;
|
|
mod = 0;
|
|
PlayThread = 0;
|
|
PlayThreadID = 0;
|
|
paused = false;
|
|
buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels );
|
|
interleaved_buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels * WINAMP_DSP_HEADROOM_FACTOR );
|
|
}
|
|
~self_winamp_t() {
|
|
return;
|
|
}
|
|
};
|
|
|
|
static self_winamp_t * self = 0;
|
|
|
|
static void apply_options() {
|
|
if ( self->mod ) {
|
|
self->mod->set_repeat_count( self->settings.repeatcount );
|
|
self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel );
|
|
self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation );
|
|
self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength );
|
|
self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping );
|
|
self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false );
|
|
switch ( self->settings.amiga_filter_type ) {
|
|
case 0:
|
|
self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" );
|
|
break;
|
|
case 1:
|
|
self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" );
|
|
break;
|
|
case 0xA500:
|
|
self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" );
|
|
break;
|
|
case 0xA1200:
|
|
self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" );
|
|
break;
|
|
}
|
|
}
|
|
self->settings.save();
|
|
}
|
|
|
|
extern In_Module inmod;
|
|
|
|
static DWORD WINAPI DecodeThread( LPVOID );
|
|
|
|
static std::basic_string<TCHAR> generate_infotext( const std::basic_string<TCHAR> & filename, const openmpt::module & mod ) {
|
|
std::basic_ostringstream<TCHAR> str;
|
|
str << TEXT("filename: ") << filename << std::endl;
|
|
str << TEXT("duration: ") << mod.get_duration_seconds() << TEXT("seconds") << std::endl;
|
|
std::vector<std::string> metadatakeys = mod.get_metadata_keys();
|
|
for ( std::vector<std::string>::iterator key = metadatakeys.begin(); key != metadatakeys.end(); ++key ) {
|
|
if ( *key == "message_raw" ) {
|
|
continue;
|
|
}
|
|
str << StringToWINAPI( StringDecode( *key, CP_UTF8 ) ) << TEXT(": ") << StringToWINAPI( StringDecode( mod.get_metadata(*key), CP_UTF8 ) ) << std::endl;
|
|
}
|
|
return str.str();
|
|
}
|
|
|
|
static void config( HWND hwndParent ) {
|
|
#if 1
|
|
libopenmpt::plugin::gui_edit_settings( &self->settings, hwndParent, TEXT(SHORT_TITLE) );
|
|
#else
|
|
static_cast<void>(hwndParent);
|
|
#endif
|
|
apply_options();
|
|
}
|
|
|
|
static void about( HWND hwndParent ) {
|
|
std::ostringstream about;
|
|
about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
|
|
about << " Copyright (c) 2013-2022 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl;
|
|
about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
|
|
about << std::endl;
|
|
about << openmpt::string::get( "contact" ) << std::endl;
|
|
about << std::endl;
|
|
about << "Show full credits?" << std::endl;
|
|
if ( MessageBox( hwndParent, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) {
|
|
return;
|
|
}
|
|
std::ostringstream credits;
|
|
credits << openmpt::string::get( "credits" );
|
|
#if 1
|
|
libopenmpt::plugin::gui_show_file_info( hwndParent, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) );
|
|
#else
|
|
MessageBox( hwndParent, StringToWINAPI( StringReplace(StringDecode(credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK );
|
|
#endif
|
|
}
|
|
|
|
static void init() {
|
|
if ( !self ) {
|
|
self = new self_winamp_t();
|
|
inmod.FileExtensions = &(self->filetypes_string[0]);
|
|
}
|
|
}
|
|
|
|
static void quit() {
|
|
if ( self ) {
|
|
inmod.FileExtensions = NULL;
|
|
delete self;
|
|
self = 0;
|
|
}
|
|
}
|
|
|
|
static int isourfile( const in_char * /* fn */ ) {
|
|
return 0;
|
|
}
|
|
|
|
static int play( const in_char * fn ) {
|
|
if ( !fn ) {
|
|
return -1;
|
|
}
|
|
try {
|
|
std::ifstream s( fn, std::ios::binary );
|
|
std::map< std::string, std::string > ctls;
|
|
ctls["seek.sync_samples"] = "1";
|
|
self->mod = new openmpt::module( s, std::clog, ctls );
|
|
self->cached_filename = fn;
|
|
self->cached_title = StringToWINAPI( StringDecode( self->mod->get_metadata( "title" ), CP_UTF8 ) );
|
|
self->cached_length = static_cast<int>( self->mod->get_duration_seconds() * 1000.0 );
|
|
self->cached_infotext = generate_infotext( self->cached_filename, *self->mod );
|
|
apply_options();
|
|
self->samplerate = self->settings.samplerate;
|
|
self->channels = self->settings.channels;
|
|
int maxlatency = inmod.outMod->Open( self->samplerate, self->channels, BPS, -1, -1 );
|
|
std::ostringstream str;
|
|
str << maxlatency;
|
|
inmod.SetInfo( self->mod->get_num_channels(), self->samplerate/1000, self->channels, 1 );
|
|
inmod.SAVSAInit( maxlatency, self->samplerate );
|
|
inmod.VSASetInfo( self->channels, self->samplerate );
|
|
inmod.outMod->SetVolume( -666 );
|
|
inmod.outMod->SetPan( 0 );
|
|
self->paused = false;
|
|
self->decode_position_frames = 0;
|
|
self->PlayThread = CreateThread( NULL, 0, DecodeThread, NULL, 0, &self->PlayThreadID );
|
|
return 0;
|
|
} catch ( ... ) {
|
|
if ( self->mod ) {
|
|
delete self->mod;
|
|
self->mod = 0;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static void pause() {
|
|
self->paused = true;
|
|
inmod.outMod->Pause( 1 );
|
|
}
|
|
|
|
static void unpause() {
|
|
self->paused = false;
|
|
inmod.outMod->Pause( 0 );
|
|
}
|
|
|
|
static int ispaused() {
|
|
return self->paused ? 1 : 0;
|
|
}
|
|
|
|
static void stop() {
|
|
PostThreadMessage( self->PlayThreadID, WM_QUIT, 0, 0 );
|
|
WaitForSingleObject( self->PlayThread, INFINITE );
|
|
CloseHandle( self->PlayThread );
|
|
self->PlayThread = 0;
|
|
self->PlayThreadID = 0;
|
|
delete self->mod;
|
|
self->mod = 0;
|
|
inmod.outMod->Close();
|
|
inmod.SAVSADeInit();
|
|
}
|
|
|
|
static int getlength() {
|
|
return self->cached_length;
|
|
}
|
|
|
|
static int getoutputtime() {
|
|
//return (int)( self->decode_position_frames * 1000 / self->mod->get_render_param( openmpt::module::RENDER_SAMPLERATE_HZ ) /* + ( inmod.outMod->GetOutputTime() - inmod.outMod->GetWrittenTime() ) */ );
|
|
return inmod.outMod->GetOutputTime();
|
|
}
|
|
|
|
static void setoutputtime( int time_in_ms ) {
|
|
PostThreadMessage( self->PlayThreadID, WM_OPENMPT_SEEK, 0, time_in_ms );
|
|
}
|
|
|
|
static void setvolume( int volume ) {
|
|
inmod.outMod->SetVolume( volume );
|
|
}
|
|
|
|
static void setpan( int pan ) {
|
|
inmod.outMod->SetPan( pan );
|
|
}
|
|
|
|
static int infobox( const in_char * fn, HWND hWndParent ) {
|
|
if ( fn && fn[0] != '\0' && self->cached_filename != std::basic_string<TCHAR>(fn) ) {
|
|
try {
|
|
std::ifstream s( fn, std::ios::binary );
|
|
openmpt::module mod( s );
|
|
#if 1
|
|
libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ) );
|
|
#else
|
|
MessageBox( hWndParent, StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK );
|
|
#endif
|
|
} catch ( ... ) {
|
|
}
|
|
} else {
|
|
#if 1
|
|
libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ) );
|
|
#else
|
|
MessageBox( hWndParent, StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK );
|
|
#endif
|
|
}
|
|
return INFOBOX_UNCHANGED;
|
|
}
|
|
|
|
|
|
static void getfileinfo( const in_char * filename, in_char * title, int * length_in_ms ) {
|
|
if ( !filename || *filename == '\0' ) {
|
|
if ( length_in_ms ) {
|
|
*length_in_ms = self->cached_length;
|
|
}
|
|
if ( title ) {
|
|
std::basic_string<TCHAR> truncated_title = self->cached_title;
|
|
if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) {
|
|
truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 );
|
|
}
|
|
_tcscpy( title, truncated_title.c_str() );
|
|
}
|
|
} else {
|
|
try {
|
|
std::ifstream s( filename, std::ios::binary );
|
|
openmpt::module mod( s );
|
|
if ( length_in_ms ) {
|
|
*length_in_ms = static_cast<int>( mod.get_duration_seconds() * 1000.0 );
|
|
}
|
|
if ( title ) {
|
|
std::basic_string<TCHAR> truncated_title = StringToWINAPI( StringDecode( mod.get_metadata("title"), CP_UTF8 ) );
|
|
if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) {
|
|
truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 );
|
|
}
|
|
_tcscpy( title, truncated_title.c_str() );
|
|
}
|
|
} catch ( ... ) {
|
|
}
|
|
}
|
|
}
|
|
|
|
static void eq_set( int /* on */ , char /* data */ [10], int /* preamp */ ) {
|
|
return;
|
|
}
|
|
|
|
static DWORD WINAPI DecodeThread( LPVOID ) {
|
|
MSG msg;
|
|
PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );
|
|
bool eof = false;
|
|
while ( true ) {
|
|
bool quit = false;
|
|
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
|
|
if ( msg.message == WM_QUIT ) {
|
|
quit = true;
|
|
} else if ( msg.message == WM_OPENMPT_SEEK ) {
|
|
double pos_seconds = self->mod->set_position_seconds( msg.lParam * 0.001 );
|
|
self->decode_position_frames = (std::int64_t)( pos_seconds * (double)self->samplerate);
|
|
eof = false;
|
|
inmod.outMod->Flush( (int)( pos_seconds * 1000.0 ) );
|
|
}
|
|
}
|
|
if ( quit ) {
|
|
break;
|
|
}
|
|
if ( eof ) {
|
|
inmod.outMod->CanWrite(); // update output plugin state
|
|
if ( !inmod.outMod->IsPlaying() ) {
|
|
PostMessage( inmod.hMainWindow, WM_WA_MPEG_EOF, 0, 0 );
|
|
return 0;
|
|
}
|
|
Sleep( 10 );
|
|
} else {
|
|
bool dsp_active = inmod.dsp_isactive() ? true : false;
|
|
if ( inmod.outMod->CanWrite() >= (int)( WINAMP_BUFFER_SIZE_FRAMES * self->channels * sizeof( signed short ) ) * ( dsp_active ? WINAMP_DSP_HEADROOM_FACTOR : 1 ) ) {
|
|
int frames = 0;
|
|
switch ( self->channels ) {
|
|
case 1:
|
|
frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES );
|
|
for ( int frame = 0; frame < frames; frame++ ) {
|
|
self->interleaved_buffer[frame*1+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
}
|
|
break;
|
|
case 2:
|
|
frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES );
|
|
for ( int frame = 0; frame < frames; frame++ ) {
|
|
self->interleaved_buffer[frame*2+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
self->interleaved_buffer[frame*2+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
}
|
|
break;
|
|
case 4:
|
|
frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+2*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+3*WINAMP_BUFFER_SIZE_FRAMES );
|
|
for ( int frame = 0; frame < frames; frame++ ) {
|
|
self->interleaved_buffer[frame*4+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
self->interleaved_buffer[frame*4+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
self->interleaved_buffer[frame*4+2] = self->buffer[2*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
self->interleaved_buffer[frame*4+3] = self->buffer[3*WINAMP_BUFFER_SIZE_FRAMES+frame];
|
|
}
|
|
break;
|
|
}
|
|
if ( frames == 0 ) {
|
|
eof = true;
|
|
} else {
|
|
self->decode_position_frames += frames;
|
|
std::int64_t decode_pos_ms = (self->decode_position_frames * 1000 / self->samplerate );
|
|
inmod.SAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms );
|
|
inmod.VSAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms );
|
|
if ( dsp_active ) {
|
|
frames = inmod.dsp_dosamples( &( self->interleaved_buffer[0] ), frames, BPS, self->channels, self->samplerate );
|
|
}
|
|
int bytes = frames * self->channels * sizeof( signed short );
|
|
inmod.outMod->Write( (char*)&( self->interleaved_buffer[0] ), bytes );
|
|
}
|
|
} else {
|
|
Sleep( 10 );
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if defined(__GNUC__)
|
|
extern In_Module inmod;
|
|
#endif
|
|
In_Module inmod = {
|
|
IN_VER,
|
|
const_cast< char * >( in_openmpt_string ), // SHORT_TITLE,
|
|
0, // hMainWindow
|
|
0, // hDllInstance
|
|
NULL, // filled later in Init() "mptm\0ModPlug Tracker Module (*.mptm)\0",
|
|
1, // is_seekable
|
|
1, // uses output
|
|
config,
|
|
about,
|
|
init,
|
|
quit,
|
|
getfileinfo,
|
|
infobox,
|
|
isourfile,
|
|
play,
|
|
pause,
|
|
unpause,
|
|
ispaused,
|
|
stop,
|
|
getlength,
|
|
getoutputtime,
|
|
setoutputtime,
|
|
setvolume,
|
|
setpan,
|
|
0,0,0,0,0,0,0,0,0, // vis
|
|
0,0, // dsp
|
|
eq_set,
|
|
NULL, // setinfo
|
|
0 // out_mod
|
|
};
|
|
|
|
extern "C" __declspec(dllexport) In_Module * winampGetInModule2();
|
|
extern "C" __declspec(dllexport) In_Module * winampGetInModule2() {
|
|
return &inmod;
|
|
}
|
|
|
|
|
|
#if defined(MPT_WITH_MFC)
|
|
|
|
#ifdef _MFC_VER
|
|
|
|
namespace libopenmpt {
|
|
namespace plugin {
|
|
|
|
void DllMainAttach() {
|
|
// nothing
|
|
}
|
|
|
|
void DllMainDetach() {
|
|
// nothing
|
|
}
|
|
|
|
} // namespace plugin
|
|
} // namespace libopenmpt
|
|
|
|
#else
|
|
|
|
// nothing
|
|
|
|
#endif
|
|
|
|
#endif // MPT_WITH_MFC
|
|
|
|
|
|
#endif // NO_WINAMP
|