|
Hi,
I posted the "A Minor Bug" note, way back in August 2002 (was it really that long ago ?!?)
Came back to my old code which used CWaveform, found that is was stalling, just as Star Fish noted.
Installed the new version.
*BANG*, CWaveform::Open() fails when given WAVE_FORM_FLOW_OUT as the uDirection parameter. The problem is this line:
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
If the param is not WAVE_FORM_FLOW_IN, the code falls through to the "Wave In Object Is Not Initialized" MessageBox. The code which handles WAVE_FORM_FLOW_OUT can *never* be reached !!!
Easily enough fixed, but amazing that nobody has picked it up.
Also, it might help people like aks-74 to note that you may need to add
#include <afxtempl.h>.
Regards,
Mike
|
|
|
|
|
The dog ate my homework - or rather, the codeproject.com HTML editor munched that #include line - it took the contents as being HTML. Yes, I should have previewed my post.
Second try:
Also, it might help people like aks-74 to note that you may need to add
#include <afxtempl.h>
Mike
|
|
|
|
|
How can i handle this problem?
What is wrong?
I use Vs2005. I try win form c++ application.
|
|
|
|
|
New version is unloaded. Based on inputs from many other developers, following bugs are fixed.
1. Potential memory leak
2. Microphone is disable when setting wave in volume
3. Dead-lock may happen when processing wave_in or wave_out data
Skeeter
MCP, MCP+I, MCSE, MCSD & MCDBA
|
|
|
|
|
Changes with non standart library classes (like CList) made build problems.
Old version based on WinAPI and standard C++ libs was more universal.
Sorry for my english )
|
|
|
|
|
Many thanks to all of you for the good comments/inputs, especially to star fish. I had suffering personal affairs in the past few years. Now things were solved and I am able back to work. I am studying the code revised by star fish and post a new version of CWaveForm in a short period.
Skeeter
MCP, MCP+I, MCSE, MCSD & MCDBA
|
|
|
|
|
when call mixerSetControlDetails(...) in CWaveForm::SetVolume() with MIXERCONTROLDETAILS_BOOLEAN microphone set disabled
|
|
|
|
|
Thanks a lot for reporting this bug. I have fixed it by retrieving control details first and then set back only the one interested. I will check in the code as soon as possible.
Skeeter
MCP, MCP+I, MCSE, MCSD & MCDBA
|
|
|
|
|
just to warn you there are many issues with this application:
1) callback proc
- you cannot call a wave*** function from within a callback proc
- doing so may - and does - result in deadlock
- this application makes many calls to such functions
- the callback must signal an event - or a new notification method should be devised
2) unprepare header
- this application does not properly-and timely unprepare the headers of the waiting and free lists
- the poor timing in calling waveinreset followed by waveinstop may - and often does - result in a hang.
- one must wait for all the buffers to be returned from the wave device before calling close.
3) the error noted below "A minor bug" must also be applied to the wavein counter part
4) simply do not call ::waveinclose as there are hang issues
suffice to call ::waveinreset
i will try and post a reworked version which appears to function smoothly (or at least smoother).
52,115
|
|
|
|
|
Here is my implementation of this application with modifications. This implementation is specific for my needs. You will have to discover the changes. Sorry, I am not maintaining this, I just fixed the code for my own use. It does run smoother and hanging issues are resolved.
quickly:
- callback proc now adds wave frames to a processlist and signals an event
- the event feeds the wave frames to the OnWaveInData() and OnWaveOutDone() methods
- the waitlist and freelist headers are now unprepared in a timely fashion
- "a minor bug" from below is fixed
// header file
//---------------------------------------------------------------------
/*
+===========================================================================+
| Notes: |
| |
| 1. Wave device sequence : open()->start()->stop()->close(). |
| 2. Support seperate operation on wave in and out object. |
| |
+===========================================================================+
*/
#ifndef _WAVEFORM_H_
#define _WAVEFORM_H_
#include "WaveInterface.h"
#include <Mmsystem.h>
#include <Mmreg.h>
#include <Msacm.h>
/****************************************************************************
* Limitation for number of wave buffer can be queued in list.
****************************************************************************
*/
#define MIN_WAVE_NUM 4
#define MAX_WAVE_NUM 8
#define MAX_WAVE_BUFFER_LEN 8192
#define MAX_BUFFER_IN_QUEUE MAX_WAVE_BUFFER_LEN * (MAX_WAVE_NUM / 2)
#define WAVE_FORM_FLOW_IN 0x00000001
#define WAVE_FORM_FLOW_OUT 0x00000002
#define WAVE_FORM_FLOW_BOTH 0x00000003
#define VALIDATE(x,y) x > y ? (x = y) : (y = x)
/****************************************************************************
* External messages borrowed from [Thread.h].
****************************************************************************
*/
#define WM_STREAM_NOTIFY WM_USER + 1
#define SUB_EVENT_WAVE_IN 0x00000001
#define SUB_EVENT_SOCKET_IN 0x00000002
#define WM_STREAM_CONTROL WM_USER + 2
#define SUB_EVENT_WAVE_QUIT 0x00000001
#define SUB_EVENT_SOCKET_QUIT 0x00000002
/****************************************************************************
* Internal wave frame structure.
****************************************************************************
*/
typedef struct stWaveFrame
{
WAVEHDR waveHdr;
CHAR Data[MAX_WAVE_BUFFER_LEN];
} WAVEFRAME, *PWAVEFRAME;
#define PPWAVEFRAME PWAVEFRAME *
/****************************************************************************
* Wave device state.
****************************************************************************
*/
#define WAVE_STATE_OPEN 0x0001
#define WAVE_STATE_CLOSE 0x0002
#define WAVE_STATE_START 0x0003
#define WAVE_STATE_STOP 0x0004
#define WAVE_STATE_RESET 0x0005
#define WAVE_STATE_PAUSE 0x0006
#define WAVE_STATE_RESTART 0x0007
/****************************************************************************
* Wave device callback routines.
****************************************************************************
*/
static void CALLBACK WaveInCallBackRoutine
(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
static void CALLBACK WaveOutCallBackRoutine
(
HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
/****************************************************************************
* CWaveForm class definition.
****************************************************************************
*
*/
class CWaveForm : public IIUnknown,
public IIStreamDevice,
public IIDataSource<PWAVEFRAME>,
public IIDataSink<PWAVEFRAME>,
public CAdvise
{
public:
CWaveForm
(
UINT uDirection,
UINT uWaveInDeviceID,
UINT uWaveOutDeviceID,
WAVEFORMATEX * lpWaveInFormatEx,
WAVEFORMATEX * lpWaveOutFormatEx,
DWORD dwWaveInVolume,
DWORD dwWaveOutVolume
);
~CWaveForm();
/////////////////////////////////////////////////////////////////////////
// Standard interface implementation.
/////////////////////////////////////////////////////////////////////////
IMP_IIUNKNOWN();
IMP_IISTREAMDEVICE();
IMP_IIDATASOURCE(PWAVEFRAME);
IMP_IIDATASINK(PWAVEFRAME);
/////////////////////////////////////////////////////////////////////////
// WaveForm spefific APIs.
/////////////////////////////////////////////////////////////////////////
BOOL GetVolume(UINT uDirection, PDWORD pVolume);
BOOL SetVolume(UINT uDirection, DWORD dwVolume);
void OnWaveInData(PWAVEFRAME waveFrame);
void OnWaveOutDone(PWAVEFRAME waveFrame);
void WaveInProcess();
void WaveOutProcess();
bool SetOutput( DWORD dwVolume );
void SelectSource(char *sourcename);
bool SetMasterVolume( DWORD dwVolume );
UINT32 GetWaitCount() { return (UINT32)m_waveInFrameWaitingList.GetCount(); }
UINT32 GetMaxWaveNum() { return MAX_WAVE_NUM;}
BOOL SoundCardCheck();
BOOL isInSupported (UINT idDev,WAVEFORMATEX * lpWaveInFormatEx);
private:
static void __cdecl ThreadProcIn(void *) ;
static void __cdecl ThreadProcOut(void *) ;
bool m_bWaveInProcessFlag;
bool m_bWaveOutProcessFlag;
bool m_bWaveInProcessState;
bool m_bWaveOutProcessState;
HANDLE m_hWaveInProcessEvent;
HANDLE m_hWaveOutProcessEvent;
HANDLE m_hWaveInProcessThread;
HANDLE m_hWaveOutProcessThread;
private:
LONG m_RefCount;
UINT m_uDirection;
UINT m_waveInState;
UINT m_waveOutState;
UINT m_waveInDeviceID;
UINT m_waveOutDeviceID;
WAVEFORMATEX m_waveInFormatEx;
WAVEFORMATEX m_waveOutFormatEx;
HWAVEIN m_hWaveIn;
HWAVEOUT m_hWaveOut;
DWORD m_waveInVolume;
DWORD m_waveOutVolume;
DWORD m_dwWaveInByteInDevice;
DWORD m_dwWaveOutByteInDevice;
CRITICAL_SECTION m_waveInFrameFreeListLock;
CRITICAL_SECTION m_waveInFrameWaitingListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveInFrameFreeList;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveInFrameWaitingList;
CRITICAL_SECTION m_waveOutFrameFreeListLock;
CRITICAL_SECTION m_waveOutFrameWaitingListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveOutFrameFreeList;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveOutFrameWaitingList;
CRITICAL_SECTION m_waveInFrameProcessListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveInFrameProcessList;
CRITICAL_SECTION m_waveOutFrameProcessListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveOutFrameProcessList;
friend static void CALLBACK WaveInCallBackRoutine
(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
friend static void CALLBACK WaveOutCallBackRoutine
(
HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
};
#endif // _WAVEFORM_H_
// implementation file
//---------------------------------------------------------------------
/*
+===========================================================================+
| Notes: |
| |
| 1. Wave device open sequence : open()->start()->stop()->close(). |
| 2. Support seperate operation on wave in and out object. |
| 3. Use standard stream device interface. |
| |
+===========================================================================+
*/
#include "Stdafx.h"
#include "WaveForm.h"
#include <string>
/****************************************************************************
* CWaveForm::CWaveForm()
****************************************************************************
* CWaveForm constructor.
*/
CWaveForm::CWaveForm
(
UINT uDirection,
UINT uWaveInDeviceID,
UINT uWaveOutDeviceID,
WAVEFORMATEX * lpWaveInFormatEx,
WAVEFORMATEX * lpWaveOutFormatEx,
DWORD dwWaveInVolume,
DWORD dwWaveOutVolume
)
{
/////////////////////////////////////////////////////////////////////////
// Init wave format related variables.
/////////////////////////////////////////////////////////////////////////
m_RefCount = 0;
/////////////////////////////////////////////////////////////////////////
// Preset wave in/out device info.
/////////////////////////////////////////////////////////////////////////
m_uDirection = uDirection;
m_waveInDeviceID = uWaveInDeviceID;
m_waveOutDeviceID = uWaveOutDeviceID;
if ((m_uDirection & WAVE_FORM_FLOW_IN) && (lpWaveInFormatEx != NULL))
{
memcpy(&m_waveInFormatEx, lpWaveInFormatEx, sizeof(WAVEFORMATEX));
}
if ((m_uDirection & WAVE_FORM_FLOW_OUT) && (lpWaveOutFormatEx != NULL))
{
memcpy(&m_waveOutFormatEx, lpWaveOutFormatEx, sizeof(WAVEFORMATEX));
}
m_hWaveIn = NULL;
m_hWaveOut = NULL;
m_waveInState = WAVE_STATE_CLOSE;
m_waveOutState = WAVE_STATE_CLOSE;
/////////////////////////////////////////////////////////////////////////
// Init wave in critical section locks & free list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_IN)
{
InitializeCriticalSection(&m_waveInFrameFreeListLock);
InitializeCriticalSection(&m_waveInFrameWaitingListLock);
InitializeCriticalSection(&m_waveInFrameProcessListLock);
// Preallocate some wave in free frames.
EnterCriticalSection(&m_waveInFrameFreeListLock);
for (UINT i = 0; i < MIN_WAVE_NUM; i++)
{
PWAVEFRAME waveFrame = new WAVEFRAME;
if (waveFrame)
{
m_waveInFrameFreeList.AddTail(waveFrame);
}
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
//Create an event for the process thread to wait on
m_hWaveInProcessEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
}
/////////////////////////////////////////////////////////////////////////
// Init wave out critical section locks & free list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_OUT)
{
InitializeCriticalSection(&m_waveOutFrameFreeListLock);
InitializeCriticalSection(&m_waveOutFrameWaitingListLock);
InitializeCriticalSection(&m_waveOutFrameProcessListLock);
//Create an event for the process thread to wait on
m_hWaveOutProcessEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
}
/////////////////////////////////////////////////////////////////////////
// Save wave in/out volumes.
/////////////////////////////////////////////////////////////////////////
m_waveInVolume = dwWaveInVolume;
m_waveOutVolume = dwWaveOutVolume;
/////////////////////////////////////////////////////////////////////////
// Set the process flags to false
/////////////////////////////////////////////////////////////////////////
m_bWaveInProcessFlag = false;
m_bWaveOutProcessFlag = false;
m_bWaveInProcessState = false;
m_bWaveOutProcessState = false;
/////////////////////////////////////////////////////////////////////////
// Setup wave in/out outstanding monitor.
/////////////////////////////////////////////////////////////////////////
m_dwWaveInByteInDevice = 0;
m_dwWaveOutByteInDevice = 0;
}
/****************************************************************************
* CWaveForm::~CWaveForm()
****************************************************************************
* CWaveForm destructor.
*/
CWaveForm::~CWaveForm()
{
/////////////////////////////////////////////////////////////////////////
// Delete wave in list lock & free free/waiting list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_IN)
{
DeleteCriticalSection(&m_waveInFrameFreeListLock);
DeleteCriticalSection(&m_waveInFrameWaitingListLock);
DeleteCriticalSection(&m_waveInFrameProcessListLock);
while (!m_waveInFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameFreeList.RemoveHead();
delete waveFrame;
}
while (!m_waveInFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameWaitingList.RemoveHead();
delete waveFrame;
}
while (!m_waveInFrameProcessList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameProcessList.RemoveHead();
delete waveFrame;
}
// close handles
CloseHandle(m_hWaveInProcessEvent);
CloseHandle(m_hWaveInProcessThread);
}
/////////////////////////////////////////////////////////////////////////
// Delete wave out list lock & free free/waiting list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_OUT)
{
DeleteCriticalSection(&m_waveOutFrameFreeListLock);
DeleteCriticalSection(&m_waveOutFrameWaitingListLock);
DeleteCriticalSection(&m_waveOutFrameProcessListLock);
while (!m_waveOutFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameFreeList.RemoveHead();
delete waveFrame;
}
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameWaitingList.RemoveHead();
delete waveFrame;
}
while (!m_waveOutFrameProcessList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameProcessList.RemoveHead();
delete waveFrame;
}
// close handles
CloseHandle(m_hWaveOutProcessEvent);
CloseHandle(m_hWaveOutProcessThread);
}
}
/****************************************************************************
* CWaveForm::AddRef()
****************************************************************************
* Increase reference count.
*/
long
CWaveForm::AddRef()
{
::InterlockedIncrement(&m_RefCount);
return m_RefCount;
}
/****************************************************************************
* CWaveForm::Release()
****************************************************************************
* Decrease reference count, if 0, delete object.
*/
long
CWaveForm::Release()
{
if (::InterlockedDecrement(&m_RefCount) == 0)
{
delete this;
return 0;
}
return m_RefCount;
}
/****************************************************************************
* CWaveForm::Open()
****************************************************************************
* Open wave in/out device.
*/
BOOL
CWaveForm::Open
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Try to open wave in device, which support requested wave format.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
if (m_waveInState == WAVE_STATE_CLOSE)
{
ret = ::waveInOpen
(
&m_hWaveIn,
WAVE_MAPPER, //m_waveInDeviceID,
&m_waveInFormatEx,
DWORD(WaveInCallBackRoutine),
DWORD(this),
CALLBACK_FUNCTION
);
if (ret == MMSYSERR_NOERROR)
{
m_waveInState = WAVE_STATE_OPEN;
// set volume of waveOut device
SetVolume(WAVE_FORM_FLOW_IN, m_waveInVolume);
SetMasterVolume( m_waveOutVolume );
// set volume of waveIn device
SetOutput( m_waveInVolume );
}
}
else
{
// This object doesn't support request wave device or already opened.
::MessageBox
(
NULL,
_T("Fail to open Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Try to open wave out device, which support requested wave format.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
if (m_waveOutState == WAVE_STATE_CLOSE)
{
ret = ::waveOutOpen
(
&m_hWaveOut,
m_waveOutDeviceID,
&m_waveOutFormatEx,
DWORD(WaveOutCallBackRoutine),
DWORD(this),
CALLBACK_FUNCTION
);
if (ret == MMSYSERR_NOERROR)
{
m_waveOutState = WAVE_STATE_OPEN;
DWORD NewVolume = 2621480000;
SetVolume(WAVE_FORM_FLOW_OUT, NewVolume);
}
}
else
{
// This object doesn't support request wave device or already opened.
::MessageBox
(
NULL,
_T("Fail to open Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::Close()
****************************************************************************
* Close wave in/out device.
*/
BOOL
CWaveForm::Close
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Try to close wave in device.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
if (m_waveInState == WAVE_STATE_STOP)
{
// Check wave in waiting frame list.
if (m_hWaveIn)
{
// unprepare wavein waiting list headers
while (!m_waveInFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
// unprepare wavein free list headers
while (!m_waveInFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameFreeList.RemoveHead();
if (waveFrame)
{
ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
::waveInClose(m_hWaveIn);
m_hWaveIn = NULL;
m_waveInState = WAVE_STATE_CLOSE;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to close Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
TCHAR szText[MAXERRORLENGTH + 1] = {'\0'};
waveInGetErrorText(ret,szText,MAXERRORLENGTH);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Try to close wave out device.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
if (m_waveOutState == WAVE_STATE_STOP)
{
// Check wave out waiting frame list.
if (m_hWaveOut)
{
// unprepare wave out waitlist headers
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
/// unprepare waveout freelist headers
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
::waveOutClose(m_hWaveOut);
m_hWaveOut = NULL;
m_waveOutState = WAVE_STATE_CLOSE;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to close Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::Start()
****************************************************************************
* Start wave device.
*/
BOOL
CWaveForm::Start
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Start wave in stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
// create a thread which will wait on the waveInProcessEvent and process the incoming buffers
m_bWaveInProcessFlag = true;
m_hWaveInProcessThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CWaveForm::ThreadProcIn, (LPVOID)this, 0, 0);
if (m_waveInState == WAVE_STATE_OPEN)
{
if (m_hWaveIn)
{
while (!m_waveInFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameFreeList.RemoveHead();
if (waveFrame)
{
waveFrame->waveHdr.lpData = waveFrame->Data;
waveFrame->waveHdr.dwBufferLength = MAX_WAVE_BUFFER_LEN;
waveFrame->waveHdr.dwBytesRecorded = 0;
waveFrame->waveHdr.dwFlags = 0;
waveFrame->waveHdr.dwLoops = 0;
waveFrame->waveHdr.dwUser = 0;
waveFrame->waveHdr.lpNext = 0;
ret = ::waveInPrepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
ret = ::waveInAddBuffer
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
m_dwWaveInByteInDevice += waveFrame->waveHdr.dwBufferLength;
}
}
ret = ::waveInStart(m_hWaveIn);
m_waveInState = WAVE_STATE_START;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to start Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Start wave out stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
// create a thread which will wait on the waveInProcessEvent and process the incoming buffers
m_bWaveOutProcessFlag = true;
m_hWaveOutProcessThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CWaveForm::ThreadProcOut, (LPVOID)this, 0, 0);
if (m_waveOutState == WAVE_STATE_OPEN)
{
if (m_hWaveOut)
{
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = NULL;
waveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveOutWrite
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
m_dwWaveOutByteInDevice += waveFrame->waveHdr.dwBufferLength;
}
}
m_waveOutState = WAVE_STATE_START;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to start Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::Stop()
****************************************************************************
* Stop wave device.
*/
BOOL
CWaveForm::Stop
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Stop wave in stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
if (m_waveInState == WAVE_STATE_START)
{
if (m_hWaveIn)
{
m_waveInState = WAVE_STATE_RESET;
ret = ::waveInReset(m_hWaveIn);
// allow buffers to be returned via the callback function (WIM_DATA messages)
// waveInReset results in a message for each outstanding buffer
while(m_dwWaveInByteInDevice > 0)
Sleep(100);
// release the wavein process thread
m_bWaveInProcessFlag = false;
SetEvent(m_hWaveInProcessEvent);
// the waveInStop call is causing certain boxes to block (hang)
// waveInStop causes outstanding buffers to be filled with 0's
// these buffers cannot be unprepared??
// it is not neccessary to call waveInStop
// on exit m_waveInState must be set to WAVE_STATE_STOP
// or else close will fail
// alternatively the close function can be altered to reflect the desired state
m_waveInState = WAVE_STATE_STOP;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to stop Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
TCHAR szText[MAXERRORLENGTH + 1] = {'\0'};
waveInGetErrorText(ret,szText,MAXERRORLENGTH);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Stop wave out stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
if (m_waveOutState == WAVE_STATE_START)
{
if (m_hWaveOut)
{
m_waveOutState = WAVE_STATE_RESET;
ret = ::waveOutReset(m_hWaveOut);
// allow buffers to be returned via the callback function (WIM_DATA messages)
// waveoutReset results in a message for each outstanding buffer
while(m_dwWaveOutByteInDevice > 0)
Sleep(100);
// release the waveout process thread
m_bWaveOutProcessFlag = false;
SetEvent(m_hWaveOutProcessEvent);
m_waveOutState = WAVE_STATE_STOP;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to stop Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::GetVolume()
****************************************************************************
* Get wave form volume.
*/
BOOL
CWaveForm::GetVolume
(
UINT uDirection,
PDWORD pVolume
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
if (uDirection & WAVE_FORM_FLOW_IN)
{
if (m_hWaveIn)
{
HMIXER hMixer = NULL;
ret = mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
if (ret == MMSYSERR_NOERROR)
{
// Get mixer recording dest line.
MIXERLINE mixerDestLine;
memset(&mixerDestLine, 0, sizeof(MIXERLINE));
mixerDestLine.cbStruct = sizeof(MIXERLINE);
mixerDestLine.dwDestination = 1; // 0 - Playback , 1 - Recording.
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerDestLine,
MIXER_GETLINEINFOF_DESTINATION
);
if (ret == MMSYSERR_NOERROR)
{
// Enumerate mixer recording source lines.
UINT srcConnection = 0;
MIXERLINE mixerSrcLine;
for (; srcConnection < mixerDestLine.cConnections; srcConnection++)
{
memset(&mixerSrcLine, 0, sizeof(MIXERLINE));
mixerSrcLine.cbStruct = sizeof(MIXERLINE);
mixerSrcLine.dwDestination = 1; // 0 - Playback , 1 - Recording.
mixerSrcLine.dwSource = srcConnection;
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerSrcLine,
MIXER_GETLINEINFOF_SOURCE
);
if (mixerSrcLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
{
MIXERCONTROL mixerMicVolumeControl;
memset(&mixerMicVolumeControl, 0, sizeof(MIXERCONTROL));
mixerMicVolumeControl.cbStruct = sizeof(MIXERCONTROL);
MIXERLINECONTROLS mixerMicLineControls;
memset(&mixerMicLineControls, 0, sizeof(MIXERLINECONTROLS));
mixerMicLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerMicLineControls.dwLineID = mixerSrcLine.dwLineID;
mixerMicLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerMicLineControls.cControls = 1;
mixerMicLineControls.pamxctrl = &mixerMicVolumeControl;
mixerMicLineControls.cbmxctrl = sizeof(MIXERCONTROL);
ret = mixerGetLineControls
(
(HMIXEROBJ)hMixer,
&mixerMicLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE
);
if (ret == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS_UNSIGNED volumeLevel[2];
volumeLevel[0].dwValue = 0;
volumeLevel[1].dwValue = 0;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerMicLineControls.pamxctrl->dwControlID;
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.cChannels = mixerSrcLine.cChannels;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED) * mixerSrcLine.cChannels;
mixerControlDetails.paDetails = volumeLevel;
ret = mixerGetControlDetails
(
(HMIXEROBJ)hMixer,
&mixerControlDetails,
MIXER_GETCONTROLDETAILSF_VALUE
);
*pVolume = volumeLevel[0].dwValue;
*pVolume |= volumeLevel[1].dwValue << 16;
}
break;
}
}
}
ret = mixerClose(hMixer);
}
}
}
if (uDirection & WAVE_FORM_FLOW_OUT)
{
if (m_hWaveOut)
{
ret = waveOutGetVolume(m_hWaveOut, pVolume);
}
}
if (ret == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
* CWaveForm::SetVolume()
****************************************************************************
* Set wave form volume.
*/
BOOL
CWaveForm::SetVolume
(
UINT uDirection,
DWORD dwVolume
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
if (uDirection & WAVE_FORM_FLOW_IN)
{
if (m_hWaveIn)
{
HMIXER hMixer = NULL;
ret = mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
if (ret == MMSYSERR_NOERROR)
{
// Get mixer recording dest line.
MIXERLINE mixerDestLine;
memset(&mixerDestLine, 0, sizeof(MIXERLINE));
mixerDestLine.cbStruct = sizeof(MIXERLINE);
mixerDestLine.dwDestination = 0; // 0 - Playback , 1 - Recording.
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerDestLine,
MIXER_GETLINEINFOF_DESTINATION
);
if (ret == MMSYSERR_NOERROR)
{
// Enumerate mixer recording source lines.
UINT srcConnection = 0;
MIXERLINE mixerSrcLine;
for (; srcConnection < mixerDestLine.cConnections; srcConnection++)
{
memset(&mixerSrcLine, 0, sizeof(MIXERLINE));
mixerSrcLine.cbStruct = sizeof(MIXERLINE);
mixerSrcLine.dwDestination = 0; // 0 - Playback , 1 - Recording.
mixerSrcLine.dwSource = srcConnection;
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerSrcLine,
MIXER_GETLINEINFOF_SOURCE
);
if ( mixerSrcLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT )
{
MIXERCONTROL mixerMicVolumeControl;
memset(&mixerMicVolumeControl, 0, sizeof(MIXERCONTROL));
mixerMicVolumeControl.cbStruct = sizeof(MIXERCONTROL);
MIXERLINECONTROLS mixerMicLineControls;
memset(&mixerMicLineControls, 0, sizeof(MIXERLINECONTROLS));
mixerMicLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerMicLineControls.dwLineID = mixerSrcLine.dwLineID;
mixerMicLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerMicLineControls.cControls = 1;
mixerMicLineControls.pamxctrl = &mixerMicVolumeControl;
mixerMicLineControls.cbmxctrl = sizeof(MIXERCONTROL);
ret = mixerGetLineControls
(
(HMIXEROBJ)hMixer,
&mixerMicLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE
);
if (ret == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS_UNSIGNED volumeLevel[2];
volumeLevel[0].dwValue = dwVolume & 0x0ffff;
volumeLevel[1].dwValue = volumeLevel[0].dwValue;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerMicLineControls.pamxctrl->dwControlID;
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.cChannels = mixerSrcLine.cChannels;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED) * mixerSrcLine.cChannels;
mixerControlDetails.paDetails = volumeLevel;
ret = mixerSetControlDetails
(
(HMIXEROBJ)hMixer,
&mixerControlDetails,
MIXER_SETCONTROLDETAILSF_VALUE
);
m_waveInVolume = dwVolume;
}
break;
} // end if
}// end for
}
ret = mixerClose(hMixer);
}
}
}
if (uDirection & WAVE_FORM_FLOW_OUT)
{
if (m_hWaveOut)
{
ret = waveOutSetVolume(m_hWaveOut, dwVolume);
m_waveOutVolume = dwVolume;
}
}
if (ret == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
* CWaveForm::Read()
****************************************************************************
* Read wave frames in waiting list.
*/
BOOL
CWaveForm::Read
(
PPWAVEFRAME ppwaveFrame
)
{
if (m_waveInState == WAVE_STATE_START)
{
if ((m_uDirection & WAVE_FORM_FLOW_IN) && m_hWaveIn)
{
EnterCriticalSection(&m_waveInFrameWaitingListLock);
if (!m_waveInFrameWaitingList.IsEmpty())
{
*ppwaveFrame = m_waveInFrameWaitingList.RemoveHead();
}
else
{
*ppwaveFrame = NULL;
}
LeaveCriticalSection(&m_waveInFrameWaitingListLock);
return TRUE;
}
}
else
{
*ppwaveFrame = NULL;
}
return FALSE;
}
/****************************************************************************
* CWaveForm::ReadDone()
****************************************************************************
* Return used wave frames.
*/
BOOL
CWaveForm::ReadDone
(
PWAVEFRAME waveFrame
)
{
if (waveFrame)
{
if ((m_uDirection & WAVE_FORM_FLOW_IN) && m_hWaveIn)
{
// Clear used frame.
waveFrame->waveHdr.dwBytesRecorded = 0;
// Reuse it in free list.
EnterCriticalSection(&m_waveInFrameFreeListLock);
m_waveInFrameFreeList.AddTail(waveFrame);
LeaveCriticalSection(&m_waveInFrameFreeListLock);
return TRUE;
}
}
return FALSE;
}
/****************************************************************************
* CWaveForm::Write()
****************************************************************************
* Ask to allocate wave frame.
*/
BOOL
CWaveForm::Write
(
PPWAVEFRAME ppwaveFrame
)
{
if ((m_uDirection & WAVE_FORM_FLOW_OUT) && m_hWaveOut)
{
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (!m_waveOutFrameFreeList.IsEmpty())
{
*ppwaveFrame = m_waveOutFrameFreeList.RemoveHead();
}
else
{
PWAVEFRAME waveFrame = NULL;
waveFrame = new WAVEFRAME;
if (waveFrame)
{
waveFrame->waveHdr.lpData = waveFrame->Data;
waveFrame->waveHdr.dwBufferLength = MAX_WAVE_BUFFER_LEN;
waveFrame->waveHdr.dwBytesRecorded = 0;
waveFrame->waveHdr.dwFlags = 0;
waveFrame->waveHdr.dwLoops = 0;
waveFrame->waveHdr.dwUser = 0;
waveFrame->waveHdr.lpNext = 0;
MMRESULT ret = ::waveOutPrepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
*ppwaveFrame = waveFrame;
}
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
return TRUE;
}
return FALSE;
}
/****************************************************************************
* CWaveForm::Write()
****************************************************************************
* Write data to preallocated wave frame.
*/
BOOL
CWaveForm::Write
(
PWAVEFRAME waveFrame
)
{
if (waveFrame)
{
if (m_waveOutState == WAVE_STATE_START)
{
if ((m_uDirection & WAVE_FORM_FLOW_OUT) && m_hWaveOut)
{
EnterCriticalSection(&m_waveOutFrameWaitingListLock);
// Queue this coming frame.
if (m_waveOutFrameWaitingList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameWaitingList.AddTail(waveFrame);
}
else // Waiting list is full.
{
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (m_waveOutFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameFreeList.AddTail(waveFrame);
}
else // Free list is also full.
{
MMRESULT ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
}
// Fetch new frame from waiting list and send to device.
if (!m_waveOutFrameWaitingList.IsEmpty() &&
(m_dwWaveOutByteInDevice < MAX_BUFFER_IN_QUEUE))
{
PWAVEFRAME newWaveFrame = NULL;
newWaveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (newWaveFrame)
{
MMRESULT ret = ::waveOutWrite
(
m_hWaveOut,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
m_dwWaveOutByteInDevice += newWaveFrame->waveHdr.dwBufferLength;
}
}
LeaveCriticalSection(&m_waveOutFrameWaitingListLock);
return TRUE;
}
}
else
{
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (m_waveOutFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameFreeList.AddTail(waveFrame);
}
else // Free list is full.
{
MMRESULT ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
}
}
return FALSE;
}
/****************************************************************************
* CWaveForm::OnWaveInData()
****************************************************************************
* Wave in data handler.
*/
void
CWaveForm::OnWaveInData
(
PWAVEFRAME waveFrame
)
{
if (m_waveInState != WAVE_STATE_START){
}
/////////////////////////////////////////////////////////////////////////
// Processing recorded wave in frame.
/////////////////////////////////////////////////////////////////////////
if(waveFrame){
if (m_dwWaveInByteInDevice != 0)
{
m_dwWaveInByteInDevice -= waveFrame->waveHdr.dwBufferLength;
}
}
if (m_waveInState == WAVE_STATE_START)
{
if (waveFrame->waveHdr.dwBytesRecorded != 0)
{
EnterCriticalSection(&m_waveInFrameWaitingListLock);
if (m_waveInFrameWaitingList.GetCount() < MAX_WAVE_NUM)
{
m_waveInFrameWaitingList.AddTail(waveFrame);
}
else
{
// Waiting list is full.
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (m_waveInFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
waveFrame->waveHdr.dwBytesRecorded = 0;
m_waveInFrameFreeList.AddTail(waveFrame);
}
else
{
// Free list is also full.
MMRESULT ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
}
LeaveCriticalSection(&m_waveInFrameWaitingListLock);
// Notify client.
Invoke(WM_STREAM_NOTIFY, SUB_EVENT_WAVE_IN, 0);
}
else
{
// else waveFrame->waveHdr.dwBytesRecorded == 0
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (m_waveInFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
waveFrame->waveHdr.dwBytesRecorded = 0;
m_waveInFrameFreeList.AddTail(waveFrame);
}
else // Free list is full.
{
MMRESULT ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
}// end if (waveFrame->waveHdr.dwBytesRecorded != 0)
}
else
{
//else m_waveInState != WAVE_STATE_START
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (m_waveInFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
waveFrame->waveHdr.dwBytesRecorded = 0;
m_waveInFrameFreeList.AddTail(waveFrame);
}
else
{
// Free list is full.
MMRESULT ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
} // end m_waveInState == WAVE_STATE_START
/////////////////////////////////////////////////////////////////////////
// Find new free wave in frame, otherwise allocate a new one.
/////////////////////////////////////////////////////////////////////////
if ((m_waveInState == WAVE_STATE_START) &&
(m_dwWaveInByteInDevice < MAX_BUFFER_IN_QUEUE))
{
MMRESULT ret;
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (!m_waveInFrameFreeList.IsEmpty())
{
newWaveFrame = m_waveInFrameFreeList.RemoveHead();
}
else
{
newWaveFrame = new WAVEFRAME;
if (newWaveFrame)
{
newWaveFrame->waveHdr.lpData = newWaveFrame->Data;
newWaveFrame->waveHdr.dwBufferLength = MAX_WAVE_BUFFER_LEN;
newWaveFrame->waveHdr.dwBytesRecorded = 0;
newWaveFrame->waveHdr.dwFlags = 0;
newWaveFrame->waveHdr.dwLoops = 0;
newWaveFrame->waveHdr.dwUser = 0;
newWaveFrame->waveHdr.lpNext = 0;
ret = ::waveInPrepareHeader
(
m_hWaveIn,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
}
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
// Add buffer to wave in device.
if (newWaveFrame)
{
ret = waveInAddBuffer
(
m_hWaveIn,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
m_dwWaveInByteInDevice += newWaveFrame->waveHdr.dwBufferLength;
}
}
if (m_waveInState != WAVE_STATE_START){
}
}
/****************************************************************************
* CWaveForm::OnWaveOutDone()
****************************************************************************
* Wave out done handler.
*/
void
CWaveForm::OnWaveOutDone
(
PWAVEFRAME waveFrame
)
{
/////////////////////////////////////////////////////////////////////////
// Processing used wave out frame.
/////////////////////////////////////////////////////////////////////////
if(waveFrame){
if (m_dwWaveOutByteInDevice != 0)
{
m_dwWaveOutByteInDevice -= waveFrame->waveHdr.dwBufferLength;
}
}
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (m_waveOutFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameFreeList.AddTail(waveFrame);
}
else // Free list is full.
{
MMRESULT ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
/////////////////////////////////////////////////////////////////////////
// If device is running, fetch new data from waiting list.
/////////////////////////////////////////////////////////////////////////
if ((m_waveOutState == WAVE_STATE_START) &&
(m_dwWaveOutByteInDevice < MAX_BUFFER_IN_QUEUE))
{
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveOutFrameWaitingListLock);
if (!m_waveOutFrameWaitingList.IsEmpty())
{
newWaveFrame = m_waveOutFrameWaitingList.RemoveHead();
}
LeaveCriticalSection(&m_waveOutFrameWaitingListLock);
// Write buffer to wave out device.
if (newWaveFrame)
{
MMRESULT ret = ::waveOutWrite
(
m_hWaveOut,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
m_dwWaveOutByteInDevice += newWaveFrame->waveHdr.dwBufferLength;
}
}
if (m_waveOutState != WAVE_STATE_START){
}
}
/****************************************************************************
* WaveInCallBackRoutine()
****************************************************************************
* Wave in callback routine.
*/
void
CALLBACK
WaveInCallBackRoutine
(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
)
{
CWaveForm * that = (CWaveForm *)dwInstance;
PWAVEFRAME waveFrame = NULL;
if (hwi == that->m_hWaveIn)
{
switch (uMsg)
{
case WIM_OPEN:
break;
case WIM_DATA:
EnterCriticalSection(&that->m_waveInFrameProcessListLock);
waveFrame = (PWAVEFRAME)dwParam1;
if (waveFrame)
that->m_waveInFrameProcessList.AddTail(waveFrame);
LeaveCriticalSection(&that->m_waveInFrameProcessListLock);
SetEvent(that->m_hWaveInProcessEvent);
break;
case WIM_CLOSE:
break;
}
}
}
/****************************************************************************
* WaveOutCallBackRoutine()
****************************************************************************
* Wave out call back routine.
*/
void
CALLBACK
WaveOutCallBackRoutine
(
HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
)
{
CWaveForm * that = (CWaveForm *)dwInstance;
PWAVEFRAME waveFrame = NULL;
if (hwo == that->m_hWaveOut)
{
switch (uMsg)
{
case WOM_OPEN:
break;
case WOM_DONE:
EnterCriticalSection(&that->m_waveOutFrameProcessListLock);
waveFrame = (PWAVEFRAME)dwParam1;
if (waveFrame)
that->m_waveOutFrameProcessList.AddTail(waveFrame);
LeaveCriticalSection(&that->m_waveOutFrameProcessListLock);
SetEvent(that->m_hWaveOutProcessEvent);
break;
case WOM_CLOSE:
break;
}
}
}
/****************************************************************************
* CWaveForm::WaveInProcess()
****************************************************************************
* process buffers.
*/
void
CWaveForm::WaveInProcess()
{
m_bWaveInProcessState = true;
while(m_bWaveInProcessFlag){
WaitForSingleObject( m_hWaveInProcessEvent, INFINITE );
while(0 < m_waveInFrameProcessList.GetCount()){
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveInFrameProcessListLock);
newWaveFrame = m_waveInFrameProcessList.RemoveHead();
LeaveCriticalSection(&m_waveInFrameProcessListLock);
OnWaveInData( newWaveFrame );
}
}
m_bWaveInProcessState = false;
}
/****************************************************************************
* CWaveForm::WaveOutProcess()
****************************************************************************
* process buffers.
*/
void
CWaveForm::WaveOutProcess()
{
m_bWaveOutProcessState = true;
while(m_bWaveOutProcessFlag){
WaitForSingleObject( m_hWaveOutProcessEvent, INFINITE );
while(0 < m_waveOutFrameProcessList.GetCount()){
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveOutFrameProcessListLock);
newWaveFrame = m_waveOutFrameProcessList.RemoveHead();
LeaveCriticalSection(&m_waveOutFrameProcessListLock);
OnWaveOutDone( newWaveFrame );
}
}
m_bWaveOutProcessState = false;
}
// -----------------------------------------------------------------------------
void __cdecl CWaveForm::ThreadProcIn(void *data)
{
CWaveForm &pi = *reinterpret_cast<CWaveForm*>(data);
pi.WaveInProcess();
}
// -----------------------------------------------------------------------------
void __cdecl CWaveForm::ThreadProcOut(void *data)
{
CWaveForm &po = *reinterpret_cast<CWaveForm*>(data);
po.WaveOutProcess();
}
bool CWaveForm::SetOutput( DWORD dwVolume ){
MMRESULT ret = MMSYSERR_INVALPARAM;
char * sourceName = "";
bool sourceNameFlag = false;
MIXERLINE mixLine;
HMIXER hMixer = NULL;
ret = mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
MIXERLINE mixerDestLine;
if (ret == MMSYSERR_NOERROR)
{
// Get mixer recording dest line.
memset(&mixerDestLine, 0, sizeof(MIXERLINE));
mixerDestLine.cbStruct = sizeof(MIXERLINE);
mixerDestLine.dwDestination = 1; // 0 - Playback , 1 - Recording.
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerDestLine,
MIXER_GETLINEINFOF_DESTINATION
);
// find the source name for the recording mixer control
// Stereo Mixer, Wave Mixer, or Record Mixer are common
// use a tiered approach
for (UINT iS=0;iS<mixerDestLine.cConnections && !sourceNameFlag;iS++) {
mixLine.cbStruct = sizeof(MIXERLINE);
mixLine.dwDestination = 1;
mixLine.dwSource = (DWORD) iS;
mixerGetLineInfo((HMIXEROBJ)hMixer, (LPMIXERLINE) &mixLine, MIXER_GETLINEINFOF_SOURCE);
const char * wrkStr = "";
int posMixer = false;
bool isMixer = false;
if(mixLine.dwComponentType == 4106){
std::string shortName = mixLine.szShortName;
int posItem = 0;
// try by using explicit control names
std::string tmpShortName = mixLine.szShortName;
wrkStr = "Stereo Mix";
posItem = tmpShortName.find(wrkStr);
bool isStereoMixer = (posMixer > -1 && posMixer < 50);
wrkStr = "Wave Mix";
posItem = tmpShortName.find(wrkStr);
bool isWaveMixer = (posMixer > -1 && posMixer < 50);
wrkStr = "Record Mix";
posItem = tmpShortName.find(wrkStr);
bool isRecordMixer = (posMixer > -1 && posMixer < 50);
if(isStereoMixer || isWaveMixer || isRecordMixer){
sourceName = mixLine.szName;
sourceNameFlag = true;
break;
}
// try line id = 1 and shortName combination
if(!sourceNameFlag){
posMixer = shortName.find("Mix");
isMixer = (posMixer > -1 && posMixer < 50);
if( isMixer && (mixLine.dwLineID == 1)){
sourceName = mixLine.szName;
sourceNameFlag = true;
break;
}
}
// try shortName and elimination combinations
if(!sourceNameFlag){
posMixer = shortName.find("Mix");
isMixer = (posMixer > -1 && posMixer < 50);
wrkStr = "Auxiliary";
posItem = tmpShortName.find(wrkStr);
bool isAux = (posMixer > -1 && posMixer < 50);
wrkStr = "Aux";
posItem = tmpShortName.find(wrkStr);
bool isAux2 = (posMixer > -1 && posMixer < 50);
wrkStr = "Video";
posItem = tmpShortName.find(wrkStr);
bool isVideo = (posMixer > -1 && posMixer < 50);
wrkStr = "IIS";
posItem = tmpShortName.find(wrkStr);
bool isIIS = (posMixer > -1 && posMixer < 50);
bool isWaveMixer = ( isAux || isVideo || isIIS || isAux2 );
if ( isMixer == true && isWaveMixer == true ){
sourceName = mixLine.szName;
sourceNameFlag = true;
break;
}
}
}
}
} // end for mixerDestLine
// if we found a record mixer control
if( sourceNameFlag ){
// Select wave mixer as the recording source.
// Get the line info for the wave in destination line
MIXERLINE mixerLine;
mixerLine.cbStruct = sizeof(mixerLine);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
mixerGetLineInfo((HMIXEROBJ)hMixer, &mixerLine,MIXER_GETLINEINFOF_COMPONENTTYPE);
// Find a LIST control, if any, for the wave in line
LPMIXERCONTROL pMixerControls = (LPMIXERCONTROL)malloc(mixerLine.cControls * sizeof(MIXERCONTROL));
MIXERLINECONTROLS mixerLinectrl = {sizeof mixerLinectrl, mixerLine.dwLineID, 0,mixerLine.cControls, sizeof MIXERCONTROL, pMixerControls};
ret = mixerGetLineControls((HMIXEROBJ) hMixer, &mixerLinectrl,MIXER_GETLINECONTROLSF_ALL);
// Now walk through each control to find a type of LIST control. This
// can be either Mux, Single-select, Mixer or Multiple-select.
DWORD i;
for(i=0; i < mixerLine.cControls; i++)
if (MIXERCONTROL_CT_CLASS_LIST == (pMixerControls[i].dwControlType &MIXERCONTROL_CT_CLASS_MASK))
break;
if (i < mixerLine.cControls)
{
// Found a LIST control
// Check if the LIST control is a Mux or Single-select type
BOOL bOneItemOnly = FALSE;
switch (pMixerControls[i].dwControlType) {
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
bOneItemOnly = TRUE;
}
DWORD cChannels = mixerLine.cChannels, cMultipleItems = 0;
if (MIXERCONTROL_CONTROLF_UNIFORM & pMixerControls[i].fdwControl)
cChannels = 1;
if (MIXERCONTROL_CONTROLF_MULTIPLE & pMixerControls[i].fdwControl)
cMultipleItems = pMixerControls[i].cMultipleItems;
// Get the text description of each item
LPMIXERCONTROLDETAILS_LISTTEXT plisttext = (LPMIXERCONTROLDETAILS_LISTTEXT)malloc(cChannels * cMultipleItems * sizeof(MIXERCONTROLDETAILS_LISTTEXT));
MIXERCONTROLDETAILS mixerControlDetail = {sizeof(mixerControlDetail),pMixerControls[i].dwControlID,cChannels,(HWND)cMultipleItems, sizeof MIXERCONTROLDETAILS_LISTTEXT,(LPVOID) plisttext};
ret = mixerGetControlDetails((HMIXEROBJ)hMixer, &mixerControlDetail,MIXER_GETCONTROLDETAILSF_LISTTEXT);
// Now get the value for each item
LPMIXERCONTROLDETAILS_BOOLEAN plistbool=(LPMIXERCONTROLDETAILS_BOOLEAN)malloc(cChannels * cMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN));
mixerControlDetail.cbDetails = sizeof MIXERCONTROLDETAILS_BOOLEAN;
mixerControlDetail.paDetails = plistbool;
ret = mixerGetControlDetails((HMIXEROBJ)hMixer,&mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
// Select the "Mixer" (sourceName) item
for (DWORD j=0; j<cMultipleItems; j = j + cChannels)
if (0 == strcmp(plisttext[j].szName, sourceName))
// Select it for both left and right channels
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 1;
//else if (bOneItemOnly) ---- deselect the others
else
// Mux or Single-select allows only one item to be selected
// so clear other items as necessary
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 0;
if (ret == MMSYSERR_NOERROR){
// Now actually set the new values in
ret = mixerSetControlDetails((HMIXEROBJ)hMixer, &mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
}
free(pMixerControls);
free(plisttext);
free(plistbool);
} else {
free(pMixerControls);
} // end if mixerLine.cControls
// END Select wave mixer as the recording source.
// Set the volume on the recording source.
MIXERCONTROL mixerMicVolumeControl;
memset(&mixerMicVolumeControl, 0, sizeof(MIXERCONTROL));
mixerMicVolumeControl.cbStruct = sizeof(MIXERCONTROL);
MIXERLINECONTROLS mixerMicLineControls;
memset(&mixerMicLineControls, 0, sizeof(MIXERLINECONTROLS));
mixerMicLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerMicLineControls.dwLineID = mixLine.dwLineID;
mixerMicLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerMicLineControls.cControls = 1;
mixerMicLineControls.pamxctrl = &mixerMicVolumeControl;
mixerMicLineControls.cbmxctrl = sizeof(MIXERCONTROL);
ret = mixerGetLineControls
(
(HMIXEROBJ)hMixer,
&mixerMicLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE
);
if (ret == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS_UNSIGNED volumeLevel[2];
volumeLevel[0].dwValue = dwVolume & 0x0ffff;
volumeLevel[1].dwValue = volumeLevel[0].dwValue;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerMicLineControls.pamxctrl->dwControlID;
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.cChannels = mixLine.cChannels;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED) * mixLine.cChannels;
mixerControlDetails.paDetails = volumeLevel;
ret = mixerSetControlDetails
(
(HMIXEROBJ)hMixer,
&mixerControlDetails,
MIXER_SETCONTROLDETAILSF_VALUE
);
}
ret = mixerClose(hMixer);
} // END if sourceNameFlag
if (ret == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
void CWaveForm::SelectSource(char *sourcename)
{
HMIXER hMixer = NULL;
mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
// Get the line info for the wave in destination line
MIXERLINE mixerLine;
mixerLine.cbStruct = sizeof(mixerLine);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
mixerGetLineInfo((HMIXEROBJ)hMixer, &mixerLine,MIXER_GETLINEINFOF_COMPONENTTYPE);
// Find a LIST control, if any, for the wave in line
LPMIXERCONTROL pMixerControls = (LPMIXERCONTROL)malloc(mixerLine.cControls * sizeof(MIXERCONTROL));
MIXERLINECONTROLS mixerLinectrl = {sizeof mixerLinectrl, mixerLine.dwLineID, 0,mixerLine.cControls, sizeof MIXERCONTROL, pMixerControls};
mixerGetLineControls((HMIXEROBJ) hMixer, &mixerLinectrl,MIXER_GETLINECONTROLSF_ALL);
// Now walk through each control to find a type of LIST control. This
// can be either Mux, Single-select, Mixer or Multiple-select.
DWORD i;
for(i=0; i < mixerLine.cControls; i++)
if (MIXERCONTROL_CT_CLASS_LIST == (pMixerControls[i].dwControlType &MIXERCONTROL_CT_CLASS_MASK))
break;
if (i < mixerLine.cControls)
{ // Found a LIST control
// Check if the LIST control is a Mux or Single-select type
BOOL bOneItemOnly = FALSE;
switch (pMixerControls[i].dwControlType) {
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
bOneItemOnly = TRUE;
}
DWORD cChannels = mixerLine.cChannels, cMultipleItems = 0;
if (MIXERCONTROL_CONTROLF_UNIFORM & pMixerControls[i].fdwControl)
cChannels = 1;
if (MIXERCONTROL_CONTROLF_MULTIPLE & pMixerControls[i].fdwControl)
cMultipleItems = pMixerControls[i].cMultipleItems;
// Get the text description of each item
LPMIXERCONTROLDETAILS_LISTTEXT plisttext =
(LPMIXERCONTROLDETAILS_LISTTEXT)malloc(cChannels * cMultipleItems *
sizeof(MIXERCONTROLDETAILS_LISTTEXT));
MIXERCONTROLDETAILS mixerControlDetail = {sizeof(mixerControlDetail),
pMixerControls[i].dwControlID,cChannels,
(HWND)cMultipleItems, sizeof MIXERCONTROLDETAILS_LISTTEXT,(LPVOID)
plisttext};
mixerGetControlDetails((HMIXEROBJ)hMixer, &mixerControlDetail,
MIXER_GETCONTROLDETAILSF_LISTTEXT);
// Now get the value for each item
LPMIXERCONTROLDETAILS_BOOLEAN plistbool
=(LPMIXERCONTROLDETAILS_BOOLEAN)malloc(cChannels * cMultipleItems *
sizeof(MIXERCONTROLDETAILS_BOOLEAN));
mixerControlDetail.cbDetails = sizeof MIXERCONTROLDETAILS_BOOLEAN;
mixerControlDetail.paDetails = plistbool;
mixerGetControlDetails((HMIXEROBJ)hMixer,
&mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
// Select the "Mixer" item
for (DWORD j=0; j<cMultipleItems; j = j + cChannels)
if (0 == strcmp(plisttext[j].szName, sourcename))
// Select it for both left and right channels
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 1;
//else if (bOneItemOnly) ---- deselect the others
else
// Mux or Single-select allows only one item to be selected
// so clear other items as necessary
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 0;
// Now actually set the new values in
mixerSetControlDetails((HMIXEROBJ)hMixer,
&mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
free(pMixerControls);
free(plisttext);
free(plistbool);
}
else
free(pMixerControls);
mixerClose(hMixer);
}
bool CWaveForm::SetMasterVolume( DWORD dwVolume ){
// set only if audio via ip
// else is set in dial up speaker
MMRESULT result;
HMIXER hMixer;
MIXERLINE ml = {0};
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
MIXERCONTROLDETAILS mcd = {0};
MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
// get a handle to the mixer device
result = mixerOpen(&hMixer, MIXER_OBJECTF_MIXER, 0, 0, 0);
if (MMSYSERR_NOERROR == result)
{
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
// get the speaker line of the mixer device
result = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
if (MMSYSERR_NOERROR == result)
{
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
// get the volume controls associated with the speaker line
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (MMSYSERR_NOERROR == result)
{
mcdu.dwValue = dwVolume;
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
// set the volume
result = mixerSetControlDetails((HMIXEROBJ) hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
if (MMSYSERR_NOERROR == result)
else
printf("wave->setmastervolume->mixerSetControlDetails() failed\n");
}
else
{
printf("wave->setmastervolume->mixerGetLineControls() failed\n");
}
}
else
{
printf("wave->setmastervolume->mixerGetLineInfo() failed\n");
}
mixerClose(hMixer);
}
else
{
printf("wave->setmastervolume->mixerOpen() failed\n");
}
if (result == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
* CWaveForm::SoundCardCheck()
****************************************************************************
* Ensure the system has a working soundcard.
*/
BOOL
CWaveForm::SoundCardCheck()
{
if (waveInGetNumDevs() == 0){
MessageBox (0, "No sound card installed",
"WaveForm", MB_OK);
return false;
}
WAVEINCAPS waveInCaps;
if (waveInGetDevCaps (0,
&waveInCaps,
sizeof(WAVEINCAPS))
!= MMSYSERR_NOERROR)
{
MessageBox (0, "Cannot determine sound card capabilities",
"WaveForm", MB_OK);
return false;
}
return true;
}
/****************************************************************************
* CWaveForm::isInSupported()
****************************************************************************
* Emsure the requested format is supported
*/
BOOL
CWaveForm::isInSupported (UINT idDev, WAVEFORMATEX * lpWaveInFormatEx)
{
MMRESULT result = ::waveInOpen(0, idDev, lpWaveInFormatEx, 0, 0, WAVE_FORMAT_QUERY);
return result == MMSYSERR_NOERROR;
}
// unused functions
UINT CWaveForm::GetDirection(){ return 0;}
void CWaveForm::SetDirection(UINT uDirection){}
BOOL CWaveForm::Reset(UINT uDirection){return FALSE;}
BOOL CWaveForm::Pause(UINT uDirection){return FALSE;}
BOOL CWaveForm::Restart(UINT uDirection){return FALSE;}
|
|
|
|
|
Hi,Skeeter:
I got following questions:
1> i want to transform a wave's format to standard format i needed(such as 8K HZ,16 bit,mono,signed) we can use software Goldwave’s “Effects->Resample”. But are there any classes or functions in VC?
2> we aslo want to transform the standard wave (we get from the first step) to A-Law PCM Signals.
How can I realize that in VC? Can you give me some suggestions or any links?
Thank you very much!
+ + + + + + + + + + + + + + + + + + + + +
Many nights we've prayed with no proof anyone could hear, we were moving moutains long before we knew we could!
Yet now i'm standing here, although we know there's much to fear, hope seemed like summer bird too swiftly flown away ...
There can be miracles! When you believe, though hope is frail, it's hard to kill!
Who knows what miracles, you can achieve! When you believe, somehow you will ...
YOU WILL WHEN YOU BELIEVE
|
|
|
|
|
Hi,
I want to know as what thread.h file to include.
star fish had the same problem, but did not mention the solution later.
Regards.
|
|
|
|
|
just delete the line.
you do not need the thread.h file
|
|
|
|
|
Sorry for this mistake. I removed Thread.h from the latest source code.
Skeeter
MCP, MCP+I, MCSE, MCSD & MCDBA
|
|
|
|
|
I want to know the duration of a wav file. How can I do it in my program? Anybody know about it ?
|
|
|
|
|
Hello,
I am using vc++ 6
Please tell me which thread.h file you are using.
vc++6 does not include thread.h
|
|
|
|
|
mmmmm
nevermind. i figured it out.
nice code!
|
|
|
|
|
how can i convert/create/modify Wav files from WAv to EBU wav format??
tks
Nicola
|
|
|
|
|
Hi!
Does it works with Borland C++ Builder 6.0?
Rodrigue
|
|
|
|
|
A very useful item, thank you.
However, CWaveForm::OnWaveOutDone has an (easily fixed) bug here :
...
else // Free list is full.
{
MMRESULT ret = ::waveOutUnprepareHeader ( ...
delete waveFrame;
}
but a few lines later the deleted waveFrame is referenced :
m_dwWaveOutByteInDevice -= waveFrame->waveHdr.dwBufferLength;
Whoops!
I also found it useful to add (trivial) routines to (a) flush queued output (b) return an indication of whether there was free space in the output queue.
--- Mike
|
|
|
|
|
Hi,
After Recording , lpData of WAVEHDR contains the data.
I had copied the lpData to char *buffer.
Now , I need to store the data in a file.
After writing Header information , I stored the data in the file as char (bytes by bytes).
This works fine for 8 bit (both mono & stereo).
I followed the same method for 16 bit .When I play the stored file ,noise also comes along with the recorded data .
I read from some articles related to WAVE that 16 bit should be stored as short..
If so , How can i store it ???
Else , If you have someother idea ,Please throw light on it.
Thanks
Maria
mariajothi@sdsindia.com
Maria Jothi (Software Engineer)
MAIL-ID:mariajothi@sdsindia.com
|
|
|
|
|
Hi Maria,
I see CWaveForm but I don't understud ...
Here is my problem:
I'm receiving a wave data into a file (8khz/8bit/mono)
(from a recording operation).
I want to play this buffer with a 2 seconds latency over my sound card.
Thank you very much,
Lucian
|
|
|
|
|
Could someone post an example project so i can see this in action?
Thanks,
Steve Guerreri
|
|
|
|
|
Would you please send me a simple dialog-based example
application (source code)?
Best Regards,
chen
yuehui chen
|
|
|
|
|
There is nothing like a demo to sell the features and capabilities of your code. Got any?
|
|
|
|
|