MODThread.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "api__in_mod.h"
  2. #include "../Winamp/wa_ipc.h"
  3. #include "MODPlayer.h"
  4. #include <libopenmpt/libopenmpt_stream_callbacks_file.h>
  5. #include <nx/nxuri.h>
  6. #include <nx/nxstring.h>
  7. #include <nx/nxfile.h>
  8. #include "../nsutil/pcm.h"
  9. openmpt_module *OpenMod(const wchar_t *filename);
  10. extern int g_duration;
  11. extern In_Module plugin;
  12. // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
  13. static const GUID playbackConfigGroupGUID =
  14. {
  15. 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf }
  16. };
  17. static const size_t kModBufferSize = 512;
  18. static const unsigned int kModSampleRate = 44100; // TODO(benski) configurable!
  19. void MODPlayer::MODWait::Wait_SetEvents(HANDLE killswitch, HANDLE seek_event)
  20. {
  21. handles[0]=killswitch;
  22. handles[1]=seek_event;
  23. }
  24. int MODPlayer::MODWait::WaitOrAbort(int time_in_ms)
  25. {
  26. switch(WaitForMultipleObjects(2, handles, FALSE, time_in_ms))
  27. {
  28. case WAIT_TIMEOUT: // all good, wait successful
  29. return 0;
  30. case WAIT_OBJECT_0: // killswitch
  31. return MODPlayer::MOD_STOP;
  32. case WAIT_OBJECT_0+1: // seek event
  33. return MODPlayer::MOD_ABORT;
  34. default: // some OS error?
  35. return MODPlayer::MOD_ERROR;
  36. }
  37. }
  38. MODPlayer::MODPlayer(const wchar_t *_filename) : audio_output(&plugin)
  39. {
  40. filename = _wcsdup(_filename);
  41. m_needseek = -1;
  42. killswitch = CreateEvent(NULL, TRUE, FALSE, NULL);
  43. seek_event = CreateEvent(NULL, TRUE, FALSE, NULL);
  44. audio_output.Wait_SetEvents(killswitch, seek_event);
  45. }
  46. MODPlayer::~MODPlayer()
  47. {
  48. CloseHandle(killswitch);
  49. CloseHandle(seek_event);
  50. free(filename);
  51. }
  52. void MODPlayer::Kill()
  53. {
  54. SetEvent(killswitch);
  55. }
  56. void MODPlayer::Seek(int seek_pos)
  57. {
  58. m_needseek = seek_pos;
  59. SetEvent(seek_event);
  60. }
  61. int MODPlayer::GetOutputTime() const
  62. {
  63. if (m_needseek != -1)
  64. return m_needseek;
  65. else
  66. return plugin.outMod->GetOutputTime();
  67. }
  68. DWORD CALLBACK MODThread(LPVOID param)
  69. {
  70. MODPlayer *player = (MODPlayer *)param;
  71. DWORD ret = player->ThreadFunction();
  72. return ret;
  73. }
  74. DWORD CALLBACK MODPlayer::ThreadFunction()
  75. {
  76. float *float_buffer = 0;
  77. void *int_buffer = 0;
  78. HANDLE handles[] = {killswitch, seek_event};
  79. size_t count = 0;
  80. size_t (*openmpt_read)(openmpt_module * mod, int32_t samplerate, size_t count, float *interleaved_stereo)=openmpt_module_read_interleaved_float_stereo;
  81. int channels = 2;
  82. bool force_mono = AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false);
  83. bool surround = AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true);
  84. int bits = (int)AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16);
  85. if (force_mono) {
  86. channels = 1;
  87. openmpt_read = openmpt_module_read_float_mono;
  88. } else if (surround) {
  89. channels = 4;
  90. openmpt_read = openmpt_module_read_interleaved_float_quad;
  91. }
  92. // ===== tell audio output helper object about the output plugin =====
  93. audio_output.Init(plugin.outMod);
  94. openmpt_module * mod = OpenMod(filename);
  95. if (!mod) {
  96. goto btfo;
  97. }
  98. openmpt_module_ctl_set(mod, "seek.sync_sample", "1");
  99. g_duration = (int)(openmpt_module_get_duration_seconds(mod) * 1000);
  100. audio_output.Open(0, channels, kModSampleRate, bits);
  101. float_buffer = (float *)malloc(sizeof(float) * kModBufferSize * channels);
  102. int_buffer = malloc(kModBufferSize * channels * bits/8);
  103. while (WaitForMultipleObjects(2, handles, FALSE, 0) != WAIT_OBJECT_0) {
  104. count = openmpt_read(mod, kModSampleRate, kModBufferSize, float_buffer);
  105. if (count == 0) {
  106. break;
  107. }
  108. nsutil_pcm_FloatToInt_Interleaved(int_buffer, float_buffer, bits, channels*count);
  109. int ret = audio_output.Write((char *)int_buffer, channels*count*bits/8);
  110. if (ret == MOD_STOP) {
  111. break;
  112. } else if (ret == MOD_ABORT) {
  113. ResetEvent(seek_event);
  114. openmpt_module_set_position_seconds(mod, m_needseek/1000.0);
  115. audio_output.Flush(m_needseek);
  116. m_needseek = -1;
  117. } else if (ret != MOD_CONTINUE) {
  118. ret = ret;
  119. }
  120. }
  121. if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0) {
  122. audio_output.Write(0,0);
  123. audio_output.WaitWhilePlaying();
  124. if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0) {
  125. PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  126. }
  127. }
  128. audio_output.Close();
  129. openmpt_module_destroy(mod);
  130. free(float_buffer);
  131. free(int_buffer);
  132. return 0;
  133. btfo: // bail the fuck out
  134. if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0) {
  135. PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  136. }
  137. audio_output.Close();
  138. openmpt_module_destroy(mod);
  139. free(float_buffer);
  140. free(int_buffer);
  141. return 1;
  142. }