6
$\begingroup$

I am having trouble understanding the example program for audio recording , it comes with PyAudio module.

I am using an external Audio Card to record the sound , obviously, the voice should be converted into the digital form to be presented to the computer. But i do not understand how this code converts the input Analog Voice into Digital Form and then saving it.

Here is the code,

import pyaudio
import wave
import sys

CHUNK = 1024
# What is CHUNKS here ?
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "test.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)
print("start....")

frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

print("done...")


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()

When the code is executed it record the sounds for 5seconds using an external audio card with a mic.

What I understood from the code is,

The Rate is 44Kbps, which means that 44 kilo bytes are generated from the Analog Audio signals per second.

Then an empty frame is generated frame[] where all the recorded data will be stored.

The next thing is for loop,

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)

the answer to RATE/CHUNK*RECORD_SECONDS is 215.33 which means there will be 215 iterations.

I don't understand why the RATE is divided by CHUNKS and then multiplied by RECORD_SECONDS for the recording of 5 seconds. (RECORD_SECONDS = 5)

Also, What exactly is CHUNK ?

$\endgroup$
10
$\begingroup$

So essentially, @porten pointed out what chunks of sound are.

Let's look at your code:

CHUNK = 1024
# What is CHUNKS here ?

The chunk is like a buffer, so therefore each buffer will contain 1024 samples, which you can then either keep or throw away. We use CHUNKS of data, instead of a continuous amount of audio because of processing power. (Let's assume this was a continuous flow of data being received from a Microphone and is being recorded and saved) then it would just eat up the processor, thus causing potential crashes. In terms of Raspberry Pi / Arduino development (Where the RAM is very small) CHUNKING the data like this makes the stream flow easier and thus prevents memory leaks.

Another reason:

Let's assume that you wanted to implement an algorithm for determining whether something is speech, or, is just noise. How would/could you do this using a constant stream flow of sound data? It would be very difficult. Therefore, by storing this into an array (or list in your case) you can perform analysis on this data, for example RMS. Then you could have some threshold to determine if you want to keep the data, or the data is no good. E.g.

CHUNK = 1024

var input[CHUNK] = readAudio(CHUNK); // reads in 1024 of data

// compute RMS 
a = RMS(input); 
if(a >= THRES_VALUE)
{ 
    actual += input;
}

So in this example above, we record 1024 bytes of data, we then compute RMS and check to see whether or not the sound is speech or just white-noise.

To confirm as well, the chunks contain the data.

$\endgroup$
  • $\begingroup$ perfect explanation +1000000 for that :) $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 22:56
  • 2
    $\begingroup$ @Effected No problem! You're going to have problems with this script though. Are you using this for a raspberry pi at all? $\endgroup$ – Phorce Jan 11 '14 at 22:58
  • $\begingroup$ yes, with Raspberry Pi , why would i have problems ? $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 22:59
  • 1
    $\begingroup$ @Effected - Well, have you ran this code, continuously for a reasonable amount of time? What sound card / Microphone are you using? Since the RaspPi does not have a ADC onboard? =) $\endgroup$ – Phorce Jan 11 '14 at 23:01
  • $\begingroup$ I am using this, ebay.com/itm/… , doesn't it perform conversion by itself from A to D ? I have run it for like 10 minutes or so ...never too long. $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 23:03
4
$\begingroup$

What is intended to do with the loop for is to record a determined number of seconds. This number is specified by RECORD_SECONDS.

In order to do it, it is necessary know how many samples we have to take. In your example RECORD_SECONDS = 5 , so we want to record 5 seconds.

Also, the variable RATE says how many samples are taken per second. Its unit is Hz = samples/second.

Finally, CHUNCK = 1024 says how many bytes a piece of sound will have.

Knowing this, now we can understand why the operation RATE / CHUNK * RECORD_SECONDS is done.

As I have said,

  • RATE: Hz = samples/second
  • CHUNK = bytes
  • RECORD_SECONDS = seconds

This operation is in charge of controlling how many iterations loop for makes. In every iteration, 1024 bytes are recorded (data = stream.read(CHUNK))

Therefore, to record 5 seconds, we have to take 16 000 samples/second * 5 seconds = 80 000 samples. Finally, if each iteration takes 1024 samples, the for will have to loop 80 000/1024 times.

And that's why it is necessary to write the expression RATE / CHUNK * RECORD_SECONDS in order to record the desired amount of seconds.

$\endgroup$
  • $\begingroup$ What if I want to record the audio in while and stop at ctrl+c,any work around for that.Thanks $\endgroup$ – Muhammad Younus Mar 18 at 12:35
2
$\begingroup$

Usually a data stream is broken up into chunks of data, where each chunk is some number of samples. In practice an analog to digital converter (ADC) has a buffer that you read data from it. So the buffer is also sometimes called a chunk of data. It's usually faster in practice to read many samples in a chunk, then process that chunk, instead of reading the data sample by sample.

You see the word chunk come up a lot in audio processing. Sometimes a chunrk can reference both meta data and data. For example this Wikipedia AIFF article describes several different chunks in the AIFF format.

$\endgroup$
  • $\begingroup$ So the Chunks are actually the Digitized audio signal here ? could you kindly answer while keeping in the context of my issue ? like what exactly is happening here? ...that would be really helpful. and i shall be really thankful to you. $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 21:57
  • 1
    $\begingroup$ Yes, the chunks are batches of 1024 samples of data. So it's reading blocks or chunks of data and each block contains 1024 samples. (Rate * Time_Recorded) / Chunks = Num_Chunks $\endgroup$ – porten Jan 11 '14 at 22:50
  • $\begingroup$ this does makes sense thank you :) but why the block has to 1024 samples long, what if i increases it ? $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 22:51
  • 1
    $\begingroup$ @Effected - Seems fine! I know, doing some basic speech processing on the Pi (using a similar script) it would just exit.. But, I was using a really bad sound card / Mic so good luck anyway! Glad I helped somewhat :) What is it you're trying to do, just out of interest? $\endgroup$ – Phorce Jan 11 '14 at 23:05
  • $\begingroup$ Thank you for your help..it really meant a lot to me. I am developing somewhat a BlackBox (one that in AirCrafts) prototype.. =) $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 23:06
2
$\begingroup$

This is an addition to porten's answer.

You are not exactly right with your description of rate. The rate is in Hertz, meaning in your case 44100 Hz - or 44100 samples per second. So you are basicly reading out that many digitized values from your device. So if you want to record 5 seconds, you will have to save $5\cdot 44100$ samples. Because, as porten wrote in his answer, most audio systems work with chunks (also called frames or blocks), the program will now read chunks of data. One chunk in your case is 1024 samples. So basicly the system reads 215.33 chunks out of the buffer until it has saved the whole 5 seconds of audio data.

$\endgroup$
  • $\begingroup$ Thank you this is fantastic ! What would happen if i increase the chunk size ? how does it effect the recording ? $\endgroup$ – Sufiyan Ghori Jan 11 '14 at 22:48
  • 1
    $\begingroup$ Generally you can say that increasing the chunk size, will result in more delay, because you would have to wait until the amounts of samples are ready at your device you are reading from. However this only is important if you have some real-time output of the signal. For example, if you read from a microphone, apply an effect, and want to play it back via the speakers. If you choose a chunk size of 22050, you will have to wait half a second until you actually hear the output. So generally lower chunks are preferred in realtime-systems. For recording it is not necessary. $\endgroup$ – lmNt Jan 11 '14 at 23:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.