0

I'm using PyAudio (which is just a Python wrapper for PortAudio) to register auditory responses from users; I want to create a little calibration animation involving a dot that dynamically grows and shrinks in response to the peak amplitude over a given sampling period.

The problem is that I can't translate amplitude to pixels meaningfully until I know what the maximum amplitude might be for any given device (PortAudio's API just describes this an unsigned long, and as I understand it, is just the unmodified amplitude as measured by the input device, whose range of values is going to vary basically on the quality of the gear).

Is there a way to have PortAudio report the maximum amplitude value possible from the input device (presumably once the stream is initialized)?

Jonline
  • 1,677
  • 2
  • 22
  • 53

1 Answers1

2

The minimum and maximum values that you can possibly receive from an input device depend on the sample format used, which is normally an signed integer. For example if you're using the pyaudio.paInt16 format, the samples are 16-bit integers, so their range is from -32,768 to 32,767. There is no "unsigned long" sample format.

The actual range input values will depend on a number of factors outside of the control any audio API. Things like the microphone you're using, how loudly people speak and any amplifiers or other devices that might be in between the microphone and ADC that converts the analogue audio to digital. You'll probably need to calibrate your setup so that it uses a useful portion of the digital sample range.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
  • So this makes sense (and also, on closer examination of the PortAudio API, I was indeed misreading when I reported an unsigned long), but, it also doesn't agree with my experience so far and I'm hoping you can clarify; intuitively, waveforms ought to be described by a signed value, yet my testing returns values of zero (ostensibly silence?) or more. Second question to follow (if I can impose!). – Jonline Dec 02 '15 at 14:22
  • Re: the range of values being contingent on the hardware, this too makes sense. But how to "calibrate" this (ie. establish a max value) without subjecting the local context to something loud enough to cause the DAC to clip (neither feasible nor desirable)? Might *writing* increasingly large values to the stream eventually throw an error or otherwise signal having reached the local device's ceiling? Or should I expect the output and input to have independent amplitude ranges? Also, I'm out of my depth here so pardon any hcore nubbing. – Jonline Dec 02 '15 at 14:23
  • PyAudio's `Stream.read` method returns the samples as a string of bytes. To interpret the samples correctly you need to convert the string into array of the same type as the samples. (eg. For `paInt16` you would use something like `samples = array.array(strm.read(...), 'h')` If you convert it to the wrong type (or don't convert it at all) the "samples" will be in the range of the converted type, but they'll be the wrong values. – Ross Ridge Dec 02 '15 at 18:13
  • 1
    You can't write too large of a sample value. The minimum and maximum output value is also determined by the sample format. If you're using `paInt16` there's no way to output a sample with a value greater than 32,767. How loud this value is depends on everything that exists between the DAC and your ears. The volume control of your output device, the volume control of your amplifier, the speakers you're using, how far you are from the speakers, etc. Also regardless of the sample format, outputting the maximum value results in the same maximum output from the DAC. More bits give more precision. – Ross Ridge Dec 02 '15 at 18:23