Python Forum
Thread Rating:
  • 2 Vote(s) - 2 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Frequency Reader?
#1
a sound is played in real time then in the window resulting a frequency number 188.000 Hz, 220.000 Hz, etc and keep goes on while the sound is still played and keep resulting the numbers...

I also wanted to made a marker on some frequency for the range like :
A = 440.000 Hz
G = 120.000 Hz
D = 250.000 Hz
E = 550.000 Hz
etc

I've found a discussion that almost similar with this project I wanted to create, they put the coding like this
import pyaudio
import os
import struct
import numpy as np
import matplotlib.pyplot as plt
import time
from time import sleep

%matplotlib tk

CHUNK = 2**14 #2**15 #4096
WIDTH = 2
FORMAT = pyaudio.paInt16 
CHANNELS = 2
RATE = 44100
dt = 1.0/RATE


### frequencies of the strings for the violin (tunned in A), in Hz
f4 = 195.998   ## G3
f3 = 293.665   ## D4
f2 = 440.000   ## A4
f1 = 659.255   ## E5

n = CHUNK
freqs = np.fft.rfftfreq(n, d = dt)

def Frequency_of_position(position):
    """ Returns the frequency (Hz) of the note in from its position (halftones)
    relative to A4 in an equal tempered scale. Ex: 0 -> 440 Hz (A4), 
    12 -> 880 Hz (A5)."""
    return 440.0*(2**(1.0/12.0))**position


def Position_to_note(position):
    "A A# B C C# D D# E F F# G G#"
    SCALE = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
    LETTER = SCALE[position % 12]
    NUMBER = str(int((position+57) / 12))
    return LETTER+NUMBER

pos = np.array(range(-36,48))
vnote_freqs = np.vectorize(Frequency_of_position)
note_freqs = vnote_freqs(pos)


def get_frequency( spectrum ):
    return freqs[np.argmax(spectrum)]



class Freq_analysis(object):
    def __init__(self):
        self.pa = pyaudio.PyAudio()
        self.stream = self.open_mic_stream()
        self.plots = self.prepare_figure()
        #self.fig_and_axes = self.prepare_figure()
        #self.first_plot = self.plot_first_figure()


    def stop(self):
        self.stream.close()

    def open_mic_stream( self ):
        device_index = self.find_input_device()

        stream = self.pa.open(   format = FORMAT,
                                 channels = CHANNELS,
                                 rate = RATE,
                                 input = True,
                                 input_device_index = device_index,
                                 frames_per_buffer = CHUNK)

        return stream

    def find_input_device(self):
        device_index = None            
        for i in range( self.pa.get_device_count() ):     
            devinfo = self.pa.get_device_info_by_index(i)   
            print( "Device %d: %s"%(i,devinfo["name"]) )

            for keyword in ["mic","input"]:
                if keyword in devinfo["name"].lower():
                    print( "Found an input: device %d - %s"%    (i,devinfo["name"]) )
                    device_index = i
                    return device_index

        if device_index == None:
            print( "No preferred input found; using default input device." )

        return device_index

    def prepare_figure(self):
        plt.ion()
        fig1 = plt.figure(1, figsize = (16,6))
        wide_plot = plt.subplot(2,1,1)
        plt.vlines([f1,f2,f3,f4],1,1e17, linestyles = 'dashed')
        plt.xlabel("freq (Hz)")
        plt.ylabel("S^2 (u. arb.)")
        plt.xscale('log')
        plt.yscale('log')
        plt.xlim([80,4000])
        #plt.xlim([600,700])
        #plt.xlim([400,500])
        plt.ylim([1e0,1e17])
        spec_w, = plt.plot([1,1],[1,1], '-',c = 'blue')

        f4_plot = plt.subplot(2,4,5)
        plt.vlines(f4,1,1e17, linestyles = 'dashed')
        plt.xlabel("freq (Hz)")
        plt.ylabel("S^2 (u. arb.)")
        plt.yscale('log')
        plt.xlim([140,260])
        plt.ylim([1e0,1e17])
        spec_f4, = plt.plot([1,1],[1,1], '-',c = 'blue')

        f3_plot = plt.subplot(2,4,6)
        plt.vlines(f3,1,1e17, linestyles = 'dashed')
        plt.xlabel("freq (Hz)")
        plt.yscale('log')
        plt.xlim([220,380])
        plt.ylim([1e0,1e17])
        spec_f3, = plt.plot([1,1],[1,1], '-',c = 'blue')

        f2_plot = plt.subplot(2,4,7)
        plt.vlines(f2,1,1e17, linestyles = 'dashed')
        plt.xlabel("freq (Hz)")
        plt.yscale('log')
        plt.xlim([400,500])
        plt.ylim([1e0,1e17])
        spec_f2, = plt.plot([1,1],[1,1], '-',c = 'blue')

        f1_plot = plt.subplot(2,4,8)
        plt.vlines(f1,1,1e17, linestyles = 'dashed')
        plt.xlabel("freq (Hz)")
        plt.yscale('log')
        plt.xlim([600,700])
        plt.ylim([1e0,1e17])
        spec_f1, = plt.plot([1,1],[1,1], '-',c = 'blue')

        plt.draw()

    #return fig1, wide_plot, f1_plot, f2_plot, f3_plot, f4_plot
        return spec_w, spec_f1, spec_f2, spec_f3, spec_f4


    def PrintFreq(self, S2):
        dominant = get_frequency( S2 )
        dist = np.abs(note_freqs-dominant)
        closest_pos = pos[np.argmin(dist)]
        closest_note = Position_to_note(closest_pos)
        print(dominant, "(",closest_note, "=",Frequency_of_position(closest_pos),")")

    def listen(self):
        try:
            block = self.stream.read(CHUNK)
        except IOError:
            # An error occurred. 
            print( "Error recording.")
            return
        indata = np.array(struct.unpack("%dh"%(len(block)/2),block))
        n = indata.size
        freqs = np.fft.rfftfreq(n, d = dt)
        data_rfft = np.fft.rfft(indata)
        S2 = np.abs(data_rfft)**2
        #self.PrintFreq(block)
        #self.update_fig(block)
        self.PrintFreq(S2)
        self.update_fig(freqs, S2)

    def update_fig(self, freqs, S2):
        self.plots[0].set_xdata(freqs)
        self.plots[1].set_xdata(freqs)
        self.plots[2].set_xdata(freqs)
        self.plots[3].set_xdata(freqs)
        self.plots[4].set_xdata(freqs)

        self.plots[0].set_ydata(S2)
        self.plots[1].set_ydata(S2)
        self.plots[2].set_ydata(S2)
        self.plots[3].set_ydata(S2)
        self.plots[4].set_ydata(S2)
        plt.draw()
        plt.pause(0.001)


if __name__ == "__main__":
    Tuner = Freq_analysis()

    for i in range(100):
        Tuner.listen()
    plt.ioff()
    plt.show()
when I run the the result got me confused... Confused

Output:
Device 0: Microsoft Sound Mapper - Input Found an input: device 0 - Microsoft Sound Mapper - Input 4635.02197266 ( D8 = 4698.63628668 ) 21.533203125 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 61.9079589844 ( B1 = 61.735412657 ) 26.9165039063 ( A1 = 55.0 ) 29.6081542969 ( A1 = 55.0 ) 34.9914550781 ( A1 = 55.0 ) 18.8415527344 ( A1 = 55.0 ) 18.8415527344 ( A1 = 55.0 ) 18.8415527344 ( A1 = 55.0 ) 29.6081542969 ( A1 = 55.0 ) 18.8415527344 ( A1 = 55.0 ) 88.8244628906 ( F2 = 87.3070578583 ) 53.8330078125 ( A1 = 55.0 ) 80.7495117188 ( E2 = 82.4068892282 ) 80.7495117188 ( E2 = 82.4068892282 ) 40.3747558594 ( A1 = 55.0 ) 40.3747558594 ( A1 = 55.0 ) 43.06640625 ( A1 = 55.0 ) 86.1328125 ( F2 = 87.3070578583 ) 43.06640625 ( A1 = 55.0 ) 91.5161132813 ( F#2 = 92.4986056779 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 43.06640625 ( A1 = 55.0 ) 43.06640625 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 51.1413574219 ( A1 = 55.0 ) 16.1499023438 ( A1 = 55.0 ) 13.4582519531 ( A1 = 55.0 ) 16.1499023438 ( A1 = 55.0 ) 53.8330078125 ( A1 = 55.0 ) 40.3747558594 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 169.573974609 ( E3 = 164.813778456 ) 53.8330078125 ( A1 = 55.0 ) 40.3747558594 ( A1 = 55.0 ) 26.9165039063 ( A1 = 55.0 ) 29.6081542969 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 26.9165039063 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 29.6081542969 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 56.5246582031 ( A1 = 55.0 ) 56.5246582031 ( A1 = 55.0 ) 56.5246582031 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 113.049316406 ( A2 = 110.0 ) 142.657470703 ( C#3 = 138.591315488 ) 139.965820313 ( C#3 = 138.591315488 ) 67.2912597656 ( C2 = 65.4063913251 ) 69.9829101563 ( C#2 = 69.2956577442 ) 75.3662109375 ( D2 = 73.4161919794 ) 45.7580566406 ( A1 = 55.0 ) 142.657470703 ( C#3 = 138.591315488 ) 45.7580566406 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 113.049316406 ( A2 = 110.0 ) 113.049316406 ( A2 = 110.0 ) 51.1413574219 ( A1 = 55.0 ) 51.1413574219 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 51.1413574219 ( A1 = 55.0 ) 53.8330078125 ( A1 = 55.0 ) 48.4497070313 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 29.6081542969 ( A1 = 55.0 ) 64.599609375 ( C2 = 65.4063913251 ) 18.8415527344 ( A1 = 55.0 ) 45.7580566406 ( A1 = 55.0 ) 40.3747558594 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 34.9914550781 ( A1 = 55.0 ) 67.2912597656 ( C2 = 65.4063913251 ) 40.3747558594 ( A1 = 55.0 ) 80.7495117188 ( E2 = 82.4068892282 ) 24.2248535156 ( A1 = 55.0 ) 32.2998046875 ( A1 = 55.0 ) 24.2248535156 ( A1 = 55.0 ) 43.06640625 ( A1 = 55.0 ) 37.6831054688 ( A1 = 55.0 ) 16.1499023438 ( A1 = 55.0 )
STOPPED after that.... Huh

what I wanted is something more simple than this kind, like audio frequency analysis (perhaps...?)

Thank you in advance!
Reply
#2
what exactly is your question?
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#3
(Jul-02-2018, 12:22 PM)buran Wrote: what exactly is your question?

a real time sound frequency reader?
sorry if I being not clear Sad
Reply
#4
Unfortunately, this is not how the forum works. We are not going to do it for you. It looks like you have found a code that is a good starting point and in fact is doing more than what you want. Put some efforts to change it and get the desired results. Ask specific questions when you have a specific problem
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#5
(Jul-02-2018, 12:30 PM)buran Wrote: Unfortunately, this is not how the forum works. We are not going to do it for you. It looks like you have found a code that is a good starting point and in fact is doing more than what you want. Put some efforts to change it and get the desired results. Ask specific questions when you have a specific problem

thank you for your pointer, and once again I'm so sorry if I being so selfish asking more than what it should've been... Undecided
and I'm so glad you warning me, thank you!

I'll be working on it now, got confused because I'm still new to this kind of programming of sound analyzer but I'll try to do it 1st and find an errors that more caused problem and ask more in efficient way

(Jul-02-2018, 12:30 PM)buran Wrote: Unfortunately, this is not how the forum works. We are not going to do it for you. It looks like you have found a code that is a good starting point and in fact is doing more than what you want. Put some efforts to change it and get the desired results. Ask specific questions when you have a specific problem

But can I ask you like this, why when I run it through Jupyter the result of the data stopped there then it showing some data graphics?
(not testing thorough yet other than Jupyter)
Reply
#6
Got my answer, the answer is this :
https://pypi.org/project/frequency_analyzer/#files
Reply
#7
I gave already the answer in another thread: https://python-forum.io/Thread-PyQt-Assi...8#pid51618
I'm using itertools.product to simplify the iteration.

# without itertools.product
for band in range(-1, 3):
    for note in ('A','B','C'):
        print(band, note)

# same with itertools.product
import itertools
bands = range(-1, 3)
notes = ('A','B','C')
for band, note in itertools.product(bands, notes):
    print(band, note)
The rest is math and string concatenation or interpolation.
There are also different ways to calculate the frequencies.
I have use the midi number, which uses another formula, as your example.

Just using a ready made module may help you with your current task,
but it won't help you to understand Python and the algorithm.

BTW: I'm not sure if I name the things right: Bands, Octaves, Notes
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#8
(Jul-06-2018, 08:29 AM)DeaD_EyE Wrote: I gave already the answer in another thread: https://python-forum.io/Thread-PyQt-Assi...8#pid51618
I'm using itertools.product to simplify the iteration.

# without itertools.product
for band in range(-1, 3):
    for note in ('A','B','C'):
        print(band, note)

# same with itertools.product
import itertools
bands = range(-1, 3)
notes = ('A','B','C')
for band, note in itertools.product(bands, notes):
    print(band, note)
The rest is math and string concatenation or interpolation.
There are also different ways to calculate the frequencies.
I have use the midi number, which uses another formula, as your example.

Just using a ready made module may help you with your current task,
but it won't help you to understand Python and the algorithm.

BTW: I'm not sure if I name the things right: Bands, Octaves, Notes

This one is a bit different with the other of my post though its also need the same thing, but yes the major is analyzer itself...

But thank you very much, I'm truly appreciate all of your help and it does help me understanding a bit of how analyzer works too.
And I have a question, what's this itertools do?
when I test run the both code you posted with and without itertools, they gave the same result

(Jul-06-2018, 08:29 AM)DeaD_EyE Wrote: I gave already the answer in another thread: https://python-forum.io/Thread-PyQt-Assi...8#pid51618
I'm using itertools.product to simplify the iteration.

# without itertools.product
for band in range(-1, 3):
    for note in ('A','B','C'):
        print(band, note)

# same with itertools.product
import itertools
bands = range(-1, 3)
notes = ('A','B','C')
for band, note in itertools.product(bands, notes):
    print(band, note)
The rest is math and string concatenation or interpolation.
There are also different ways to calculate the frequencies.
I have use the midi number, which uses another formula, as your example.

Just using a ready made module may help you with your current task,
but it won't help you to understand Python and the algorithm.

BTW: I'm not sure if I name the things right: Bands, Octaves, Notes

oh yes I do also have another very confusing result that is when I run the code that I posted here it always stopped before I terminate them, so when I force close it'll say do I want to terminate them while the program still running... but the thing is the code not even give me any more results, it stopped so suddenly and even if I waited for some minutes, still no updates from before Wall
Reply
#9
I've cut the codes to simple it without the matplotlib running too, but still it's not make sense why it's always stopping in the middle of the process. And if I terminated the running file's it said if I want to close while it still running...
but actually nothing happening at all no update of the data or whatsoever

here is the updated code without the matplotlib
import pyaudio
import os
import struct
import numpy as np
import time
from time import sleep


CHUNK = 2**14 #2**15 #4096
WIDTH = 2
FORMAT = pyaudio.paInt16 
CHANNELS = 2
RATE = 44100
dt = 1.0/RATE


### frequencies of the strings for the violin (tunned in A), in Hz
f4 = 195.998   ## G3
f3 = 293.665   ## D4
f2 = 440.000   ## A4
f1 = 659.255   ## E5

n = CHUNK
freqs = np.fft.rfftfreq(n, d = dt)

def Frequency_of_position(position):
    """ Returns the frequency (Hz) of the note in from its position (halftones)
    relative to A4 in an equal tempered scale. Ex: 0 -> 440 Hz (A4), 
    12 -> 880 Hz (A5)."""
    return 440.0*(2**(1.0/12.0))**position


def Position_to_note(position):
    "A A# B C C# D D# E F F# G G#"
    SCALE = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
    LETTER = SCALE[position % 12]
    NUMBER = str(int((position+57) / 12))
    return LETTER+NUMBER

pos = np.array(range(-36,48))
vnote_freqs = np.vectorize(Frequency_of_position)
note_freqs = vnote_freqs(pos)


def get_frequency( spectrum ):
    return freqs[np.argmax(spectrum)]

class Freq_analysis(object):
    def __init__(self):
        self.pa = pyaudio.PyAudio()
        self.stream = self.open_mic_stream()

    def stop(self):
        self.stream.close()

    def open_mic_stream( self ):
        device_index = self.find_input_device()

        stream = self.pa.open(   format = FORMAT,
                                 channels = CHANNELS,
                                 rate = RATE,
                                 input = True,
                                 input_device_index = device_index,
                                 frames_per_buffer = CHUNK)

        return stream

    def find_input_device(self):
        device_index = None            
        for i in range( self.pa.get_device_count() ):     
            devinfo = self.pa.get_device_info_by_index(i)   
            print( "Device %d: %s"%(i,devinfo["name"]) )

            for keyword in ["mic","input"]:
                if keyword in devinfo["name"].lower():
                    print( "Found an input: device %d - %s"%    (i,devinfo["name"]) )
                    device_index = i
                    return device_index

        if device_index == None:
            print( "No preferred input found; using default input device." )

        return device_index

    def PrintFreq(self, S2):
        dominant = get_frequency( S2 )
        dist = np.abs(note_freqs-dominant)
        closest_pos = pos[np.argmin(dist)]
        closest_note = Position_to_note(closest_pos)
        print(dominant, "(",closest_note, "=",Frequency_of_position(closest_pos),")")

    def listen(self):
        try:
            block = self.stream.read(CHUNK)
        except IOError:
            # An error occurred. 
            print( "Error recording.")
            return
        indata = np.array(struct.unpack("%dh"%(len(block)/2),block))
        n = indata.size
        freqs = np.fft.rfftfreq(n, d = dt)
        data_rfft = np.fft.rfft(indata)
        S2 = np.abs(data_rfft)**2
        #self.PrintFreq(block)
        #self.update_fig(block)
        self.PrintFreq(S2)
        
if __name__ == "__main__":
    Tuner = Freq_analysis()

    for i in range(100):
        Tuner.listen()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How to optimize analog gauge reader? kadink 0 724 May-19-2023, 08:58 PM
Last Post: kadink
  vtk reader paul18fr 1 1,499 Feb-07-2022, 10:21 PM
Last Post: Larz60+
  Reset csv.reader Huck 16 20,156 Aug-01-2018, 04:20 PM
Last Post: Huck

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020