This article is a continuation of Sound signal processing module that can be used with Python-Sounddevice ASIO [Basic]. Please see here for the initial setting method for using sounddevice from the preparation before using it, and the basic playback method, recording method, simultaneous recording / playback method, and streaming method for sounddevice.
In this article, I would like to write about the channel mapping method using sound device (input from your favorite microphone and output from your favorite speaker in a multi-channel environment).
See here for details Python sound device official
With the update, it seems that the operation has become easier. The following articles describe older versions, so check the official documentation.
For example, suppose you have a speaker array like this If you want to output the sound source of 5 channels in order from the speakers of 5 channels, there is no problem because the sound device side automatically allocates the channels.
If you want to output the sound source of 1 channel from any speaker (3rd speaker this time) 1 channel, do as follows.
MonoChannelPlayback.py
out = [-1,-1,0,-1,-1]
sd.play(..., mapping = out ,...)
Next, if you want to output the sound source of 3 channels from any speaker (2nd, 3rd, 5th speaker this time) 3 channel, do as follows.
MultiChannelsPlayback.py
out = [-1,0,1,-1,2]
sd.play(..., mapping = out ,...)
In other words, if you make a list with [-1] for the speakers you do not want to output and [0] [1] [2] .. for the speakers you want to output, and put them in mapping, they will be assigned. Also,
MultiChannelsPlayback.py
out = [-1,1,0,-1,2]
sd.play(..., mapping = out ,...)
You can change the order of the speakers that produce sound.
This section describes the setting method when controlling input / output through unique APIs such as ASIO, Core Audio, and WASAPI. To check the API currently supported by your machine [Initial settings of equipment used](https://qiita.com/MikuMaekawa/items/aaac6df5d6cee2f8cf71#%E4%BD%BF%E7%94%A8% E6% A9% 9F% E6% 9D% 90% E3% 81% AE% E8% A8% AD% E5% AE% 9A) or try the following command.
checkAPI.py
sd.query_hostapis(index=None)
Return value
({'name': 'Core Audio',
'devices': [0, 1, 2],
'default_input_device': 0,
'default_output_device': 1},)
ASIO Click here for channel mapping settings in ASIO. This is controlled assuming that there is an environment where the speaker output is 5 channels and the microphone input is 2 channels.
ASIOMultiChannnelsControl.py
out = [0,1,2,3,4]
in = [0,1]
asio_out = sd.AsioSettings(channel_map = out)
asio_in = sd.AsioSettings(channel_map = in)
#Regeneration
sd.play(..., extra_settings=asio_out)
#recording
recdata = sd.rec(..., channels=2, extra_settings=asio_in,...)
#Simultaneous recording / playback
recdata = sd.playrec(...,channels=2, extra_settings=(asio_in,asio_out),... )
You can also set extra_setting as the default if you know you will use the same settings all the time.
default_map.py
out = [0,1,2,3,4]
in = [0,1]
asio_out = sd.AsioSettings(channel_map = out)
asio_in = sd.AsioSettings(channel_map = in)
sd.default.extra_settings = (asio_in,asio_out)
Core Audio The method is almost the same as that of ASIO.
CoreAudioMultiChannnelsControl.py
out = [0,1,2,3,4]
in = [0,1]
ca_out = sd.CoreAudioSettings(channel_map = out)
ca_in = sd.CoreAudioSettings(channel_map = in)
#Regeneration
sd.play(..., extra_settings=ca_out)
#recording
recdata = sd.rec(..., channels=2, extra_settings=ca_in,...)
#Simultaneous recording / playback
recdata = sd.playrec(...,channels=2, extra_settings=(ca_in,ca_out),... )
WASAPI The same is true for WASAPI
WasapiMultiChannnelsControl.py
out = [0,1,2,3,4]
in = [0,1]
wasapi_out = sd.WasapiSettings(channel_map = out)
wasapi_in = sd.WasapiSettings(channel_map = in)
#Regeneration
sd.play(..., extra_settings=wasapi_out)
#recording
recdata = sd.rec(..., channels=2, extra_settings=wasapi_in,...)
#Simultaneous recording / playback
recdata = sd.playrec(...,channels=2, extra_settings=(wasapi_in,wasapi_out),... )
This concludes the explanation of sound device. Hopefully, the number of sounddevice users will increase in the world, and I hope that various super-convenient and strongest programs that use sounddevice will overflow in the world.
Finally, I will say goodbye to the program that automatically finds the impulse response from the multi-channel speaker array I used to the dummy head without going through DAW software. Thank you for your hard work.
I will write a commentary article when I feel like it, but maybe people who use it do not need commentary ...
InpulseResponse.py
import numpy as np
import scipy as sp
import sounddevice as sd
import wave
import struct
#Setting
Fs=44100
small=1000000 #Adjust the volume to 1 / small because the sound of the prepared wav file was too loud
#sounddevise Setting
sd.default.samplerate=Fs
print(sd.query_devices())
#A list of connected devices will appear, so enter the device ID.
deviceNo = input("Please enter the ID of the device to use :" )
sd.default.device = int(deviceNo)
area = 1
#mapping
out1 = sd.CoreAudioSettings(channel_map=[0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1])
out2 = sd.CoreAudioSettings(channel_map=[-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1])
out3 = sd.CoreAudioSettings(channel_map=[-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1])
out4 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1])
out5 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1])
out6 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1])
out7 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1])
out8 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1])
out9 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1])
out10 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1])
out11 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1])
out12 = sd.CoreAudioSettings(channel_map=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0])
ca_in = sd.CoreAudioSettings(channel_map=[0,1])
def wavread(filename):#Reading 16bit WAVE files
wf = wave.open(filename,'rb')
buf = wf.readframes(wf.getnframes())
data = np.frombuffer(buf, dtype = "int16")
return data
TSP=wavread("tsp.wav")/small
#Put in white noise or Swept Sine signal (TSP) signal
#Compute the Convolution impulse response
def IR(rTSPdata,outputfilename):
rTSPdata=rTSPdata.T
ipls=np.real(sp.ifft(sp.fft(rTSPdata)*sp.fft(np.flipud(TSP),rTSPdata.size)))
c=np.fft.fftshift(ipls/max(ipls))
int16amp=32768 / int(c.max())
y2 = np.array([c * int16amp],dtype = "int16")[0]
y4 = struct.pack("h" * len(y2), *y2)
w = wave.Wave_write(outputfilename)
w.setparams((
1, # channel
2, # byte width
44100, # sampling rate
len(y4), # number of frames
"NONE", "NONE" # no compression
))
w.writeframesraw(y4)
w.close()
#Playrec
def PlayRec(outmap,IDnumber):
#sd.play(TSP,Fs,extra_settings=outmap,blocking=True)
TSP1=sd.playrec(TSP,Fs,channels=2,extra_settings=(ca_in,outmap),blocking=True)
TSP2=sd.playrec(TSP,Fs,channels=2,extra_settings=(ca_in,outmap),blocking=True)
TSP3=sd.playrec(TSP,Fs,channels=2,extra_settings=(ca_in,outmap),blocking=True)
#We are doing additive polymerization, but recently we have prepared a long white noise or Swept Sine signal (TSP signal).
#It seems that the mainstream is to find it in one shot without additive polymerization.
rTSP = TSP1 + TSP2 + TSP3
#Invert the recorded response to find the IR
rTSP1 = rTSP[:,0]
rTSP2 = rTSP[:,1]
rTSP3 = rTSP[:,2]
rTSP4 = rTSP[:,3]
rTSP5 = rTSP[:,4]
rTSP6 = rTSP[:,5]
rTSP7 = rTSP[:,6]
rTSP8 = rTSP[:,7]
rTSP9 = rTSP[:,8]
rTSP10 = rTSP[:,9]
#Name the resulting impulse response and write it as a WAV file to a folder
IR(rTSP1,"IR"+str(IDnumber)+"1.wav")
IR(rTSP2,"IR"+str(IDnumber)+"2.wav")
IR(rTSP3,"IR"+str(IDnumber)+"3.wav")
IR(rTSP4,"IR"+str(IDnumber)+"4.wav")
IR(rTSP5,"IR"+str(IDnumber)+"5.wav")
IR(rTSP6,"IR"+str(IDnumber)+"6.wav")
IR(rTSP7,"IR"+str(IDnumber)+"7.wav")
IR(rTSP8,"IR"+str(IDnumber)+"8.wav")
IR(rTSP9,"IR"+str(IDnumber)+"9.wav")
IR(rTSP10,"IR"+str(IDnumber)+"10.wav")
print("Start measurement")
PlayRec(out1,1)
PlayRec(out2,2)
PlayRec(out3,3)
PlayRec(out4,4)
PlayRec(out5,5)
PlayRec(out6,6)
PlayRec(out7,7)
PlayRec(out8,8)
PlayRec(out9,9)
PlayRec(out10,10)
PlayRec(out11,11)
PlayRec(out12,12)
print("End of measurement")
Python sound device official Sound signal processing module that can be used with Python-Sounddevice ASIO [Basic]
Recommended Posts