GithubHelp home page GithubHelp logo

tomschimansky / guitartuner Goto Github PK

View Code? Open in Web Editor NEW
144.0 3.0 48.0 46.99 MB

Guitar tuner program made with Python, Tkinter and PyAudio.

License: GNU General Public License v2.0

Python 100.00%
python pyaudio music tuner tkinter py2app guitar-tuner tkinter-gui gui-application audio-analysis

guitartuner's Introduction

GitHub release (latest by date) GitHub all releases GitHub Release Date

GuitarTuner App

This is a simple chromatic tuner designed for guitar tuning, but it should also work with every other instrument. The played note is automatically recognized through the microphone, and an acoustic signal is heard when the tuning is correct. If you want you can also change the reference-tone to another frequency. At the moment, a compiled version is only available for macOS, but you can use it on Windows too if you run it in the command line.

  • Automatic tone detection
  • High accuracy: < 0.5 cents (around the A4 area)
  • Working from 60 to 2000 Hz (C2 to C7)
  • High stability of the pitch indicator
  • Support for macOS light and dark-mode

➜️ Download macOS app (Intel only): Download here

Functionality

The app is written in Python with Tkinter, PyAudio and numpy. It uses PyAudio to get access to the raw audio-stream coming from the microphone. Then a fast-fourier-transformation (numpy.fft) is applied on the audio-data, which is buffered for about 1.5 seconds. Then a HPS (Harmonic Product Spectrum) operation is applied to filter the harmonic frequencies. From the HPS output, you can get the loudest frequency and convert it to a musical note by applying the following formula: 12 * numpy.log2(f / a4_frequency) + 69.

Run GuitarTuner with python

First you need to install all necessary libraries:

pip3 install -r requirements.txt

Then you can do:

python3 main.py

Create standalone application

You can also create a standalone application for macOS or Windows by yourself. For macOS you can use py2app:

python3.8 setup.py py2app

For windows, you would need to use py2exe instead and modify the setup.py file.

To keep application size as small as possible, make sure you create a virtual environment where you install only the necessary libraries. The macOS dark-mode currently only works with the anaconda python Version. If you compile the app with a python.org version, you have to disable the dark-mode by deleting the 'NSRequiresAquaSystemAppearance': Falseentry in setup.py, which causes the application window to go into dark-mode.

guitartuner's People

Contributors

tomschimansky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

guitartuner's Issues

standalone app

Hello Tom! I'm trying to build a standalone app from source. However, after creating the GuitarTuner.app application and launching it, the macOS does not ask for permission to use the microphone. At the same time, your application copied from dmg works fine. What am I doing wrong?

[FUN] ChatGPT rewrites and optimizes your code

User:
Convert this Python code into a more efficient (in terms of performances) programming language: <pasted audio_analyzer.py source>

ChatGPT:
To convert this Python code into a more performance-efficient language, such as C or C++, we'll need to rewrite the core functionality using appropriate libraries and structures to handle audio input, Fourier transforms, and multithreading. Here's a general outline of how you might approach this in C++ using libraries like PortAudio and FFTW for audio input and Fourier analysis.

Steps to Rewrite in C++:

  1. Include Necessary Libraries:
    Use C++ libraries like PortAudio for audio input and output, and FFTW (Fastest Fourier Transform in the West) for efficient Fourier transforms.

    #include <iostream>
    #include <cmath>
    #include <vector>
    #include <portaudio.h>
    #include <fftw3.h>
    #include <thread>
    #include <mutex>
    #include <queue>
    #include <chrono>
  2. Define AudioAnalyzer Class:
    Use a class to encapsulate the audio analysis functionality, similar to the Python AudioAnalyzer class.

    class AudioAnalyzer {
    public:
        AudioAnalyzer(std::queue<double>& queue);
        void start();
        void stop();
    
    private:
        std::queue<double>& queue_;
        PaStream* stream_;
        bool running_;
        const int samplingRate_ = 48000;
        const int chunkSize_ = 1024;
        const int bufferTimes_ = 50;
        const int zeroPadding_ = 3;
        const int numHps_ = 3;
    
        std::vector<double> buffer_;
        std::vector<double> hanningWindow_;
    
        void processAudio();
        static void audioCallback(const void* inputBuffer, void* outputBuffer,
                                  unsigned long framesPerBuffer,
                                  const PaStreamCallbackTimeInfo* timeInfo,
                                  PaStreamCallbackFlags statusFlags,
                                  void* userData);
    };
  3. Implement Constructor and Methods:
    Implement the constructor, start(), stop(), and processAudio() methods.

    AudioAnalyzer::AudioAnalyzer(std::queue<double>& queue) 
        : queue_(queue), running_(false), buffer_(chunkSize_ * bufferTimes_, 0.0), 
          hanningWindow_(chunkSize_)
    {
        // Initialize hanning window
        for (size_t i = 0; i < chunkSize_; ++i) {
            hanningWindow_[i] = 0.5 * (1 - cos(2 * M_PI * i / chunkSize_));
        }
    }
    
    void AudioAnalyzer::start() {
        running_ = true;
        Pa_Initialize();
        Pa_OpenDefaultStream(&stream_, 1, 0, paInt16, samplingRate_, chunkSize_,
                             audioCallback, this);
        Pa_StartStream(stream_);
    }
    
    void AudioAnalyzer::stop() {
        running_ = false;
        Pa_StopStream(stream_);
        Pa_CloseStream(stream_);
        Pa_Terminate();
    }
    
    void AudioAnalyzer::processAudio() {
        // Implement audio processing logic here
        // This is similar to the Python run() method
    }
    
    void AudioAnalyzer::audioCallback(const void* inputBuffer, void* outputBuffer,
                                      unsigned long framesPerBuffer,
                                      const PaStreamCallbackTimeInfo* timeInfo,
                                      PaStreamCallbackFlags statusFlags,
                                      void* userData) {
        auto analyzer = reinterpret_cast<AudioAnalyzer*>(userData);
        const int16_t* data = static_cast<const int16_t*>(inputBuffer);
    
        // Process the audio data
        analyzer->processAudio();
        
        return paContinue;
    }
  4. Implement Audio Processing Logic:
    Translate the audio processing logic from Python (Fourier transform, HPS algorithm, etc.) to C++ using FFTW for Fourier transforms.

    void AudioAnalyzer::processAudio() {
        // Implement the audio processing logic
        // Similar to the Python run() method
    }
  5. Main Function:
    In the main() function, create a std::queue and AudioAnalyzer instance, then start processing.

    int main() {
        std::queue<double> q;
        AudioAnalyzer analyzer(q);
        analyzer.start();
    
        while (true) {
            if (!q.empty()) {
                double freq = q.front();
                std::cout << "Loudest frequency: " << freq
                          << " Nearest note: " << analyzer.frequencyToNoteName(freq, 440)
                          << std::endl;
                q.pop();
                std::this_thread::sleep_for(std::chrono::milliseconds(20));
            }
        }
    
        analyzer.stop();
        return 0;
    }

Additional Notes:

  • Error Handling: In C++, you need to handle errors explicitly using try-catch blocks or error codes returned by functions.
  • Memory Management: Use appropriate memory management techniques (e.g., smart pointers) to avoid memory leaks.
  • Concurrency: Ensure thread safety using mutexes or locks when accessing shared data structures like the queue.

This outline provides a starting point for rewriting the Python audio analysis code in C++. You'll need to fill in the details for audio processing and error handling based on your specific requirements and the capabilities of the chosen libraries.

User:
OK, now optimize the rewritten code for speed/efficency

ChatGPT:
To optimize the C++ code for speed and efficiency, we can focus on several key areas such as optimizing the audio processing pipeline, leveraging multithreading for parallelization, and using efficient data structures and algorithms. Below are some optimizations and best practices to enhance the performance of the rewritten code.

1. Use Efficient Data Structures and Memory Management:

  • Use std::vector Instead of std::queue: std::vector can be more efficient than std::queue for storing and accessing audio data frames due to better cache locality.
std::vector<double> audioBuffer(chunkSize_ * bufferTimes_, 0.0);

2. Optimize Audio Processing Pipeline:

  • Minimize Memory Allocations: Allocate memory buffers (e.g., FFT input/output buffers) once outside the processing loop to avoid frequent memory allocations.
// Allocate FFT input and output buffers
std::vector<double> fftInput(chunkSize_, 0.0);
std::vector<double> fftOutput(chunkSize_, 0.0);

// Initialize FFTW plans for efficiency
fftw_plan fftPlan = fftw_plan_r2r_1d(chunkSize_, fftInput.data(), fftOutput.data(), FFTW_R2HC, FFTW_MEASURE);

3. Leverage Multithreading for Parallelization:

  • Use std::thread for Parallel Processing: Launch separate threads for audio input/output and audio processing to utilize multiple CPU cores.
std::thread audioThread(&AudioAnalyzer::processAudio, this);
  • Thread-Safe Access to Shared Data: Use mutexes (std::mutex) to protect shared data structures (e.g., audio buffers) when accessed by multiple threads.

4. Efficient Fourier Transform (FFT) Using FFTW:

  • Reuse FFT Plans: Create and reuse FFTW plans (fftw_plan) to avoid repetitive planning overhead.
// Create FFTW plan for efficiency
fftw_plan fftPlan = fftw_plan_r2r_1d(chunkSize_, fftInput.data(), fftOutput.data(), FFTW_R2HC, FFTW_MEASURE);

// Inside processAudio(), use the plan:
fftw_execute(fftPlan);

5. Avoid Unnecessary Copying of Data:

  • Minimize Data Copies: Avoid unnecessary copying of audio data by passing pointers or references to data buffers.
// Inside audioCallback(), pass data buffer directly to processAudio()
analyzer->processAudio(data);

6. Compiler Optimizations:

  • Enable Compiler Optimizations: Use compiler flags (-O3 for GCC/Clang) to enable aggressive optimizations, inline functions, and vectorization.

Example Optimized Code:

// Example optimized processAudio() method
void AudioAnalyzer::processAudio(const int16_t* inputData) {
    // Copy input data to buffer
    std::copy(inputData, inputData + chunkSize_, audioBuffer.begin());

    // Apply Hanning window
    for (size_t i = 0; i < chunkSize_; ++i) {
        audioBuffer[i] *= hanningWindow_[i];
    }

    // Execute FFT
    fftw_execute(fftPlan);

    // Process FFT output (e.g., calculate magnitude spectrum, apply HPS)
    // Update result in the queue (e.g., loudest frequency)

    double loudestFrequency = ...; // Calculate loudest frequency

    // Protect queue access with a mutex
    {
        std::lock_guard<std::mutex> lock(queueMutex_);
        queue_.push(loudestFrequency);
    }
}

Final Notes:

  • Profile and Benchmark: Use profiling tools (gprof, perf) to identify performance bottlenecks and optimize critical sections of the code.
  • Experiment with Compiler Flags: Try different compiler optimization flags and settings to achieve the best performance.
  • Use SIMD Instructions (Optional): Consider using SIMD (Single Instruction, Multiple Data) instructions (e.g., SSE/AVX) for further optimization of audio processing routines.

By applying these optimizations, you can significantly improve the speed and efficiency of the C++ audio analyzer compared to the original Python implementation. Remember to test the code on target hardware and adjust optimizations based on performance metrics and requirements.

More @ https://chat.openai.com/share/7acc35fe-d6c2-4bd4-b238-dc9934bd1111

...it would be interesting to test if the rewritten code is working or it's just an illusion...

.clap plugin

this would be useful to port into a .clap plugin

Custom Frame in TkinterCustomButton

Hey!
Here's a sample of my code:

    CloseBtn = TkinterCustomButton(titleBarCus
                                            ,text="YouTube",
    corner_radius=1, fg_color="red", command=root.destroy)
   CloseBtn.pack(side=RIGHT, anchor="ne")

When I'm adding a frame name in first parameter it shows me this error:

Traceback (most recent call last):
  File "E:\Programming\Python Projects\ShareDocs\main.py", line 39, in <module>
    shareDocsCloseBtn = TkinterCustomButton(titleBarCus
  File "E:\Programming\Python Projects\ShareDocs\tkinter_custom_button.py", line 89, in __init__
    self.canvas = tkinter.Canvas(master=self,
  File "C:\Users\SimpleSmartTech\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 2684, in __init__
    Widget.__init__(self, master, 'canvas', cnf, kw)
  File "C:\Users\SimpleSmartTech\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 2568, in __init__
    self.tk.call(
_tkinter.TclError: unknown color name ".!frame"

Too much Thanks For your Effort and providing it for free...

I got the solution from your code...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.