0
$\begingroup$

I'm doing some MIR related work with stereo audio and am a little unsure on how to proceed with some basic tasks. All my academic work prior to this has involved forcing audio to "mono" to perform analysis, and I'm trying to avoid that as much as possible here.

So, for example, I have a crest factor function in python that looks like this for an array of audio data (either mono, left, or right channel):

def get_cf(data, win_size):
    """
    data: audio array in mono, left, or right channel only
    win_size: size in samples for the block analysis (created in calc_crest_factor)

    calc_crest_factor passes mono style data to this function to get the crest factor.

    returns: the crest factor for each window"""
    # Buffer the signal matrix-style (input, block-size, hop-size)
    data_matrix = librosa.util.frame(data, win_size, win_size)

    peaks = np.amax(np.absolute(data_matrix), axis=0)

    # Get the mean-square over each window
    RMS = np.sqrt(np.mean(np.square(data_matrix), axis=0))

    # Get crest factor for each window
    return np.divide(peaks, RMS)

In another function, I call the function above like so for stereo audio:

 if len(data) == 2:
    crest_factor_l = get_cf(data[0,:], win_size)
    crest_factor_r = get_cf(data[1,:], win_size)

And here I now have a crest factor for the right channel and one for the left channel, but am unsure on how to proceed on getting a final "crest factor" value for the audio. Do I just choose the greater of the two values for each window? Or is it more correct to keep both values?

This same question goes for RMS too. I know in my pro audio applications, stereo audio gets passed to some RMS calculator and a single value gets pumped out. How do the two separate channels with two separate values for either Crest Factor or RMS become 1 value while honoring the "stereoness" of the data?

$\endgroup$
2
  • 2
    $\begingroup$ the crest factor is the ratio of two "norms". it is the $L^{\infty}$ norm divided by the $L^2$ norm . you can define that meaningfully for two (or more) channels, just as well as for one mono channel. $\endgroup$ Nov 22, 2015 at 2:50
  • $\begingroup$ @Rdotyung Sorry I am new to sound recordings, but just understand is window size same as the frame or width? consider the following bit of code p = pyaudio.PyAudio() stream = p.open(format=p.get_format_from_width(WIDTH), channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK) $\endgroup$ Feb 28, 2018 at 14:28

3 Answers 3

2
$\begingroup$

Conceptually you can think of it as creating one mono signal by concatenating the left and the right channel signals, and then computing the RMS and the Crest factor of that mono signal. With $N$ the number of samples in the current frame, and $x_l[n]$ and $x_r[n]$ the left and right channel signals, respectively, you get the following formulas:

$$\begin{align}x_{\text{rms}}&=\sqrt{\frac{1}{2N}\left[\sum_{n=0}^{N-1}x^2_l[n]+\sum_{n=0}^{N-1}x^2_r[n]\right]}=\sqrt{\frac12\left(x^2_{l,\text{rms}}+x^2_{r,\text{rms}}\right)}\\ C&=\frac{\max\{|x_l[n]|,|x_r[n]|\}}{x_{\text{rms}}}\end{align}$$

where $x_{l,\text{rms}}$ and $x_{r,\text{rms}}$ are the RMS values of the left and right channel, respectively.

$\endgroup$
3
  • $\begingroup$ Awesome! Thank you. Is it safe to use this thought process in other situations involving stereo data? $\endgroup$ Nov 22, 2015 at 17:39
  • $\begingroup$ @Rdotyung: Not sure which other situations you have in mind. Just think if it makes sense according to the definition of the respective quantity. $\endgroup$
    – Matt L.
    Nov 22, 2015 at 17:42
  • $\begingroup$ So for instance, right now I want to calculate the Spectral Centroid on a stereo audio file. However, this involves having both a left and right channel STFT, and I'm not sure how to combine the two for "stereo". Most MIR documentation is always mono. $\endgroup$ Jan 6, 2016 at 18:38
0
$\begingroup$
import librosa

# Load an audio file (replace 'your_audio_file.wav' with your file path)
audio_file = 'your_audio_file.wav'
y, sr = librosa.load(audio_file)

# Calculate the peak level (maximum value)
peak_level = max(abs(y))

# Calculate the RMS (average level) using librosa's rms function
rms = librosa.feature.rms(y=y)[0]

# Calculate the crest factor
crest_factor = peak_level / rms

print(f"Crest Factor: {crest_factor}")
$\endgroup$
1
  • $\begingroup$ Please avoid posting code-only answers. Although your code may be correct, there is no explanation of the logic behind it or justification for it. Try adding some more information as to why you performed the actions you did and what you achieved with each one of them. $\endgroup$
    – ZaellixA
    Oct 20, 2023 at 10:48
0
$\begingroup$

This answer averages the two RMS values for each channel. But when a stereo signal is played over two loudspeakers the overall acoustic RMS value will increase (by something like $+ 3$dB) - not average. Thus I think the $1/2$ multiplier term in the $x_{rms}$ equation should not be applied.

Then what to do with the peak for a stereo signal?

I think the peak value acoustically will be the largest in-phase summed value for both channels. So you might try summing both channels, then look for the maximum absolute value. Then combine this pair of values as a power:

e.g.:
Find index $n$ that gives the maximum of $\left| x_{l} + x_{r} \right|$. Then the overall peak value will be $\sqrt{x_{l}^{2} \left[ n \right] + x_{r}^{2} \left[ n \right])}$

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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