Search code examples
pythonfileaudioaudio-recording

saved .wav files have no data


I made a program that records files and saves them to a file directory and it does save them properly. However, when I try and open it and see what was recorded I see that it has no stored audio data. I am not sure what I am doing wrong. Please take a look and let me know.

from playsound import playsound
from random import randrange
import pyttsx3
from datetime import datetime
import pyaudio
import speech_recognition as sr
import requests
import wave
import numpy as np
import sounddevice as sd
import math
import time
import os
import sys
import sounddevice as sd
from scipy.io.wavfile import write
import struct
def voiceDetection():
    SoundThreshHold = 50
    TimeoutLength = 5
    chunk = 1024  
    FORMAT = pyaudio.paInt16
    CHANNELS = 2 #Basicly audio output
    RATE = 16000 #Rate at which you sample
    f_name_directory = r"C:\Users\x\OneDrive\Desktop\Record"
    def rms(data):
       count = len(data)/2
       format = "%dh"%(count)
       shorts = struct.unpack( format, data )
       sum_squares = 0.0
       for sample in shorts:
           n = sample * (1.0/32768)
           sum_squares += n*n
       return math.sqrt( sum_squares / count)*1000
    p = pyaudio.PyAudio()
    stream = p.open(format=FORMAT,
                     channels=CHANNELS,
                     rate=RATE,
                     input=True,
                     output=True,
                     frames_per_buffer=chunk)
    currentTime = time.time()
    end = time.time() + TimeoutLength
    frames = []
    while currentTime < end:
       currentTime = time.time()
       data = stream.read(chunk)
       if rms(data) >= SoundThreshHold:
          #print(rms(data))
          end = time.time() + TimeoutLength
          frames.append(data)
          n_files = len(os.listdir(f_name_directory))
          filename = os.path.join(f_name_directory,'{}.wav'.format(n_files))
          wf = wave.open(filename,'wb')
          wf.setnchannels(CHANNELS)
          wf.setsampwidth(p.get_sample_size(FORMAT))
          wf.setframerate(RATE)
          wf.writeframes(data)
          wf.close()
          print('Written to file: {}'.format(filename))
    stream.stop_stream()
    stream.close()
    p.terminate()
voiceDetection()

Solution

  • The current code writes a separate WAV file once per chunk, and always with the same name, so the file overwrites any WAV written for a previous chunk. You probably intend to call wave.open once before the loop and wf.close after the loop, so that one WAV is written for the whole the session.


    Edit: Interspersing file IO during the audio recording might be too much overhead to record properly without dropping samples. You could try instead buffering up all the samples in memory and then writing the WAV all at once afterward. On the pyaudio homepage, there is a "record" example to record several seconds of audio and write it as a WAV file:

    """PyAudio example: Record a few seconds of audio and save to a WAVE file."""
    
    import pyaudio
    import wave
    
    CHUNK = 1024
    FORMAT = pyaudio.paInt16
    CHANNELS = 2
    RATE = 44100
    RECORD_SECONDS = 5
    WAVE_OUTPUT_FILENAME = "output.wav"
    
    p = pyaudio.PyAudio()
    
    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)
    
    print("* recording")
    
    frames = []
    
    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK)
        frames.append(data)
    
    print("* done recording")
    
    stream.stop_stream()
    stream.close()
    p.terminate()
    
    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()
    

    As a general note, beware that unfortunately the (standard CPython) Python interpreter has limited ability to execute threads truly simultaneously, which makes Python a poor language for real time audio applications (see also Does python support multiprocessor/multicore programming?). Depending on your project goals, you might want to switch to C++ and use the portaudio C library (on which pyaudio is based).