forked from LosaDev/ls-2019-source
LosaDev source snapshot 2019
This commit is contained in:
commit
c198676e97
20588 files changed
+8812878
No files matched your search
@@ -0,0 +1,504 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// BandiVideoLibrary 2.1
|
||||
///
|
||||
/// Copyright(C) 2008-2011 BandiSoft.com All rights reserved.
|
||||
///
|
||||
/// Visit http://www.bandisoft.com for more information.
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#include <math.h>
|
||||
#include "BandiVideoSound_DS.h"
|
||||
|
||||
#define BVL_DSWND_CLASS_NAME _T("CBandiVideoSound_DS")
|
||||
|
||||
|
||||
CBandiVideoSound_DS::CBandiVideoSound_DS() : m_ref_count(0)
|
||||
{
|
||||
m_hwnd = NULL;
|
||||
m_hinst = NULL;
|
||||
m_ds = NULL;
|
||||
m_dsb_primary = NULL;
|
||||
m_dsb_secondary = NULL;
|
||||
|
||||
m_channels = m_samplerate = 0;
|
||||
m_last_write_pos = 0;
|
||||
m_inbuf_samples = m_total_samples = 0;
|
||||
|
||||
m_cur_play_time = 0;
|
||||
|
||||
memset(&m_crit_sec, NULL, sizeof(m_crit_sec));
|
||||
m_crit_sec_inited = FALSE;
|
||||
|
||||
m_hevent = NULL;
|
||||
m_hthread = NULL;
|
||||
m_thread_id = 0;
|
||||
|
||||
m_playing = FALSE;
|
||||
m_callback = NULL;
|
||||
|
||||
m_outbuf_size_max = -1;
|
||||
m_outbuf_size_min = -1;
|
||||
|
||||
memset(m_sample_block, NULL, PLAY_SAMPLE_BLOCK_LEN);
|
||||
m_sample_block_size = 0;
|
||||
}
|
||||
|
||||
|
||||
CBandiVideoSound_DS::~CBandiVideoSound_DS()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP_(ULONG) CBandiVideoSound_DS::AddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement(&m_ref_count);
|
||||
ASSERT(lRef >= 0);
|
||||
|
||||
return m_ref_count;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP_(ULONG) CBandiVideoSound_DS::Release()
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&m_ref_count);
|
||||
ASSERT(lRef >= 0);
|
||||
|
||||
if(lRef == 0)
|
||||
{
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
}
|
||||
|
||||
return m_ref_count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Open sound device.
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::Open(INT channels, INT samplerate, IBandiVideoSoundCB *callback)
|
||||
{
|
||||
Close();
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
m_hinst = (HINSTANCE)GetModuleHandle(NULL);
|
||||
if(m_hinst == NULL) goto error;
|
||||
|
||||
WNDCLASS wc;
|
||||
ZeroMemory(&wc, sizeof(wc));
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.lpszClassName = BVL_DSWND_CLASS_NAME;
|
||||
RegisterClass(&wc);
|
||||
|
||||
// 버퍼타임으로 버퍼 byte 크기 계산
|
||||
m_outbuf_size_max = MulDiv(samplerate * channels * 2, MAX_BUFFER_TIME , 1000) ;
|
||||
m_outbuf_size_min = MulDiv(samplerate * channels * 2, MIN_BUFFER_TIME ,1000 );
|
||||
|
||||
// Create dummy window
|
||||
m_hwnd = CreateWindow(BVL_DSWND_CLASS_NAME, _T(""), 0, 0, 0, 0, 0, NULL, NULL, m_hinst, 0L);
|
||||
if(m_hwnd == NULL)
|
||||
goto error;
|
||||
|
||||
// Create Direct Sound Instance
|
||||
hr = DirectSoundCreate8(NULL, &m_ds, NULL);
|
||||
if(FAILED(hr))
|
||||
goto error;
|
||||
|
||||
hr = m_ds->SetCooperativeLevel(m_hwnd, DSSCL_PRIORITY);
|
||||
if(FAILED(hr))
|
||||
goto error;
|
||||
|
||||
// Create a primary buffer
|
||||
DSBUFFERDESC dsbdesc;
|
||||
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||||
hr = m_ds->CreateSoundBuffer(&dsbdesc, &m_dsb_primary, NULL);
|
||||
if(FAILED(hr))
|
||||
goto error;
|
||||
|
||||
// Set format of the primary buffer
|
||||
WAVEFORMATEX wfx;
|
||||
ZeroMemory(&wfx, sizeof(WAVEFORMATEX));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = channels;
|
||||
wfx.nSamplesPerSec = samplerate;
|
||||
wfx.wBitsPerSample = 16;
|
||||
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
hr = m_dsb_primary->SetFormat(&wfx);
|
||||
if(FAILED(hr))
|
||||
goto error;
|
||||
|
||||
// Create secondary sound buffer
|
||||
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS
|
||||
/*| DSBCAPS_LOCDEFER | DSBCAPS_CTRLFREQUENCY*/ | DSBCAPS_CTRLVOLUME;
|
||||
dsbdesc.dwBufferBytes = m_outbuf_size_max;
|
||||
dsbdesc.lpwfxFormat = &wfx;
|
||||
hr = m_ds->CreateSoundBuffer(&dsbdesc, &m_dsb_secondary, NULL);
|
||||
if(FAILED(hr))
|
||||
goto error;
|
||||
|
||||
InitializeCriticalSection(&m_crit_sec);
|
||||
m_crit_sec_inited = TRUE;
|
||||
|
||||
// Create an event object for periodical processing
|
||||
m_hevent = CreateEvent(NULL, FALSE, FALSE, NULL); // auto reset event
|
||||
if(m_hevent == NULL)
|
||||
goto error;
|
||||
|
||||
// Create thread for playback
|
||||
m_hthread = (HANDLE)_beginthreadex(NULL, 0, InitialThreadProc, this, CREATE_SUSPENDED, &m_thread_id);
|
||||
if(m_hthread == NULL)
|
||||
goto error;
|
||||
|
||||
m_channels = channels;
|
||||
m_samplerate = samplerate;
|
||||
|
||||
m_callback = callback;
|
||||
|
||||
memset(m_sample_block, NULL, PLAY_SAMPLE_BLOCK_LEN);
|
||||
m_sample_block_size = 0;
|
||||
|
||||
SetThreadPriority(m_hthread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
ResumeThread(m_hthread);
|
||||
|
||||
return S_OK;
|
||||
|
||||
error:
|
||||
Close();
|
||||
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Close sound device.
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CBandiVideoSound_DS::Close()
|
||||
{
|
||||
HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hthread, 0);
|
||||
if(hThread)
|
||||
{
|
||||
if(m_hevent) SetEvent(m_hevent);
|
||||
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
|
||||
if(m_hevent)
|
||||
{
|
||||
CloseHandle(m_hevent);
|
||||
m_hevent = NULL;
|
||||
}
|
||||
|
||||
if(m_crit_sec_inited)
|
||||
{
|
||||
DeleteCriticalSection(&m_crit_sec);
|
||||
m_crit_sec_inited = FALSE;
|
||||
}
|
||||
|
||||
if(m_dsb_secondary)
|
||||
{
|
||||
m_dsb_secondary->Release();
|
||||
m_dsb_secondary = NULL;
|
||||
}
|
||||
|
||||
if(m_dsb_primary)
|
||||
{
|
||||
m_dsb_primary->Release();
|
||||
m_dsb_primary = NULL;
|
||||
}
|
||||
|
||||
if(m_ds)
|
||||
{
|
||||
m_ds->Release();
|
||||
m_ds = NULL;
|
||||
}
|
||||
|
||||
if(m_hwnd)
|
||||
{
|
||||
DestroyWindow(m_hwnd);
|
||||
UnregisterClass(BVL_DSWND_CLASS_NAME, m_hinst);
|
||||
m_hwnd = NULL;
|
||||
}
|
||||
|
||||
m_channels = m_samplerate = 0;
|
||||
m_last_write_pos = 0;
|
||||
m_inbuf_samples = m_total_samples = 0;
|
||||
m_cur_play_time = 0;
|
||||
|
||||
m_playing = FALSE;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Start
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::Start()
|
||||
{
|
||||
EnterCriticalSection(&m_crit_sec);
|
||||
|
||||
m_playing = TRUE;
|
||||
|
||||
LeaveCriticalSection(&m_crit_sec);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Stop
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::Stop()
|
||||
{
|
||||
EnterCriticalSection(&m_crit_sec);
|
||||
|
||||
m_playing = FALSE;
|
||||
|
||||
if(m_dsb_secondary)
|
||||
{
|
||||
BYTE *pbData = NULL;
|
||||
BYTE *pbData2 = NULL;
|
||||
DWORD dwLength=0;
|
||||
DWORD dwLength2=0;
|
||||
|
||||
m_dsb_secondary->Stop();
|
||||
m_dsb_secondary->SetCurrentPosition(0);
|
||||
|
||||
// Lock DirectSound buffer
|
||||
m_dsb_secondary->Lock(0, m_outbuf_size_max, (void**)&pbData, &dwLength, (void**)&pbData2, &dwLength2, 0);
|
||||
|
||||
if(pbData) memset(pbData, 0, dwLength);
|
||||
if(pbData2) memset(pbData2, 0, dwLength2);
|
||||
|
||||
// Unlock the buffer
|
||||
m_dsb_secondary->Unlock(pbData, dwLength, pbData2, dwLength2);
|
||||
|
||||
m_last_write_pos = 0;
|
||||
m_total_samples = m_inbuf_samples = 0;
|
||||
m_cur_play_time = 0;
|
||||
|
||||
memset(m_sample_block, NULL, PLAY_SAMPLE_BLOCK_LEN);
|
||||
m_sample_block_size = 0;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&m_crit_sec);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Stop
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::Pause(BOOL pause)
|
||||
{
|
||||
EnterCriticalSection(&m_crit_sec);
|
||||
|
||||
if(pause)
|
||||
{
|
||||
m_playing = FALSE;
|
||||
if(m_dsb_secondary) m_dsb_secondary->Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_playing = TRUE;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&m_crit_sec);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Get play time (100nsec units)
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::GetTime(INT64 &time)
|
||||
{
|
||||
EnterCriticalSection(&m_crit_sec);
|
||||
|
||||
time = m_cur_play_time;
|
||||
|
||||
|
||||
LeaveCriticalSection(&m_crit_sec);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Set sound volume
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::SetVolume(INT volume)
|
||||
{
|
||||
if(m_dsb_secondary == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
double lfPower10 = pow(10.0,-10.0); // 10^(-10);
|
||||
double lfVolume = (1 - lfPower10)*((double)volume/255) + lfPower10;
|
||||
|
||||
lfVolume = 10*log10(lfVolume);
|
||||
lfVolume *= 300;
|
||||
|
||||
if(lfVolume < -10000)
|
||||
lfVolume = -10000;
|
||||
|
||||
return m_dsb_secondary->SetVolume((LONG)lfVolume);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// ThreadProc
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
UINT CBandiVideoSound_DS::ThreadProc()
|
||||
{
|
||||
BOOL bWorking = FALSE;
|
||||
while(m_hthread)
|
||||
{
|
||||
EnterCriticalSection(&m_crit_sec);
|
||||
{
|
||||
if(m_playing)
|
||||
PlayDS();
|
||||
}
|
||||
LeaveCriticalSection(&m_crit_sec);
|
||||
|
||||
WaitForSingleObject(m_hevent, 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Play DirectSound
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HRESULT CBandiVideoSound_DS::PlayDS()
|
||||
{
|
||||
HRESULT hr;
|
||||
int sample_bytes = m_channels*sizeof(INT16);
|
||||
DWORD free_buffer_size = GetFreeBufferSize();
|
||||
|
||||
// Update play position
|
||||
m_inbuf_samples = (m_outbuf_size_max - free_buffer_size)/(m_channels*sizeof(INT16));
|
||||
m_cur_play_time = max((m_total_samples - m_inbuf_samples)*10000000i64/m_samplerate, 0);
|
||||
|
||||
// Transfer PCM data to Direct Sound Buffer
|
||||
if(m_callback)
|
||||
{
|
||||
void *lock1_ptr = NULL;
|
||||
void *lock2_ptr = NULL;
|
||||
DWORD lock1_bytes = 0;
|
||||
DWORD lock2_bytes = 0;
|
||||
|
||||
if(m_sample_block_size < PLAY_SAMPLE_BLOCK_LEN)
|
||||
{
|
||||
int req_samples = (PLAY_SAMPLE_BLOCK_LEN-m_sample_block_size)/sample_bytes;
|
||||
int get_samples = m_callback->GetPcmData((INT16*)(&m_sample_block[m_sample_block_size]), req_samples);
|
||||
m_sample_block_size += get_samples*sample_bytes;
|
||||
}
|
||||
|
||||
if(m_sample_block_size == PLAY_SAMPLE_BLOCK_LEN && m_sample_block_size <= free_buffer_size)
|
||||
{
|
||||
hr = m_dsb_secondary->Lock(m_last_write_pos, m_sample_block_size,
|
||||
&lock1_ptr, &lock1_bytes,
|
||||
&lock2_ptr, &lock2_bytes, 0);
|
||||
|
||||
if(hr == DSERR_BUFFERLOST)
|
||||
{
|
||||
m_dsb_secondary->Restore();
|
||||
hr = m_dsb_secondary->Lock(m_last_write_pos, m_sample_block_size,
|
||||
&lock1_ptr, &lock1_bytes,
|
||||
&lock2_ptr, &lock2_bytes, 0);
|
||||
}
|
||||
|
||||
if(FAILED(hr)) return hr;
|
||||
|
||||
if(lock1_ptr) memcpy(lock1_ptr, m_sample_block, lock1_bytes);
|
||||
if(lock2_ptr) memcpy(lock2_ptr, m_sample_block+lock1_bytes, lock2_bytes);
|
||||
|
||||
m_dsb_secondary->Unlock(lock1_ptr, lock1_bytes, lock2_ptr, lock2_bytes);
|
||||
|
||||
// Update Write Pointer
|
||||
m_total_samples += m_sample_block_size/sample_bytes;
|
||||
m_last_write_pos += m_sample_block_size;
|
||||
if (INT(m_last_write_pos) >= m_outbuf_size_max)
|
||||
m_last_write_pos = m_last_write_pos - m_outbuf_size_max;
|
||||
|
||||
m_sample_block_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// PLAYBACK control
|
||||
DWORD dsb_status;
|
||||
m_dsb_secondary->GetStatus(&dsb_status);
|
||||
if((dsb_status & DSBSTATUS_PLAYING) == 0)
|
||||
{
|
||||
if (m_inbuf_samples >= m_outbuf_size_min)
|
||||
{
|
||||
m_dsb_secondary->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// Get amount of free data in the buffer
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DWORD CBandiVideoSound_DS::GetFreeBufferSize()
|
||||
{
|
||||
if(m_dsb_secondary == NULL) return 0;
|
||||
|
||||
if(m_total_samples == 0)
|
||||
return m_outbuf_size_max;
|
||||
|
||||
DWORD play_pos;
|
||||
DWORD free_buffer_size = 0;
|
||||
if(SUCCEEDED(m_dsb_secondary->GetCurrentPosition(&play_pos, NULL)))
|
||||
{
|
||||
if(m_last_write_pos > play_pos)
|
||||
free_buffer_size = (m_outbuf_size_max - m_last_write_pos) + play_pos;
|
||||
else
|
||||
free_buffer_size = play_pos - m_last_write_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
free_buffer_size = m_outbuf_size_max;
|
||||
}
|
||||
|
||||
return free_buffer_size;
|
||||
}
|
||||
Reference in new issue
Block a user