📄 dlgdest.cpp
字号:
/*
* Copyright (c) Microsoft Corportation. All rights reserved.
*/
// DlgDest.cpp : implementation file
//
#include "stdafx.h"
#include "multichan.h"
#include "DlgDest.h"
#include "dlgsrc.h"
#include "childview.h"
#include <initguid.h>
#include <mmreg.h>
#include <msacm.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*
* CDlgDest
* MFC stuff
*/
/////////////////////////////////////////////////////////////////////////////
// CDlgDest dialog
void
CDlgDest::DoDataExchange
(
CDataExchange* pDX
)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDlgDest)
DDX_Control(pDX, IDC_SPEAKERFLAGS, m_cChannelMask);
DDX_Control(pDX, IDC_AVEBITS, m_cAveBitsPerSec);
DDX_Control(pDX, IDC_REMIX, m_cRemix);
DDX_Control(pDX, IDC_EDIT_VALIDBITS, m_cValidBits);
DDX_Control(pDX, IDC_CHANNELS, m_cChannels);
DDX_Control(pDX, IDC_OUTPUT, m_cOutput);
DDX_Control(pDX, IDC_COMBO_BITDEPTH, m_comboBitDepth);
DDX_Control(pDX, IDC_COMBO_SAMPLERATE, m_comboSampleRate);
DDX_Control(pDX, IDC_COMBO_WAVEFORMAT, m_comboFormat);
DDX_Control(pDX, IDC_PLAY, m_butPlay);
DDX_Control(pDX, IDC_STOP, m_butStop);
DDX_Text(pDX, IDC_EDIT_VALIDBITS, m_wValidBitsPerSample);
DDV_MinMaxUInt(pDX, m_wValidBitsPerSample, 0, 65535);
DDX_Text(pDX, IDC_SPEAKERFLAGS, m_strChannelMask);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDlgDest, CDialog)
//{{AFX_MSG_MAP(CDlgDest)
ON_BN_CLICKED(IDC_REMIX, OnRemix)
ON_BN_CLICKED(IDC_PLAY, OnPlay)
ON_BN_CLICKED(IDC_STOP, OnStop)
ON_CBN_SELENDOK(IDC_COMBO_SAMPLERATE, OnComboSamplerate)
ON_CBN_SELENDOK(IDC_COMBO_WAVEFORMAT, OnComboWaveformat)
ON_CBN_SELENDOK(IDC_COMBO_BITDEPTH, OnComboBitdepth)
ON_EN_KILLFOCUS(IDC_EDIT_VALIDBITS, OnEditValidbits)
ON_WM_CTLCOLOR()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/*
* CDlgDest
* construction
*/
// ----------------------------------------------------------------------------------
// constructor
// ----------------------------------------------------------------------------------
CDlgDest::CDlgDest
(
CWnd* pParent /*=NULL*/
)
: CDialog(CDlgDest::IDD, pParent),
m_pwndParent(pParent),
m_pbData(NULL),
m_fPlayable(FALSE),
m_fDragging(FALSE),
m_cbData( 0 ),
m_lpwhdr( 0 )
{
//{{AFX_DATA_INIT(CDlgDest)
m_wValidBitsPerSample = 0;
m_strChannelMask = _T("0x00000000");
//}}AFX_DATA_INIT
m_wfExt.Format.wFormatTag = WAVE_FORMAT_PCM;
m_wfExt.Format.cbSize = 0;
m_wfExt.Format.wBitsPerSample = 16;
m_wfExt.Format.nChannels = 0;
m_wfExt.Format.nBlockAlign = 4;
m_wfExt.Format.nSamplesPerSec = 44100;
m_wfExt.Format.nAvgBytesPerSec = m_wfExt.Format.nBlockAlign * m_wfExt.Format.nSamplesPerSec;
m_wfExt.Samples.wValidBitsPerSample = 16;
m_wfExt.dwChannelMask = 0;
m_wfExt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
m_wValidBitsPerSample = m_wfExt.Samples.wValidBitsPerSample;
}
// ----------------------------------------------------------------------------------
// destructor
// ----------------------------------------------------------------------------------
CDlgDest::~CDlgDest
()
{
SafeLocalFree( m_pbData );
SafeLocalFree( m_lpwhdr );
}
// ----------------------------------------------------------------------------------
// Create
// ----------------------------------------------------------------------------------
void
CDlgDest::Create
(
void
)
{
CDialog::Create(CDlgDest::IDD, m_pwndParent);
}
// ----------------------------------------------------------------------------------
// OnInitDialog
// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
CONST_GUID_REP cgrFormats[] =
{
&GUID_NULL, "GUID_NULL",
&KSDATAFORMAT_SUBTYPE_PCM, "KSDATAFORMAT_SUBTYPE_PCM"
};
UINT rgnSampleRate[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000 };
UINT rgnBitDepth[] = { 8, 16, 24, 32 };
BOOL
CDlgDest::OnInitDialog
()
{
CDialog::OnInitDialog();
int c,i;
i = m_comboFormat.AddString("WAVE_FORMAT_PCM");
m_comboFormat.SetItemData(i, WAVE_FORMAT_PCM);
i = m_comboFormat.AddString("WAVE_FORMAT_EXTENSIBLE");
m_comboFormat.SetItemData(i, WAVE_FORMAT_EXTENSIBLE);
char sz[10];
for(c = 0; c < ARRAY_ELEMENTS(rgnSampleRate); c++)
{
_snprintf(sz, 10, "%d", rgnSampleRate[c]);
i = m_comboSampleRate.AddString(sz);
m_comboSampleRate.SetItemData(i, rgnSampleRate[c]);
}
for(c = 0; c < ARRAY_ELEMENTS(rgnBitDepth); c++)
{
_snprintf(sz, 10, "%d", rgnBitDepth[c]);
i = m_comboBitDepth.AddString(sz);
m_comboBitDepth.SetItemData(i, rgnBitDepth[c]);
}
m_comboSampleRate.SelectString(0, "44100");
m_comboBitDepth.SelectString(0, "16");
m_comboFormat.SelectString(0, "WAVE_FORMAT_PCM");
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
/*
* CDlgDest
* operations
*/
// ----------------------------------------------------------------------------------
// OnRemix
// traverses the list of source channels and mixes them according to the user settings
// ----------------------------------------------------------------------------------
void
CDlgDest::OnRemix
()
{
CDlgSrc * pdlgSrc = 0;
ULONG cMaxSamples = 0;
UINT nSample;
ULONG cbSample;
// move over, bacon
SafeLocalFree(m_pbData);
//
// update UI
//
Update();
//
// determine the max number of samples
//
ULONG cSamplesSrcThisFormat = 0;
for
(
POSITION pos = g_listSources.GetHeadPosition();
pos;
)
{
pdlgSrc = g_listSources.GetNext(pos);
cSamplesSrcThisFormat = MulDiv(
m_wfExt.Format.nSamplesPerSec,
pdlgSrc->m_cSamples,
pdlgSrc->m_wfx.nSamplesPerSec
);
cMaxSamples = max(cMaxSamples, cSamplesSrcThisFormat);
}
//
// determine the length of the buffer required
//
cbSample = m_wfExt.Format.nChannels * m_wfExt.Format.wBitsPerSample / 8;
m_cbData = cbSample * cMaxSamples;
m_pbData = (PBYTE)LocalAlloc(LPTR, m_cbData);
if( 0 == m_pbData)
{
MessageBox( "Insufficient memory to complete the task.", "MultiChan : Error", MB_OK | MB_ICONSTOP );
return;
}
//
// copy data from each src to the dst
//
MMRESULT mmRes;
HACMSTREAM has;
ULONG cbConversion;
PVOID pvConversion;
ACMSTREAMHEADER ash;
ULONG cSamplesOut;
BOOL fRes = FALSE;
WAVEFORMATEX wfxConversion;
wfxConversion.wFormatTag = WAVE_FORMAT_PCM;
wfxConversion.cbSize = 0;
wfxConversion.nChannels = 1;
wfxConversion.nSamplesPerSec = m_wfExt.Format.nSamplesPerSec;
wfxConversion.wBitsPerSample = m_wfExt.Format.wBitsPerSample;
wfxConversion.nBlockAlign = wfxConversion.wBitsPerSample / 8;
wfxConversion.nAvgBytesPerSec = wfxConversion.nBlockAlign * wfxConversion.nSamplesPerSec;
//
// for each SRC (src dialog), convert it's buffer into 1 channel of the Dst format
//
for
(
pos = g_listSources.GetHeadPosition();
pos;
)
{
pdlgSrc = g_listSources.GetNext(pos);
//
// first, convert dlg format to dest format using ACM
//
// open an appropriate ACM driver
mmRes =
acmStreamOpen
(
&has,
NULL,
&pdlgSrc->m_wfx,
&wfxConversion,
NULL, //wFilter,
NULL,
0,
ACM_STREAMOPENF_NONREALTIME
);
if(!TrapMMError(mmRes, "acmStreamOpen"))
break;
//
// how big a buffer do we need to convert this one channel?
// in any case, acm overestimates the size of the buffer needed
// if the acm size is used when copying we will exceed the boundaries of our allocated m_pbData
//
mmRes =
acmStreamSize
(
has,
pdlgSrc->m_cbData,
&cbConversion,
ACM_STREAMSIZEF_SOURCE
);
if(!TrapMMError(mmRes, "acmStreamSize"))
break;
// alloc
pvConversion = LocalAlloc(LPTR, cbConversion);
if(!(fRes = (pvConversion != NULL)))
{
MessageBox("Not enough memory for ACM operation", "MultiChan : Error!", MB_ICONEXCLAMATION | MB_OK);
break;
}
// be prepared!
ZeroMemory(&ash, sizeof(ACMSTREAMHEADER));
ash.cbStruct = sizeof(ACMSTREAMHEADER);
ash.pbSrc = (PBYTE)pdlgSrc->m_pvData;
ash.cbSrcLength = pdlgSrc->m_cbData;
ash.pbDst = (PBYTE)pvConversion;
ash.cbDstLength = cbConversion;
mmRes = acmStreamPrepareHeader(has, &ash, 0);
if(!TrapMMError(mmRes, "acmStreamPrepareHeader"))
break;
// do it
mmRes = acmStreamConvert(has, &ash, 0);
if(!TrapMMError(mmRes, "acmStreamConvert"))
break;
// clean up
mmRes = acmStreamUnprepareHeader(has, &ash, 0) |
acmStreamClose(has, 0);
if(!TrapMMError(mmRes, "acmStreamUnprepareHeader"))
break;
//
// now copy the data from conversion buffer to final output buffer
//
cSamplesOut = ( cbConversion > m_cbData ) ?
( m_cbData / wfxConversion.nBlockAlign ) :
( cbConversion / wfxConversion.nBlockAlign );
switch(wfxConversion.nBlockAlign)
{
case 1: // 8-bit
{
// stagger dest
PBYTE pbDst = m_pbData + pdlgSrc->m_nChannel;
PBYTE pbSrc = (PBYTE)pvConversion;
for(nSample = 0; nSample < cSamplesOut; nSample++)
{
*pbDst = *pbSrc++;
pbDst += m_wfExt.Format.nChannels;
}
break;
}
case 2: // 16-bit
{
// stagger dest
PUSHORT pusDst = ((PUSHORT)m_pbData) + pdlgSrc->m_nChannel;
PUSHORT pusSrc = (PUSHORT)pvConversion;
for(nSample = 0; nSample < cSamplesOut; nSample++)
{
*pusDst = *pusSrc++;
pusDst += m_wfExt.Format.nChannels;
}
break;
}
case 3: // 24-bit
{
typedef struct {
BYTE b[3];
} S24BITS, *PS24BITS;
// stagger dest
PS24BITS psDst = ((PS24BITS)m_pbData) + pdlgSrc->m_nChannel;
PS24BITS psSrc = (PS24BITS)pvConversion;
for(nSample = 0; nSample < cSamplesOut; nSample++)
{
*psDst = *psSrc++;
psDst += m_wfExt.Format.nChannels;
}
break;
}
default:
ASSERT(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -