播放两个独立波形文件所需的API配置/调用是什么? 我试图这样做,我得到资源忙的错误。一些解决问题的指针将非常有用。
以下是来自第二个wavefile的snd_pcm_prepare()
的错误消息
"Device or resource busy"
答案 0 :(得分:5)
ALSA不提供混音器。如果您需要同时播放多个音频流,则需要自己将它们混合在一起。
最简单的方法是将WAV文件解码为float
样本,添加它们,并在将它们转换回整数样本时剪切它们。
或者,您可以尝试多次打开默认音频设备(以及不硬件设备,如“hw:0”),对于您希望的每个流,玩,并希望加载dmix ALSA插件并提供混音功能。
答案 1 :(得分:1)
由于ALSA默认提供混音设备(dmix),因此您可以简单地使用aplay,就像这样:
aplay song1.wav &
aplay -Dplug:dmix song2.wav
如果您的音频文件具有相同的速率和格式,则无需使用插头。变成:
aplay song1.wav &
aplay -Ddmix song2.wav
但是,如果要编程此方法,则可以进行一些C ++音频编程tutorials here。这些教程向您展示了如何加载音频文件以及如何操作不同的音频子系统,例如jackd和ALSA。
在this example中,它演示了使用ALSA播放一个音频文件的过程。可以这样打开第二个音频文件来修改它:
Sox<short int> sox2;
res=sox2.openRead(argv[2]);
if (res<0 && res!=SOX_READ_MAXSCALE_ERROR)
return SoxDebug().evaluateError(res);
然后像这样修改the while loop:
Eigen::Array<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> buffer, buffer2;
size_t totalWritten=0;
while (sox.read(buffer, pSize)>=0 && sox2.read(buffer2, pSize)>=0){
if (buffer.rows()==0 || buffer.rows()==0) // end of the file.
break;
// as the original files were opened as short int, summing will not overload the int buffer.
buffer+=buffer2; // sum the two waveforms together
playBack<<buffer; // play the audio data
totalWritten+=buffer.rows();
}
答案 2 :(得分:0)
您也可以使用此配置
private void CreateExpression(Type interfaceType, Type methodReturnType, MethodInfo methodName)
{
ParameterExpression parameter = Expression.Parameter(interfaceType, "srv");
Expression property = Expression.Call(methodReturnType, methodName.Name, new Type[]{ } ,parameter);
Type expressionType = typeof(Expression<>);
Type lambdaType = typeof(LambdaExpression);
Type funcType = typeof(Func<,>);
Type delegateType = funcType.MakeGenericType(interfaceType, methodReturnType);
Type expression = expressionType.MakeGenericType(delegateType);
MethodInfo mI = typeof(Expression).GetMethod("Lambda");
MethodInfo lambda = mI.MakeGenericMethod(delegateType);
var ex = lambda.Invoke(this, new object[] { delegateType, property, parameter });
}
在〜/ .asoundrc或/etc/asound.conf
中更新它您可以使用命令
对于wav文件
aplay -D mix_stream&#34; filename&#34;
对于raw或pcmfile
aplay -D mix_stream -c&#34;频道&#34; -r&#34;率&#34; -f&#34;格式&#34; &#34;文件名&#34;
根据音频文件输入频道,比率,格式和文件名的值
答案 3 :(得分:0)
以下是一个非常简化的多线程回放解决方案(假设两个文件的样本格式相同,频道号相同,频率相同):
每个文件解码启动基于缓冲区的线程(必须为file1
和file2
生成此代码2次:
import wave
import threading
periodsize = 160
f = wave.open(file1Wave, 'rb')
file1Alive = True
file1Thread = threading.Thread(target=_playFile1)
file1Thread.daemon = True
file1Thread.start()
文件解码线程本身(也必须定义两次 - file1
和file2
):
def _playFile1():
# Read data from RIFF
while file1Alive:
if file1dataReady:
time.sleep(.001)
else:
data1 = f.readframes(periodsize)
if not data1:
file1Alive = False
f.close()
else:
file1dataReady == True
开始合并线程(又名funnel
)以合并文件解码
import alsaaudio
import threading
sink = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, device="hw:CARD=default")
sinkformat = 2
funnelalive = True
funnelThread = threading.Thread(target=self._funnelLoop)
funnelThread.daemon = True
funnelThread.start()
合并和播放(又名funnel
)线程
def _funnelLoop():
# Reading all Inputs
while funnelalive:
# if nothing to play - time to selfdestruct
if not file1Alive and not file2Alive:
funnelalive = False
sink.close()
else:
if file1dataReady and file2dataReady:
# merging data from others but first
datamerged = audioop.add(data2, data2, sinkformat)
file1dataReady = False
file2dataReady = False
sink.write(datamerged)
time.sleep(.001)