Find the time the music sound starts - python-3.x

I have this sound file where I am looking for the time the music starts. I am limited to using only the scipy module. How do I detect the time on x axis when the sound starts?
An example figure is shown below. The Signal with higher magnitudes shows when the music.
Note sometimes there is noise in the signal which could also have high peaks.
import scipy
import numpy as np
import matplotlib.pyplot as plt
#create single signal
dt = 0.001
t= np.arange(0,6,dt)
lowFreq = np.sin(2+ np.pi*10*t)
musicFreq = 3.5*np.sin(2+np.pi*25*t)
combinedSignal = np.concatenate([lowFreq,musicFreq])
plt.plot(combinedSignal)
plt.show()

I think you can get the time when the sound start by just using:
idx_start = np.where(combinedSignal > 1)[0][0]
This will return the first index where the magnitude of your signal is greater than 1.

Related

draw signal spectrum using matplotlib

I have the following signal and I want to do the following:
s= 4*np.cos(4*np.pi*pow(10,6)*t+30)+2*np.sin(8*np.pi*pow(10,6)*t+15)+np.cos(12*np.pi*pow(10,6)*t)+0.5*np.cos(16*np.pi*pow(10,6)*t) # the signal
I want to draw signal spectrum using matplotlib and numpy,
the find its bandwidth and determine if it's periodic or not
I use this code available here(https://matplotlib.org/3.1.0/gallery/lines_bars_and_markers/spectrum_demo.html)
thanks for helping
I am not 100% sure if I now what you want to do but it seems plotting and returning all the turning points of your function should help you a lot with your problem.
Therefore you may try this:
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import argrelextrema
def func(t):
# messures the time in units of
# pow(10,6)*t
exp = 4*np.cos(4*np.pi*t+30)+\
2*np.sin(8*np.pi*t+15)+\
np.cos(12*np.pi*t)+\
0.5*np.cos(16*np.pi*t)
return exp
max_time = 2
time_steps = 400
# defining the signal
X = np.linspace(0,max_time,time_steps)
Y = func(X)
# getting all the max and min values
minimas = argrelextrema(Y, np.less)
maximas = argrelextrema(Y, np.greater)
# plot the singal
plt.plot(X,Y)
# plot minimas and maximas
plt.scatter(X[minimas],Y[minimas],color='r')
plt.scatter(X[maximas],Y[maximas],color='g')
plt.xlabel('t*10**6')
plt.ylabel('signal')
plt.show()

SymPy Plot Resolution

I just recently started learning Python (Platform: Python 3.7) for my Signal processing and communications class and so far it has been great. However, I'm having issues reproducing the same resolutional quality that's achievable with MatPlotLib and linspace (shown in the code below) when using the SymPy library. I was wondering if there is any way of achieving the same resolution?
I understand that SymPy works off the MatPlotLib library, on the back-end, but is limited in how much it actually uses. I tried adding sampling rates to the time-domain limits in the sym.plot call, like you can do with linspace, but that doesn't work. Is there anyway to call the linspace function prior to plotting, to improve the plot's resolution, or even without using linspace?
Step 1 shows the necessary plots, using MatPlotLib. Step 2 shows the code I'm trying to develop to produce the same results, but the quality of the waveform is nowhere near the same as Step 1.
import sympy as sym
import matplotlib.pyplot as plt
import numpy as np
# Step 1 & Section Identifiers
fc, fm = 10**9,10**6
wc, wm, Ac, Am = 2*np.pi*fc, 2*np.pi*fm, 8, 2
# Carrier Signal Plot
t = np.linspace(0, 5/fc, 500)
ct = Ac*np.cos(wc*t)
plt.xlabel('Time')
plt.ylabel('c(t)')
plt.plot(t,ct)
plt.show()
# Step 2 & Section Identifiers
t = sym.Symbol('t')
fc, fm = 10**7, 10**4
wc, wm = 2*sym.pi*fc, 2*sym.pi*fm
# Carrier Plot
ct = Ac*sym.cos(wc*t)
sym.plot(ct, (t, 0, 5/fc), ylabel = "C(t)")
Edit
I Found that I could turn off adaptive sampling and manually specifying the number of data points, to smooth out the signal. I have added the edited line(s) necessary to show this!
sym.plot(ct, (t, 0, 5/fc), ylabel = "C(t)", adaptive = False, nb_of_points = 500)

librosa.util.exceptions.ParameterError: Invalid shape for monophonic audio: ndim=2, shape=(1025, 5341)

I am trying to separate voice from background noise in audio file using python and then extract mfcc features
but I get "librosa.util.exceptions.ParameterError: Invalid shape for monophonic audio: ndim=2, shape=(1025, 5341) "
error
here's the code
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
import librosa
import librosa.display
import scipy
from scipy.io.wavfile import write
import soundfile as sf
from sklearn.preprocessing import normalize
from scipy.io.wavfile import read, write
from scipy.fftpack import rfft, irfft
y, sr = librosa.load('/home/osboxes/Desktop/AccentReco1/audio-files/egyptiansong.mp3', duration=124)
y=rfft(y)
# And compute the spectrogram magnitude and phase
S_full, phase = librosa.magphase(librosa.stft(y))
# We'll compare frames using cosine similarity, and aggregate similar frames
# by taking their (per-frequency) median value.
#
# To avoid being biased by local continuity, we constrain similar frames to be
# separated by at least 2 seconds.
#
# This suppresses sparse/non-repetetitive deviations from the average spectrum,
# and works well to discard vocal elements.
S_filter = librosa.decompose.nn_filter(S_full,
aggregate=np.median,
metric='cosine',
width=int(librosa.time_to_frames(2, sr=sr)))
# The output of the filter shouldn't be greater than the input
# if we assume signals are additive. Taking the pointwise minimium
# with the input spectrum forces this.
S_filter = np.minimum(S_full, S_filter)
# We can also use a margin to reduce bleed between the vocals and instrumentation masks.
# Note: the margins need not be equal for foreground and background separation
margin_i, margin_v = 2, 10
power = 2
mask_i = librosa.util.softmask(S_filter,
margin_i * (S_full - S_filter),
power=power)
mask_v = librosa.util.softmask(S_full - S_filter,
margin_v * S_filter,
power=power)
# Once we have the masks, simply multiply them with the input spectrum
# to separate the components
S_foreground = mask_v * S_full
S_background = mask_i * S_full
# extract mfcc feature from data
mfccs = np.mean(librosa.feature.mfcc(y=S_foreground, sr=sr, n_mfcc=40).T,axis=0)
print(mfccs)
any idea?
You are trying to get the MFCCs for a spectrogram.
You have to convert them back to an audio sample using inverse STFT.
from librosa.core import istft
vocals = istft(S_foreground )

FFT on MPU6050 output signal

I want to perform FFT on data array that I have extracted from MPU6050 sensor connected to Arduino UNO using Python
Please find the data sample below
0.13,0.04,1.03
0.14,0.01,1.02
0.15,-0.04,1.05
0.16,0.02,1.05
0.14,0.01,1.02
0.16,-0.03,1.04
0.15,-0.00,1.04
0.14,0.03,1.02
0.14,0.01,1.03
0.17,0.02,1.05
0.15,0.03,1.03
0.14,0.00,1.02
0.17,-0.02,1.05
0.16,0.01,1.04
0.14,0.02,1.01
0.15,0.00,1.03
0.16,0.03,1.05
0.11,0.03,1.01
0.15,-0.01,1.03
0.16,0.01,1.05
0.14,0.02,1.03
0.13,0.01,1.02
0.15,0.02,1.05
0.13,0.00,1.03
0.08,0.01,1.03
0.09,-0.01,1.03
0.09,-0.02,1.03
0.07,0.01,1.03
0.06,0.00,1.05
0.04,0.00,1.04
0.01,0.01,1.02
0.03,-0.05,1.02
-0.03,-0.05,1.03
-0.05,-0.02,1.02
I have taken 1st column (X axis) and saved in an array
Reference:https://hackaday.io/project/12109-open-source-fft-spectrum-analyzer/details
from this i took a part of FFT and the code is as below
from scipy.signal import filtfilt, iirfilter, butter, lfilter
from scipy import fftpack, arange
import numpy as np
import string
import matplotlib.pyplot as plt
sample_rate = 0.2
accx_list_MPU=[]
outputfile1='C:/Users/Meena/Desktop/SensorData.txt'
def fftfunction(array):
n=len(array)
print('The length is....',n)
k=arange(n)
fs=sample_rate/1.0
T=n/fs
freq=k/T
freq=freq[range(n//2)]
Y = fftpack.fft(array)/n
Y = Y[range(n//2)]
pyl.plot(freq, abs(Y))
pyl.grid()
ply.show()
with open(outputfile1) as f:
string1=f.readlines()
N1=len(string1)
for i in range (10,N1):
if (i%2==0):
new_list=string1[i].split(',')
l=len(new_list)
if (l==3):
accx_list_MPU.append(float(new_list[0]))
fftfunction(accx_list_MPU)
I have got the output of FFT as shown FFToutput
I do not understand if the graph is correct.. This is the first time im working with FFT and how do we relate it to data
This is what i got after the changes suggested:FFTnew
Here's a little rework of your fftfunction:
def fftfunction(array):
N = len(array)
amp_spec = abs(fftpack.fft(array)) / N
freq = np.linspace(0, 1, num=N, endpoint=False)
plt.plot(freq, amp_spec, "o-", markerfacecolor="none")
plt.xlim(0, 0.6) # easy way to hide datapoints
plt.margins(0.05, 0.05)
plt.xlabel("Frequency $f/f_{sample}$")
plt.ylabel("Amplitude spectrum")
plt.minorticks_on()
plt.grid(True, which="both")
fftfunction(X)
Specifically it removes the fs=sample_rate/1.0 part - shouldn't that be the inverse?
The plot then basically tells you how strong which frequency (relative to the sample frequency) was. Looking at your image, at f=0 you have your signal offset or mean value, which is around 0.12. For the rest of it, there's not much going on, no peaks whatsoever that indicate a certain frequency being overly present in the measurement data.

Faster plotting of real time audio signal

I have a piece of code that takes real time audio signal from audio jack of my laptop and plots its graph after some basic filtering. The problem I am facing is that the real time plotting is getting slower and slower as the program is running ahead.
Any suggestions to make this plotting faster and proceed at constant rate?? I think animation function will make it faster but was not able to formulate according to my requirement
import pyaudio
import numpy as np
import time
import matplotlib.pyplot as plt
import scipy.io.wavfile
from scipy.signal import butter, lfilter
import wave
plt.rcParams["figure.figsize"] = 8,4
RATE = 44100
CHUNK = int(RATE/2) # RATE / number of updates per second
#Filter co-efficients
nyq = 0.5 * RATE
low = 3000 / nyq
high = 6000 / nyq
b, a = butter(7, [low, high], btype='band')
#Figure structure
fig, (ax, ax2) =plt.subplots(nrows=2, sharex=True)
x = np.linspace(1, CHUNK, CHUNK)
extent = [x[0] - (x[1] - x[0]) / 2., x[-1] + (x[1] - x[0]) / 2., 0, 1]
def soundplot(stream):
t1=time.time()
data = np.array(np.fromstring(stream.read(CHUNK),dtype=np.int32))
y1 = lfilter(b, a, data)
ax.imshow(y1[np.newaxis, :], cmap="jet", aspect="auto")
plt.xlim(extent[0], extent[1])
plt.ylim(-50000000, 50000000)
ax2.plot(x, y1)
plt.pause(0.00001)
plt.cla() # which clears data but not axes
y1 = []
print(time.time()-t1)
if __name__=="__main__":
p=pyaudio.PyAudio()
stream=p.open(format=pyaudio.paInt32,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK)
for i in range(RATE):
soundplot(stream)
stream.stop_stream()
stream.close()
p.terminate()
This is a little long for a comment, and since you're asking for suggestions I think it's a semi-complete answer. There's more info and examples online about getting realtime plotting with matplotlib, if you need ideas beyond what's here. The library wasn't designed for this, but it's possible.
First step, profile the code. You can do this with
import cProfile
cProfile.run('soundplot(stream)')
That will show where most of the time is being spent.
Without doing that, I'll give a few tips, but be aware that profiling may show other causes.
First, you want to eliminate redundant function calls in the function soundplot. Both of the following are unnecessary:
plt.xlim(extent[0], extent[1])
plt.ylim(-50000000, 50000000)
They can be called once in initialization code. imshow updates these automatically, but for speed you shouldn't call that every time. Instead, in some initialization code outside the function use im=imshow(data, ...), where data is the same size as what you'll be plotting (although it may not need to be). Then, in soundplot use im.set_data(y1[np.newaxis, :]). Not having to recreate the image object each iteration will speed things up immensely.
Since the image object remains through each iteration, you'll also need to remove the call to cla(), and replace it with either show() or draw() to have the figure draw the updated image. You can do the same with the line on the second axis, using line.set_ydata(y).
Please post the before and after rate it runs at, and let me know if that helps.
Edit: some quick profiling of similar code suggests a 100-500x speedup, mostly from removing cla().
Also looking at your code, the reason for it slowing down is that cla isn't ever called on the first axis. Eventually there will be hundreds of images drawn on that axis, slowing matplotlib to a crawl.

Resources