python บันทึกเสียง pyaudio
ฉันพยายามบันทึกเสียงจากไมโครโฟนด้วย Python และฉันมีรหัสต่อไปนี้:
import pyaudio
import wave
import threading
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
CHUNK = 1024
WAVE_OUTPUT_FILENAME = "file.wav"
stop_ = False
audio = pyaudio.PyAudio()
stream = audio.open(format=FORMAT, channels=CHANNELS,
rate=RATE, input=True,
frames_per_buffer=CHUNK)
def stop():
global stop_
while True:
if not input('Press Enter >>>'):
print('exit')
stop_ = True
t = threading.Thread(target=stop, daemon=True).start()
frames = []
while True:
data = stream.read(CHUNK)
frames.append(data)
if stop_:
break
stream.stop_stream()
stream.close()
audio.terminate()
waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(b''.join(frames))
waveFile.close()
รหัสของฉันใช้งานได้ดี แต่เมื่อฉันเล่นการบันทึกฉันไม่ได้ยินเสียงใด ๆ ในไฟล์เอาต์พุตสุดท้ายของฉัน ( file.wav)
เหตุใดปัญหาจึงเกิดขึ้นที่นี่และฉันจะแก้ไขได้อย่างไร
คำตอบ
รหัสของคุณใช้งานได้ดี ปัญหาที่คุณพบเกิดจากสิทธิ์ของผู้ดูแลระบบ ไฟล์เสียงมีข้อมูล 0 คงที่ดังนั้นคุณจึงไม่สามารถฟังเสียงในไฟล์ wav ที่สร้างขึ้นได้ ฉันคิดว่าอุปกรณ์ไมโครโฟนของคุณได้รับการติดตั้งและทำงานอย่างถูกต้อง หากคุณไม่แน่ใจเกี่ยวกับสถานะการติดตั้งเสียงให้ทำตามขั้นตอนต่อไปนี้ตามระบบปฏิบัติการ:
MAC OS: การตั้งค่าระบบ -> เสียง -> อินพุตและที่นั่นคุณสามารถมองเห็นแถบเป็นเสียงได้ ตรวจสอบให้แน่ใจว่าประเภทอุปกรณ์ที่เลือกเป็นแบบ Built-in
Windos OS: การตั้งค่าเสียงและทดสอบไมโครโฟนโดยคลิกฟังอุปกรณ์นี้คุณสามารถยกเลิกการเลือกได้ในภายหลังเพราะจะวนกลับเสียงของคุณไปที่ลำโพงและจะสร้างเสียงดัง
คุณอาจใช้ Mac OS เป็นส่วนใหญ่ ฉันมีปัญหาที่คล้ายกันเนื่องจากฉันใช้โปรแกรมแก้ไข Atom เพื่อเรียกใช้รหัส python ลองเรียกใช้รหัสของคุณจากเทอร์มินัลของ Mac OS (หรือ Power Shell หากคุณกำลังใช้ windows) (ในกรณีที่ป๊อปอัปปรากฏขึ้นสำหรับการเข้าถึงไมโครโฟนบน Mac OS ให้กดตกลง) แค่นั้นแหละ! รหัสของคุณจะบันทึกได้ดี ในฐานะผู้ทดสอบโปรดเรียกใช้โค้ดด้านล่างเพื่อตรวจสอบว่าคุณสามารถแสดงภาพเสียงได้หรือไม่และตรวจสอบให้แน่ใจว่าได้เรียกใช้ผ่าน Terminal (ไม่มีตัวแก้ไขหรือ IDE)
import queue
import sys
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd
# Lets define audio variables
# We will use the default PC or Laptop mic to input the sound
device = 0 # id of the audio device by default
window = 1000 # window for the data
downsample = 1 # how much samples to drop
channels = [1] # a list of audio channels
interval = 30 # this is update interval in miliseconds for plot
# lets make a queue
q = queue.Queue()
# Please note that this sd.query_devices has an s in the end.
device_info = sd.query_devices(device, 'input')
samplerate = device_info['default_samplerate']
length = int(window*samplerate/(1000*downsample))
# lets print it
print("Sample Rate: ", samplerate)
# Typical sample rate is 44100 so lets see.
# Ok so lets move forward
# Now we require a variable to hold the samples
plotdata = np.zeros((length,len(channels)))
# Lets look at the shape of this plotdata
print("plotdata shape: ", plotdata.shape)
# So its vector of length 44100
# Or we can also say that its a matrix of rows 44100 and cols 1
# next is to make fig and axis of matplotlib plt
fig,ax = plt.subplots(figsize=(8,4))
# lets set the title
ax.set_title("PyShine")
# Make a matplotlib.lines.Line2D plot item of color green
# R,G,B = 0,1,0.29
lines = ax.plot(plotdata,color = (0,1,0.29))
# We will use an audio call back function to put the data in queue
def audio_callback(indata,frames,time,status):
q.put(indata[::downsample,[0]])
# now we will use an another function
# It will take frame of audio samples from the queue and update
# to the lines
def update_plot(frame):
global plotdata
while True:
try:
data = q.get_nowait()
except queue.Empty:
break
shift = len(data)
plotdata = np.roll(plotdata, -shift,axis = 0)
# Elements that roll beyond the last position are
# re-introduced
plotdata[-shift:,:] = data
for column, line in enumerate(lines):
line.set_ydata(plotdata[:,column])
return lines
ax.set_facecolor((0,0,0))
# Lets add the grid
ax.set_yticks([0])
ax.yaxis.grid(True)
""" INPUT FROM MIC """
stream = sd.InputStream( device = device, channels = max(channels), samplerate = samplerate, callback = audio_callback)
""" OUTPUT """
ani = FuncAnimation(fig,update_plot, interval=interval,blit=True)
with stream:
plt.show()
บันทึกไฟล์นี้เป็น voice.py ลงในโฟลเดอร์ (เช่น AUDIO) จากนั้น cd ไปยังโฟลเดอร์ AUDIO จากคำสั่งเทอร์มินัลจากนั้นดำเนินการโดยใช้:
python3 voice.py
หรือ
python voice.py
ขึ้นอยู่กับชื่อ python env ของคุณ
เมื่อใช้print(sd.query_devices())ฉันเห็นรายการอุปกรณ์ดังต่อไปนี้:
- Microsoft Sound Mapper - อินพุต, MME (2 เข้า, 0 ออก)
- ไมโครโฟน (AudioHubNano2D_V1.5, MME (2 in, 0 out)
- ไมโครโฟนภายใน (Conexant S, MME (2 in, 0 out)
- ...
อย่างไรก็ตามหากฉันใช้device = 0ฉันยังสามารถรับเสียงจากไมโครโฟน USB ซึ่งเป็นอุปกรณ์หมายเลข 1 ได้ตามค่าเริ่มต้นสัญญาณเสียงทั้งหมดจะไปที่ Sound Mapper หรือไม่ นั่นหมายความว่าถ้าฉันใช้device = 0ฉันจะได้รับสัญญาณเสียงทั้งหมดจากอินพุตเสียงทั้งหมด และถ้าฉันต้องการเพียงแค่สัญญาณเสียงจากเครื่องหนึ่งโดยเฉพาะอย่างยิ่งผมต้องเลือก x device = xจำนวนของการเป็น
ฉันมีคำถามอื่น: เป็นไปได้ไหมที่จะจับสัญญาณเสียงจากอุปกรณ์ 1 และ 2 ในแอปพลิเคชั่นเดียว แต่แยกกัน