Original Post
Hi! I am attemting to capture sound directly from a mic with direcsound. But i am receiving errors such as: error LNK2001: unresolved external symbol _DXTraceA@20 error LNK2001: unresolved external symbol "public: __thiscall CWaveFile::~CWaveFile(void)" (??1CWaveFile@@QAE@XZ) error LNK2001: unresolved external symbol "public: long __thiscall CWaveFile::Write(unsigned int,unsigned char *,unsigned int *)" (?Write@CWaveFile@@QAEJIPAEPAI@Z) fatal error LNK1120: 3 unresolved externals How can I resolve these errors? I do not know what to do... here is my code:
// CaptureSound.cpp : Defines the entry point for the application.
//
#define STRICT
#include <windows.h>
#include <basetsd.h>
#include <commdlg.h>
#include <mmreg.h>
#include <dxerr9.h>
#include <dsound.h>
#include "resource.h"
#include "DSUtil.h"
#include "DXUtil.h"
//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
HRESULT INITDIRECTSOUND( HWND hDlg, GUID* pDeviceGuid );
HRESULT CreateCaptureBuffer( WAVEFORMATEX* pwfxInput );
HRESULT InitNotifications();
HRESULT StartOrStopRecord(BOOL bStartRecording);
HRESULT RecordCapturedData() ;
HRESULT OnSaveSoundFile( HWND hDlg );
HRESULT FreeDirectSound();
HRESULT OnInitMainDialog( HWND hDlg );
HRESULT OnInitMainDialog( HWND hDlg );INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
#define NUM_REC_NOTIFICATIONS 16
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
LPDIRECTSOUNDCAPTURE dsCapture = NULL;
DSBPOSITIONNOTIFY pPosNotify[ NUM_REC_NOTIFICATIONS + 1 ];
LPDIRECTSOUNDCAPTUREBUFFER g_pDSBCapture = NULL;
DWORD g_dwCaptureBufferSize;
LPDIRECTSOUNDNOTIFY lpDSBNotify = NULL;
LPDIRECTSOUNDNOTIFY g_pDSNotify = NULL;
HANDLE g_hNotificationEvent;
DWORD g_dwNotifySize;
DWORD g_dwNextCaptureOffset;
HINSTANCE g_hInst = NULL;
GUID g_guidCaptureDevice = GUID_NULL;
BOOL g_bRecording;
CWaveFile* g_pWaveFile;
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point for the application. Since we use a simple dialog for
// user interaction we don't need to pump messages.
//-----------------------------------------------------------------------------
INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine,
INT nCmdShow )
{ HRESULT hr;
DWORD dwResult;
MSG msg;
BOOL bDone;
HWND hDlg;
g_hInst = hInst;
g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
// Display the main dialog box.
dwResult = DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc );
if( dwResult != IDOK )
{
// The user canceled, so stop message pump,
// and fall through to the cleanup code
PostQuitMessage( 0 );
}
else
{
// Init DirectSound
if( FAILED( hr = INITDIRECTSOUND( hDlg, &g_guidCaptureDevice ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("InitDirectSound"), hr );
MessageBox( hDlg, "Error initializing DirectSound. Sample will now exit.",
"DirectSound Sample", MB_OK | MB_ICONERROR );
PostQuitMessage( 0 );
dwResult = IDCANCEL;
}
}
bDone = FALSE;
while( !bDone )
{
dwResult = MsgWaitForMultipleObjects( 1, &g_hNotificationEvent,
FALSE, INFINITE, QS_ALLEVENTS );
switch( dwResult )
{
case WAIT_OBJECT_0 + 0:
// g_hNotificationEvents[0] is signaled
// This means that DirectSound just finished playing
// a piece of the buffer, so we need to fill the circular
// buffer with new sound from the wav file
if( FAILED( hr = RecordCapturedData() ) )
{
DXTRACE_ERR_MSGBOX( TEXT("RecordCapturedData"), hr );
MessageBox( hDlg, "Error handling DirectSound notifications. "
"Sample will now exit.", "DirectSound Sample",
MB_OK | MB_ICONERROR );
bDone = TRUE;
}
break;
case WAIT_OBJECT_0 + 1:
// Windows messages are available
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if( !IsDialogMessage( hDlg, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
if( msg.message == WM_QUIT )
bDone = TRUE;
}
break;
}
}
StartOrStopRecord( FALSE );
// Clean up everything
FreeDirectSound();
CloseHandle( g_hNotificationEvent );
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: OnInitDialog()
// Desc: Initializes the dialogs (sets up UI controls, etc.)
//-----------------------------------------------------------------------------
HRESULT OnInitMainDialog( HWND hDlg )
{
//HRESULT hr;
EnableWindow( GetDlgItem( hDlg, IDC_RECORD ), FALSE);
// SetDlgItemText( hDlg, IDC_FILENAME, TEXT("No file loaded.") );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: MainDlgProc()
// Desc: Handles dialog messages
//-----------------------------------------------------------------------------
INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
HRESULT hr;
switch( msg )
{
case WM_INITDIALOG:
OnInitMainDialog( hDlg );
break;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDCANCEL:
PostQuitMessage( 0 );
EndDialog( hDlg, IDCANCEL );
break;
case IDC_SOUNDFILE:
OnSaveSoundFile( hDlg );
break;
case IDC_RECORD:
g_bRecording = !g_bRecording;
if( FAILED( hr = StartOrStopRecord( g_bRecording ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("StartOrStopRecord"), hr );
MessageBox( hDlg, "Error with DirectSoundCapture buffer."
"Sample will now exit.", "DirectSound Sample",
MB_OK | MB_ICONERROR );
PostQuitMessage( 0 );
EndDialog( hDlg, IDABORT );
}
if( !g_bRecording )
EnableWindow( GetDlgItem( hDlg, IDC_RECORD ), FALSE );
break;
default:
return FALSE; // Didn't handle message
}
break;
default:
return FALSE; // Didn't handle message
}
return TRUE; // Handled message
}
HRESULT INITDIRECTSOUND( HWND hDlg, GUID* pDeviceGuid )
{
HRESULT hr;
ZeroMemory( &pPosNotify, sizeof(DSBPOSITIONNOTIFY) *
(NUM_REC_NOTIFICATIONS + 1) );
dsCapture=NULL;
g_dwCaptureBufferSize = 0;
g_dwNotifySize = 0;
g_pWaveFile = NULL;
hr = CoInitialize(NULL);
hr = DirectSoundCaptureCreate(NULL,&dsCapture,NULL);
return IDOK;
}
HRESULT FreeDirectSound()
{
SAFE_DELETE( g_pWaveFile );
// Release DirectSound interfaces
SAFE_RELEASE( g_pDSNotify );
SAFE_RELEASE( g_pDSBCapture );
SAFE_RELEASE( dsCapture );
// Release COM
CoUninitialize();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: OnSaveSoundFile()
// Desc: Called when the user requests to save to a sound file
//-----------------------------------------------------------------------------
HRESULT OnSaveSoundFile( HWND hDlg )
{
HRESULT hr;
static TCHAR strFileName[MAX_PATH] = TEXT("");
static TCHAR strPath[MAX_PATH] = TEXT("");
// Setup the OPENFILENAME structure
OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL,
TEXT("Wave Files\0*.wav\0All Files\0*.*\0\0"), NULL,
0, 1, strFileName, MAX_PATH, NULL, 0, strPath,
TEXT("Save Sound File"),
OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST |
OFN_HIDEREADONLY | OFN_NOREADONLYRETURN,
0, 0, TEXT(".wav"), 0, NULL, NULL };
// Get the default media path (something like C:\WINDOWS\MEDIA)
if( '\0' == strPath[0] )
{
if( GetWindowsDirectory( strPath, MAX_PATH ) != 0 )
{
if( strcmp( &strPath[strlen(strPath)], TEXT("\\") ) )
strcat( strPath, TEXT("\\") );
strcat( strPath, TEXT("MEDIA") );
}
}
if( g_bRecording )
{
// Stop the capture and read any data that
// was not caught by a notification
StartOrStopRecord( FALSE );
g_bRecording = FALSE;
}
/* // Update the UI controls to show the sound as loading a file
EnableWindow( GetDlgItem( hDlg, IDC_RECORD ), FALSE );
SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Saving file...") );
SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
SAFE_DELETE( g_pWaveFile );
g_pWaveFile = new CWaveFile;
if( NULL == g_pWaveFile )*/
return IDOK;
}
HRESULT CreateCaptureBuffer( WAVEFORMATEX* pwfxInput )
{
WAVEFORMATEX wave;
ZeroMemory(&wave,sizeof(WAVEFORMATEX));
wave.wFormatTag = WAVE_FORMAT_PCM;
wave.nChannels = 2;
wave.nSamplesPerSec= 44100;
wave.nAvgBytesPerSec = 44100 * 4;
wave.nBlockAlign = 4;
wave.wBitsPerSample = 16;
wave.cbSize = 0;
SAFE_RELEASE( g_pDSNotify );
SAFE_RELEASE( g_pDSBCapture );
// Set the notification size
g_dwNotifySize = MAX( 1024, pwfxInput->nAvgBytesPerSec / 8 );
g_dwNotifySize -= g_dwNotifySize % pwfxInput->nBlockAlign;
// Set the buffer sizes
g_dwCaptureBufferSize = g_dwNotifySize * NUM_REC_NOTIFICATIONS;
SAFE_RELEASE( g_pDSNotify );
SAFE_RELEASE( g_pDSBCapture );
HRESULT hr;
DSCBUFFERDESC dscbd;
WAVEFORMATEX w;
// Create the capture buffer
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
dscbd.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY;
dscbd.dwBufferBytes = g_dwCaptureBufferSize;
dscbd.lpwfxFormat = pwfxInput; // Set the format during creatation
if( FAILED( hr = dsCapture->CreateCaptureBuffer( &dscbd,
&g_pDSBCapture,
NULL ) ) )
return IDOK;
}
HRESULT InitNotifications()
{
HRESULT hr;
//Set Direct Sound Buffer Notify Position
//g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if( FAILED( hr = g_pDSBCapture->QueryInterface( IID_IDirectSoundNotify,
(VOID**)&g_pDSNotify ) ) )
return IDOK;
for( INT i = 0; i < NUM_REC_NOTIFICATIONS; i++ )
{
pPosNotify.dwOffset = (g_dwNotifySize * i) + g_dwNotifySize - 1;
pPosNotify.hEventNotify = g_hNotificationEvent;
}
if ( FAILED(lpDSBNotify->SetNotificationPositions(NUM_REC_NOTIFICATIONS, pPosNotify)) )
return DXTRACE_ERR_MSGBOX( TEXT("SetNotificationPositions"), hr );
}
HRESULT StartOrStopRecord(BOOL bStartRecording)
{
HRESULT hr;
if( bStartRecording )
{
if( FAILED( hr = g_pDSBCapture->Start( DSCBSTART_LOOPING ) ) )
return IDOK;
}
else
{
// Stop the buffer,
if( FAILED( hr = g_pDSBCapture->Stop() ) )
return IDOK;
}
}
HRESULT RecordCapturedData()
{
HRESULT hr;
VOID* pbCaptureData = NULL;
DWORD dwCaptureLength;
VOID* pbCaptureData2 = NULL;
DWORD dwCaptureLength2;
DWORD dwReadPos;
UINT dwDataWrote;
DWORD dwCapturePos;
LONG lLockSize;
// void* audio1=NULL,*audio2=NULL;
// void* buf;
if( NULL == g_pDSBCapture )
return S_FALSE;
if( NULL == g_pWaveFile )
return S_FALSE;
if( FAILED( hr = g_pDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("GetCurrentPosition"), hr );
lLockSize = dwReadPos - g_dwNextCaptureOffset;
if( lLockSize < 0 )
lLockSize += g_dwCaptureBufferSize;
// Block align lock size so that we are always write on a boundary
lLockSize -= (lLockSize % g_dwNotifySize);
if( lLockSize == 0 )
return S_FALSE;
// Lock the capture buffer down
if( FAILED( hr = g_pDSBCapture->Lock( g_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// Write the data into the wav file
if( FAILED( hr = g_pWaveFile->Write( dwCaptureLength,
(BYTE*)pbCaptureData,
&dwDataWrote ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("Write"), hr );
// Move the capture offset along
g_dwNextCaptureOffset += dwCaptureLength;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer
if( pbCaptureData2 != NULL )
{
// Write the data into the wav file
if( FAILED( hr = g_pWaveFile->Write( dwCaptureLength2,
(BYTE*)pbCaptureData2,
&dwDataWrote ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("Write"), hr );
// Move the capture offset along
g_dwNextCaptureOffset += dwCaptureLength2;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer
}
// Unlock the capture buffer
g_pDSBCapture->Unlock( pbCaptureData, dwCaptureLength,
pbCaptureData2, dwCaptureLength2 );
return S_OK;
/*if( FAILED( hr = g_pDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) )
g_pDSBCapture->Lock( g_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L);
if(audio1) memcpy(buf,pbCaptureData,dwCaptureLength);
if(audio2) memcpy((char*)buf+dwCaptureLength,pbCaptureData2,dwCaptureLength2);
g_pDSBCapture->Unlock( pbCaptureData, dwCaptureLength,
pbCaptureData2, dwCaptureLength2 );
return IDOK;*/
}
[/source}