I have a DirectX implementation using IBasicAudio, and I can control the balance just fine. What I would like to do is to select the Left or Right audio signal and drive it out both speakers. Can someone direct me to an existing implementation or give me some pointers? Thank you very much!
Best regards,
Dave
yooper
December 5th, 2005, 09:49 AM
Hello again,
I believe I know how to replicate the left channel sound on the right, or vice versa. But I still need some help. I need a working callback routine for the BufferCB interface of an ISampleGrabberCB, hooked into my DirectX audio filter. If anyone has a working SampleGrabber that matches this description, please be so kind as to share it with the forum (and me :-). Thanks!
Best regards,
Dave
yooper
December 16th, 2005, 03:21 PM
For those who may stumble onto this thread and need some assistance, here's how I finally got it to work:
void MyFreeMediaType(AM_MEDIA_TYPE& mt)
{
if (mt.cbFormat != 0)
{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
// Unecessary because pUnk should not be used, but safest.
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
HRESULT PlayMovieInWindow(LPTSTR szFile)
{
.
.
.
// Convert filename to wide character string
wcsncpy(wFile, T2W(szFile), NUMELMS(wFile)-1);
wFile[MAX_PATH-1] = 0;
// Get the interface for DirectShow's GraphBuilder
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGB));
if(SUCCEEDED(hr))
{
// Add a Sample Grabber to the Filter Graph.
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGF));
hr = pGB->AddFilter(pGF, L"Sample Grabber"));
hr = pGF->QueryInterface(IID_ISampleGrabber, (void**)&pSG));
// Set the media type of the Sample Grabber to Audio.
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
mt.formattype = FORMAT_WaveFormatEx;
hr = pSG->SetMediaType(&mt));
// Have the graph builder construct the appropriate graph automatically
hr = pGB->RenderFile(wFile, NULL));
// Query for video interfaces, which may not be relevant for audio files
hr = pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW));
hr = pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV));
// Query for audio interfaces, which may not be relevant for video-only files
hr = pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA));
// Have the graph signal event via window callbacks for performance
hr = pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0));
// Set up the callback function to MUX the audio when required.
hr = pSG->SetOneShot(FALSE));
hr = pSG->SetBufferSamples(TRUE));
hr = pSG->SetCallback(&pVASG, 0));
// Run the graph to play the media file *********************
hr = pMC->Run());
}
return hr;
}
void VideoSetAudioChannel(ZMUX_MODE button)
{
if (button == MUX_both)
g_lMux = MUX_BOTH;
else if (button == MUX_mute_right)
g_lMux = MUX_LEFT;
else if (button == MUX_mute_left)
g_lMux = MUX_RIGHT;
//else
// Invalid input. Leave the MUX alone.
}
STDMETHODIMP VidAudioSampleGrabber::SampleCB( double SampleTime, IMediaSample * pSample )
{
// Only process the audio stream if we're MUXing
if (g_lMux != MUX_BOTH)
{
unsigned char * pData;
LONG lSamples = pSample->GetActualDataLength();
HRESULT hr = pSample->GetPointer(&pData);
if (SUCCEEDED(hr))
{
while (lSamples > 0)
{
if (g_lMux == MUX_RIGHT)
{
// Place the left channel onto the right
pData[0] = pData[2];
pData[1] = pData[3];
}
else if (g_lMux == MUX_LEFT)
{
// Place the right channel onto the left
pData[2] = pData[0];
pData[3] = pData[1];
}
I've left out a lot of the boring (and possibly confidential) stuff, but this should give you the basics to create a working SampleGrabber. I was trying to Connect filters, find PinIn and PinOut, etc. But what I finally got to work turned out to be rather simple.
I hope you benefit from this.
Best regards,
Dave
lkm985
September 12th, 2006, 12:01 PM
Want to know something from you!
Can you make the left or right audio out both speakers??
Can you teach me how to make it? i also have to same problem.
Thanks
yooper
September 12th, 2006, 12:34 PM
Hi,
Did you check out my code segment above? It is pretty much all you need to know to get this to happen.
Basically, you need an ISampleGrabberCB class where you define methods for: AddRef(), Release(), QueryInterface(), SampleCB(), and BufferCB(). I chose to implement the channel swap in the SampleCB, as that seemed to be the easiest and have the best performance.
In my example, you can see which bytes of the quadruple need to be overlaid with which other bytes. You can do other types of audio manipulation here, like key changing, amplitude filtering, etc., but those require a lot more computation than simply swapping bytes.
Good luck!
Dave
P.S. If you like my post, please feel free to rate me. :-)
lkm985
September 16th, 2006, 07:51 AM
Sorry, i'm new with it and dont really understand it.
Can you show some code how to define for AddRef(), Release(), QueryInterface() and etc.?
I dont mind you email to me!
yooper
September 16th, 2006, 11:04 AM
It's all up there. The class defines AddRef() to return an unsigned long value of 2. It also defines release to return an unsigned long value of 1. QueryInterface() is farther down, and looks like this:STDMETHODIMP VidAudioSampleGrabber::QueryInterface(REFIID riid, void ** ppv)
{
if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown)
{
*ppv = (void *) static_cast<ISampleGrabberCB *>(this);
return S_OK;
}
return E_NOINTERFACE;
}Everything you need should be defined right at the top of this thread.
lkm985
September 16th, 2006, 11:31 PM
Finally, i found out what happen to my code. Missed one part. lolx.
but another thing is after i change the audio channel to left or right then cannot change back to both channel audio. What wrong??
Other, want to know something from you. Is that everytime will get different of BYTE when trying to pSample->GetPointer(&pData); ?
Thank's Man!!
lkm985
September 17th, 2006, 04:12 AM
i use the keyboard key to call the VideoSetAudio Channel function but it does not work if i call the both channel function. Any idea?
Here is my code:
void MyFreeMediaType(AM_MEDIA_TYPE& mty)
{
if (mty.cbFormat != 0)
{
CoTaskMemFree((PVOID)mty.pbFormat);
mty.cbFormat = 0;
mty.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
// Unecessary because pUnk should not be used, but safest.
mty.pUnk->Release();
mty.pUnk = NULL;
}
}
// Clear open dialog remnants before calling RenderFile()
UpdateWindow(ghApp);
// Convert filename to wide character string
wcsncpy(wFile, T2W(szFile), NUMELMS(wFile)-1);
wFile[MAX_PATH-1] = 0;
// Get the interface for DirectShow's GraphBuilder
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGB));
if(SUCCEEDED(hr))
{
// Add a Sample Grabber to the Filter Graph.
JIF(CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGF));
JIF(pGB->AddFilter(pGF, L"Sample Grabber"));
JIF(pGF->QueryInterface(IID_ISampleGrabber, (void**)&pSG));
// Set the media type of the Sample Grabber to Audio.
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mty.majortype = MEDIATYPE_Audio;
mty.subtype = MEDIASUBTYPE_PCM;
mty.formattype = FORMAT_WaveFormatEx;
JIF(pSG->SetMediaType(&mty));
// Have the graph builder construct its the appropriate graph automatically
JIF(pGB->RenderFile(wFile, NULL));
// Query for video interfaces, which may not be relevant for audio files
JIF(pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW));
JIF(pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV));
// Query for audio interfaces, which may not be relevant for video-only files
JIF(pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA));
// Is this an audio-only file (no video component)?
CheckVisibility();
// Have the graph signal event via window callbacks for performance
JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0));
if (!g_bAudioOnly)
{
// Setup the video window
JIF(pVW->put_Owner((OAHWND)ghApp));
JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
JIF(InitVideoWindow(1, 1));
}
else
{
// Initialize the default player size and enable playback menu items
JIF(InitPlayerWindow());
}
// Set up the callback function to MUX the audio when required.
JIF(pSG->SetOneShot(FALSE));
JIF(pSG->SetBufferSamples(TRUE));
JIF(pSG->SetCallback(&pVASG, 0));
#ifdef REGISTER_FILTERGRAPH
hr = AddGraphToRot(pGB, &g_dwGraphRegister);
if (FAILED(hr))
{
Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr);
g_dwGraphRegister = 0;
}
#endif
switch(toupper((int) wParam))
{
case '2':
VideoSetAudioBothChannel();
case '3':
VideoSetAudioLeftChannel();
case '4':
VideoSetAudioRightChannel();
.............
// Pass this message to the video window for notification of system changes
if (pVW)
pVW->NotifyOwnerMessage((LONG_PTR) hWnd, message, wParam, lParam);