diff options
author | Jean-Francois Mauguit <jfmauguit@mac.com> | 2024-09-24 09:03:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-24 09:03:25 -0400 |
commit | bab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Input/in_mod-openmpt/MODThread.cpp | |
parent | 4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff) | |
parent | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff) | |
download | winamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz |
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/Plugins/Input/in_mod-openmpt/MODThread.cpp')
-rw-r--r-- | Src/Plugins/Input/in_mod-openmpt/MODThread.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_mod-openmpt/MODThread.cpp b/Src/Plugins/Input/in_mod-openmpt/MODThread.cpp new file mode 100644 index 00000000..40c67082 --- /dev/null +++ b/Src/Plugins/Input/in_mod-openmpt/MODThread.cpp @@ -0,0 +1,166 @@ +#include "api__in_mod.h" +#include "../Winamp/wa_ipc.h" +#include "MODPlayer.h" +#include <libopenmpt/libopenmpt_stream_callbacks_file.h> +#include <nx/nxuri.h> +#include <nx/nxstring.h> +#include <nx/nxfile.h> +#include "../nsutil/pcm.h" + +openmpt_module *OpenMod(const wchar_t *filename); + +extern int g_duration; +extern In_Module plugin; +// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F} +static const GUID playbackConfigGroupGUID = +{ + 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } +}; + +static const size_t kModBufferSize = 512; +static const unsigned int kModSampleRate = 44100; // TODO(benski) configurable! + +void MODPlayer::MODWait::Wait_SetEvents(HANDLE killswitch, HANDLE seek_event) +{ + handles[0]=killswitch; + handles[1]=seek_event; +} + +int MODPlayer::MODWait::WaitOrAbort(int time_in_ms) +{ + switch(WaitForMultipleObjects(2, handles, FALSE, time_in_ms)) + { + case WAIT_TIMEOUT: // all good, wait successful + return 0; + case WAIT_OBJECT_0: // killswitch + return MODPlayer::MOD_STOP; + case WAIT_OBJECT_0+1: // seek event + return MODPlayer::MOD_ABORT; + default: // some OS error? + return MODPlayer::MOD_ERROR; + } +} + +MODPlayer::MODPlayer(const wchar_t *_filename) : audio_output(&plugin) +{ + filename = _wcsdup(_filename); + m_needseek = -1; + + killswitch = CreateEvent(NULL, TRUE, FALSE, NULL); + seek_event = CreateEvent(NULL, TRUE, FALSE, NULL); + + audio_output.Wait_SetEvents(killswitch, seek_event); +} + +MODPlayer::~MODPlayer() +{ + CloseHandle(killswitch); + CloseHandle(seek_event); + free(filename); +} + +void MODPlayer::Kill() +{ + SetEvent(killswitch); +} + +void MODPlayer::Seek(int seek_pos) +{ + m_needseek = seek_pos; + SetEvent(seek_event); +} + +int MODPlayer::GetOutputTime() const +{ + if (m_needseek != -1) + return m_needseek; + else + return plugin.outMod->GetOutputTime(); +} + +DWORD CALLBACK MODThread(LPVOID param) +{ + MODPlayer *player = (MODPlayer *)param; + DWORD ret = player->ThreadFunction(); + return ret; +} + +DWORD CALLBACK MODPlayer::ThreadFunction() +{ + float *float_buffer = 0; + void *int_buffer = 0; + + HANDLE handles[] = {killswitch, seek_event}; + size_t count = 0; + size_t (*openmpt_read)(openmpt_module * mod, int32_t samplerate, size_t count, float *interleaved_stereo)=openmpt_module_read_interleaved_float_stereo; + + int channels = 2; + bool force_mono = AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false); + bool surround = AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true); + int bits = (int)AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16); + if (force_mono) { + channels = 1; + openmpt_read = openmpt_module_read_float_mono; + } else if (surround) { + channels = 4; + openmpt_read = openmpt_module_read_interleaved_float_quad; + } + + // ===== tell audio output helper object about the output plugin ===== + audio_output.Init(plugin.outMod); + + openmpt_module * mod = OpenMod(filename); + if (!mod) { + goto btfo; + } + openmpt_module_ctl_set(mod, "seek.sync_sample", "1"); + g_duration = (int)(openmpt_module_get_duration_seconds(mod) * 1000); + audio_output.Open(0, channels, kModSampleRate, bits); + + float_buffer = (float *)malloc(sizeof(float) * kModBufferSize * channels); + int_buffer = malloc(kModBufferSize * channels * bits/8); + + while (WaitForMultipleObjects(2, handles, FALSE, 0) != WAIT_OBJECT_0) { + count = openmpt_read(mod, kModSampleRate, kModBufferSize, float_buffer); + if (count == 0) { + break; + } + nsutil_pcm_FloatToInt_Interleaved(int_buffer, float_buffer, bits, channels*count); + int ret = audio_output.Write((char *)int_buffer, channels*count*bits/8); + + if (ret == MOD_STOP) { + break; + } else if (ret == MOD_ABORT) { + ResetEvent(seek_event); + openmpt_module_set_position_seconds(mod, m_needseek/1000.0); + audio_output.Flush(m_needseek); + m_needseek = -1; + } else if (ret != MOD_CONTINUE) { + ret = ret; + } + } + + if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0) { + audio_output.Write(0,0); + audio_output.WaitWhilePlaying(); + + if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0) { + PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + } + } + audio_output.Close(); + openmpt_module_destroy(mod); + free(float_buffer); + free(int_buffer); + return 0; + +btfo: // bail the fuck out + if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0) { + PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + } + audio_output.Close(); + openmpt_module_destroy(mod); + free(float_buffer); + free(int_buffer); + return 1; +}
\ No newline at end of file |