如何象豪杰超级解霸那样控制左右声道?(300分)

  • 主题发起人 主题发起人 Vision
  • 开始时间 开始时间
用一个叫AMIXER的控件,很好实现这个功能。下载地址可以自己搜索一下。
 
试过AMIXER,和上面几个例子是相同的效果,关闭一个声道后,只有一个喇叭发声。
 
我不会这个问题,但我觉得你的思路有点小问题。当然也许是我对你问题理解错误。
按照你的要求,我认为不应该关闭某一个声道。关闭声道是肯定只有一个喇叭发声的。
应该做的是控制声道输出的源头,把某个音轨同时输出到两个喇叭。
 
to 百刃刀客
应该做的是控制声道输出的源头,把某个音轨同时输出到两个喇叭。

我觉得是应该这样实现才行,相信“豪杰超级解霸”也是这样实现的,但是我不知道如何去实现,网上能找到的办法通通是关闭一个声道这种做法,但这种做法的结果就是有一个喇叭不发声了,耳朵靠近听只听到沙沙声的噪音。
 
我估计要读出数据,然后自己播放了。 看看这个,有没有帮助

指针 lpData 指向 Buf[2048],lpData每次读出4个字节,前2个字节为左声道,后两个字节为右声道。

这个是 Delphi 的一个左右声道的例子(采用了mmtools插件),
procedure TForm1.WaveOutBufferFilled(Sender: TObject;
lpWaveHdr: PWaveHdr);
type
PChannel = ^TChannel;

TChannel = record
Left : Smallint;

Right: Smallint;

end;


PChannels = ^TChannels;

TChannels = array[0..0] of TChannel;

var
i: integer;
lpData: PChannels;
dwCount: DWORD;
begin

// Waveout has loaded the data, our last chance to modify it
// before it is send to the driver.
if (RadioGroup1.ItemIndex > 0) then

begin

// this works only with stereo PCM data !
if (WaveOut.PWaveFormat^.wFormatTag = WAVE_FORMAT_PCM) and
(WaveOut.PWaveFormat^.nChannels = 2) then

begin

lpData := PChannels(lpWaveHdr^.lpData);
dwCount := lpWaveHdr^.dwBytesRecorded div 4;
// length in stereo samples if (RadioGroup1.ItemIndex = 1) then

begin

// play the left channel on the right channel too
for i := 0 to dwCount-1do

lpData.Right := lpData.Left;
end
else

begin

// play the right channel on the left channel too
for i := 0 to dwCount-1do

lpData.Left := lpData.Right;
end;

end;

end;

end;
 
我们联系一下 QQ 87797301
 
看看这个能不能解决:
http://www.2ccc.com/article.asp?articleid=631
 
to: abin30
看你贴的代码这左右声道复制的,应该行得通吧?但我在找很久,没找到好用的mmtools,有个源码版的,但没有for d7或d2006的,没法试。

使用DXSound混音用在TRealAudio或TWindowMediaPlayer肯定是行不通的,如果使用DirectShow写的应该可以。
 
我是帮你找的资料,本人没有实验过。实在不好意思哈~能不能用,就要自己实验了。
 
终于找到一个例子,不过是VC 的,不过原理应该是一样的
使用DirectShow技术切换双声道音频声道的方法
  我们在编写多媒体播放器程序时,经常会遇到不知怎么让双声道切换到左声道或右声道音频的问题,而使用MCI接口或媒体播放器控件往往只能使用调节声道左右均衡的方法达到切换声道的目的,但这样只会有一只喇叭发出声音,且某些VCD格式的歌曲甚至不能用这种方法切换声道.
  但我们在使用媒体播放器播放VCD格式的文件时,如果你仔细观察,会发现可以在播放时通过 属性->高级->选中Mpeg Audio Decoder过滤器->属性->频道 的方法分别切换到左右声道或立体声状态,媒体播放器是怎样实现这个功能但我们为什么又不能直接在VB中实现它呢?,其实这都是因为媒体播放器是基于DirectShow技术的原因.
  同理,我们也可以直接调用DirectShow达到播放多媒体文件的目的,但要实现切换声道还得首先弄懂音频数据的格式,下面以16位音频数据为例(8位音频只是少了一个字节的数据)简单说一下解压后的音频数据在即将播放时的声道分布格式.
  当音频数据通过各种解码器解码后,在将要播放时都会先送到声卡数据缓冲区里,其数据为Wave格式,例如:aa bb cc dd,其中aa-左声道,bb-右声道,cc-左声道,dd-右声道,很简单的是吗:)
  如果要切换到左声道就要用左声道的数据填充到右声道里,即使上面的音频数据变为:aa aa cc cc这种形式,知道它的原理,下一步的工作就是利用DirectShow技术写一个Filter插入到声卡reanderer的前面,这样只要是双声道格式的音频数据,我们都可以对它进行声道切换了.下面列出我写的一个用于16音频声道切换的Filter源代码(其实很简单的,但你得对COM有一点了解)
//ZQAudio.cpp
//用于切换声道的一个directshow fileter
// Copyright (c) 2004, 程序设计:张强. All rights reserved.
// hndamofy@163.com
// 如果您要传播此源码,请保留该部分
#include <streams.h> // DirectShow (includes windows.h)
#include <initguid.h> // declares DEFINE_GUID to declare an EXTERN_C const.
#include &quot;IZQAudio.h&quot;
// 自定义接口

// {CFBE95E1-5DB4-11d8-929C-92B98A07327D}
DEFINE_GUID(CLSID_ZQAudio,
0xcfbe95e1, 0x5db4, 0x11d8, 0x92, 0x9c, 0x92, 0xb9, 0x8a, 0x7, 0x32, 0x7d);

const AMOVIESETUP_MEDIATYPE sudPinTypes =
{ &MEDIATYPE_Audio // clsMajorType
, &MEDIASUBTYPE_PCM };
// clsMinorType

const AMOVIESETUP_PIN psudPins[] =
{ { L&quot;Input&quot;
// strName
, FALSE // bRendered
, FALSE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, L&quot;&quot;
// strConnectsToPin
, 1 // nTypes
, &sudPinTypes // lpTypes
}
, { L&quot;Output&quot;
// strName
, FALSE // bRendered
, TRUE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, L&quot;&quot;
// strConnectsToPin
, 1 // nTypes
, &sudPinTypes // lpTypes
}
};


const AMOVIESETUP_FILTER sudNullNull =
{ &CLSID_ZQAudio // clsID
, L&quot;zhang qiang Filter&quot;
// strName
, MERIT_DO_NOT_USE // dwMerit
, 2 // nPins
, psudPins };
// lpPin

// CZQAudio
//
class CZQAudio:
public CTransInPlaceFilter,
public IZQAudioInterface
{

public:

//COM 函数声明
static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);

DECLARE_IUNKNOWN;

STDMETHODIMP put_AudioMode(int inAudio_Channel_Mode);
STDMETHODIMP get_AudioMode(int *outAudio_Channel_Mode);

private:

int Audio_Channel_Mode;
//声道模式设置
//int s;
CCritSec m_Mylock;
//锁定对象

//构造函数,同时调用基类的构造函数
CZQAudio(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)
: CTransInPlaceFilter (tszName, punk, CLSID_ZQAudio, phr)
{ Audio_Channel_Mode=0;
}

//主要执行函数
HRESULT Transform(IMediaSample *pSample);
//检查输入类型
HRESULT CheckInputType(const CMediaType *mtIn);

//检查输入与输出类型是否一致
//HRESULT CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut){ return S_OK;
};

//取得类型
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);


};



// Needed for the CreateInstance mechanism
CFactoryTemplate g_Templates[]=
{ { L&quot;zhang qiang Filter&quot;
, &CLSID_ZQAudio
, CZQAudio::CreateInstance
, NULL
, &sudNullNull }
};
int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);


//
// CreateInstance
//
// 创建一个对象实例
CUnknown * WINAPI CZQAudio::CreateInstance(LPUNKNOWN punk, HRESULT *phr) {

CZQAudio *pNewObject = new CZQAudio(NAME(&quot;Zhang qiang audio filter&quot;), punk, phr );
if (pNewObject == NULL) {
*phr = E_OUTOFMEMORY;
}

return pNewObject;
} // CreateInstance


HRESULT CZQAudio::Transform(IMediaSample *pSample)
{
BYTE *pOutData;
int i=0,w_pos=0,r_pos=0,SampleSize=0,n=0;

//进行声道选择
switch(Audio_Channel_Mode)
{
case 1:r_pos=0;
w_pos=2;
break;
//左声道

case 2:r_pos=2;
w_pos=0;

break;
//右声道

default:return NOERROR;
//不处理(双声道模式)
}

pSample->GetPointer(&pOutData);
//取得缓冲区指针
SampleSize=pSample->GetActualDataLength();
//取得有效数据大小
n=SampleSize/4;
//循环次数

//执行声道切换操作
for(i=0;i<n;i++){
memcpy(pOutData+w_pos,pOutData+r_pos,2);

w_pos+=4;
r_pos+=4;
}
return NOERROR;
}

HRESULT CZQAudio::GetMediaType(int iPosition,CMediaType *pMediaType)
{
return NOERROR;
}

HRESULT CZQAudio::CheckInputType(const CMediaType *mtIn)
{
//检查是否在停止状态,且是否是音频数据类型
if(IsStopped() && *mtIn->Type()==MEDIATYPE_Audio)
{
//检查是否是PCM格式的数据
if(*mtIn->Subtype()==MEDIASUBTYPE_PCM ||
*mtIn->Subtype()==MEDIASUBTYPE_WAVE)
{
return S_OK;
//成功
}
}
return E_INVALIDARG;
//无效类型
}


//设置声道
STDMETHODIMP CZQAudio::put_AudioMode(int inAudio_Channel_Mode)
{
//判断参数是否合法
if(inAudio_Channel_Mode>=0 && inAudio_Channel_Mode<=2){
Audio_Channel_Mode=inAudio_Channel_Mode;
return S_OK;
}
return E_INVALIDARG;
//参数无效
}

//取得声道模式设置
STDMETHODIMP CZQAudio::get_AudioMode(int *outAudio_Channel_Mode)
{
//取得声道模式设置
*outAudio_Channel_Mode=Audio_Channel_Mode;
return S_OK;
}

//暴露接口
STDMETHODIMP CZQAudio::NonDelegatingQueryInterface(REFIID riid,void **ppv)
{
CheckPointer(ppv,E_POINTER);
if(riid==IID_IZQAudioInterface){
return GetInterface((IZQAudioInterface *) this,ppv);
}else
{
return CTransInPlaceFilter::NonDelegatingQueryInterface(riid,ppv);
}
}
/******************************全局函数******************************/
* 注册及反注册函数
/**************************************************************************/
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}

STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
//屏蔽 4514 警告
#pragma warning( disable:4514)

//IZQAudio.h
//声道切换的自定义接口

#ifndef _H_IZQAudioInterface_
#define _H_IZQAudioInterface_

#ifdef _cplusplus
extern &quot;C&quot;
{
#endif

//IZQAudioChannel's GUID
// {83BA1141-6135-11d8-929C-A23780A5EB7C}
DEFINE_GUID(IID_IZQAudioInterface,
0x83ba1141, 0x6135, 0x11d8, 0x92, 0x9c, 0xa2, 0x37, 0x80, 0xa5, 0xeb, 0x7c);

// 双声道模式参数声明
#define AM_AUDIO_DUAL_MERGE 0 //双声道
#define AM_AUDIO_DUAL_LEFT 1 //左声道
#define AM_AUDIO_DUAL_RIGHT 2 //右声道

//IZQAudioInterface 接口定义
DECLARE_INTERFACE_(IZQAudioInterface,IUnknown)
{
//设置声道:0-不处理声道,1-左声道,2-右声道
STDMETHOD (put_AudioMode) (THIS_
int inAudio_Channel_Mode
) PURE;
//返回声道的设置
STDMETHOD (get_AudioMode) (THIS_
int *outAudio_Channel_Mode
) PURE;
};

#ifdef _cplusplus
}
#endif

#endif //_H_IZQAudio_

将以上文件加入到VC工程里,并安装DirectX8.1 SDK,设置好相关的文件搜索路径(具体可参考<DirectShow开发指南>)编译后将得到一个Filter,现在你可在程序中用它来切换声道了,如果你想在VB中使用它,须写一个DLL将各种播放操作封装,然后供VB进行调用.
另外,用它对某些VCD格式的歌曲会无效,原因在于Mpeg Audio Decoder解码器的设置问题,你可在程序中包含MpegType.h文件来切换声道.
以上均是我摸索实验的结果,如有错误还请指出!




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=253005
 
to: abin30
非常感谢啊,虽然我对C++不太熟,先来研究研究
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部