Search code examples
c++loopsaudiojuce

Why is this looping of audio code using so much CPU/Memory?


void FilePlayer::setLooping(const bool newState, float startPos)
{
while (newState == true)
{
    float endPos = startPos + 4/audioTransportSource.getLengthInSeconds();

    float currentPos = audioTransportSource.getCurrentPosition()/audioTransportSource.getLengthInSeconds();

    if (currentPos == endPos || currentPos > endPos)
    {
        audioTransportSource.setPosition(startPos * audioTransportSource.getLengthInSeconds());
    }
}
}

This is code for looping 4 seconds of any audio file no matter how long. You click the loop button and the newState variable becomes true. I have another button that turns it to false, however, when I perform the looping task in the application the CPU/Memory/Energy Impact go through the roof and the application becomes unusable to the point I cannot click on the button to end the loop.

Can someone explain to me why this is?


Solution

  • Have you tried adding a sleep call or making sure you return to your main event loop in order to process the button click event?

    Edit: also, should your newState variable be passed by reference (and not const) instead so you can change the value in order to stop the loop?

    Edit2: A really basic/simple threading example:

    FilePlayer.h

    #include <iostream>
    #include <thread>
    #include <chrono>
    #include <atomic>
    #include <mutex>
    
    class 
    {
    public:
        /**
          * @brief Constructor
          */
        FilePlayer();
    
        /**
         * @brief Destructor
         */
        ~FilePlayer();
    
    private:
        /**
         * @brief startThread Starts the thread
         */
        void startThread();
    
        /**
         * @brief stopThread Stops the thread
         */
        void stopThread();
    
        /**
         * @brief theLoop The threaded loop
         */
        void theLoop(float startPos);
    
        std::atomic<bool> running; //lock for thread control
        std::mutex mtxAudioTransportSource; //mutex lock for audioTransportSource access
        std::thread td;   
    
    }
    

    FilePlayer.cpp

    FilePlayer::FilePlayer()
    {
        running.store(false);
    }
    
    FilePlayer::~FilePlayer()
    {
        stopThreads();
    }
    
    void FilePlayer::startThreads()
    {
        if(running.load()){
            //The thread is alread running, either call stopThreads before making a different one
            //or error out (I just put return in)
            return;
        }
        running.store(true);
        td = thread(theLoop, 1.0);
    }
    
    void FilePlayer::stopThreads()
    {
        running.store(false);
        if(td.joinable()){
            td.join();
        }
        delete td;
        td = NULL;
    }
    
    void FilePlayer::theLoop(float startPos)
    {
        while (running.load())
        {
            mtxAudioTransportSource.lock(); //Since the audioTransportSource object is being used in multiple threads, 
                                            //you must use a mutex lock to make sure only 1 thread is accessing it at any time
                                            //you will need to add the lock/unlock to all threads using it.
    
                                            //It is often a good idea to lock, get what you need, and unlock as soon as possible so
                                            //the other thread isn't blocked for too long if it is waiting on it.
    
            float audioLength = audioTransportSource.getLengthInSeconds();
            float currentPos = audioTransportSource.getCurrentPosition()/audioLength;
    
            mtxAudioTransportSource.unlock();
    
            float endPos = startPos + 4/audioLength;
    
            if (currentPos >= endPos)
            {
                mtxAudioTransportSource.lock();
                audioTransportSource.setPosition(startPos * audioTransportSource.getLengthInSeconds());
                mtxAudioTransportSource.unlock();
            }
    
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    

    So I didn't compile this at all so there might be some errors but this is just supposed to be somewhat of an example for you to work off of. If anyone has any corrections or optimizations please feel free to say so. The most important thing to remember about threading is to never access a shared variable without using some kind of lock. Good luck with your project!