Creating and playing multiple ofSoundPlayers when detecting a circle

Hello!

I am using HoughCircles to detect circles from the video camera, and I want to play back a sound each time a circle is detected. With this code, a new player is created each time a circle is detected. I would create the beforehand in setup, but since I have no idea how many circles I will detect, I have to make them on the fly. The end goal is to have the app load and play a different sound depending on where the circle is detected on the screen. For now I am using the same sound.

I feel like though that I need to delete each player once its done, because the app stops playing sounds after awhile (it looks like it creates up to ~250 players, then no more sound).

Code is here: https://github.com/jdiedrick/circlesounds

And below:

####.h
#pragma once

#include "ofxiOS.h"
#include "ofxCv.h"
#include "ofxGui.h"

class ofApp : public ofxiOSApp {

public:
    void setup();
    void update();
    void draw();
    void exit();

    void touchDown(ofTouchEventArgs & touch);
    void touchMoved(ofTouchEventArgs & touch);
    void touchUp(ofTouchEventArgs & touch);
    void touchDoubleTap(ofTouchEventArgs & touch);
    void touchCancelled(ofTouchEventArgs & touch);

    void lostFocus();
    void gotFocus();
    void gotMemoryWarning();
    void deviceOrientationChanged(int newOrientation);

ofImage img;

//for video grabber
ofVideoGrabber grabber;
ofImage gray;

cv::Mat cvMat;

vector<cv::Vec3f> circles;

ofxPanel gui;

ofxIntSlider dp_param;
ofxIntSlider mindist_param;
ofxIntSlider param1_param;
ofxIntSlider param2_param;
ofxIntSlider minradius_param;
ofxIntSlider maxradius_param;
ofxLabel numCircles;


//sound
ofSoundPlayer  vocals;
vector<ofSoundPlayer> players;

int numPlayers;
};

####.mm

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

//work with video grabber
grabber.initGrabber(ofGetWidth(), ofGetHeight());
gray.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_GRAYSCALE);
ofxCv::allocate(cvMat, ofGetWidth(), ofGetHeight(), OF_IMAGE_GRAYSCALE);

//setup gui
gui.setup(); // most of the time you don't need a name
gui.add(dp_param.setup("dp param", 1, 0, 10));
gui.add(mindist_param.setup("min dist param", 200, 1, 1000));
gui.add(param1_param.setup("param1 param", 130, 0, 500));
gui.add(param2_param.setup("param2 param", 30, 0, 100));
gui.add(minradius_param.setup("min. radius param", 0, 0, 500));
gui.add(maxradius_param.setup("max. radius param", 400, 0, 500));
gui.add(numCircles.setup("# of circles size", ofToString((int)circles.size())));

numPlayers = 0; // keep track of how many players we're making

}

void ofApp::update(){

//ofSoundUpdate();


for (int i=0; i<players.size(); i++){
    cout << "playing player #: " << i << endl;
    players[i]->play();
}

players.clear();

grabber.update();
if (grabber.isFrameNew()){

    circles.clear();

    ofxCv::convertColor(grabber, gray, CV_RGB2GRAY);
    gray.update();
    
    cvMat = ofxCv::toCv(gray);
    cv::GaussianBlur( cvMat, cvMat, cv::Size(9, 9), 2, 2 );
    
    cv::HoughCircles( cvMat,
                     circles,
                     CV_HOUGH_GRADIENT,
                     dp_param,
                     mindist_param,
                     param1_param,
                     param2_param,
                     minradius_param,
                     maxradius_param );

    std::cout << "num circles " << circles.size() << endl;

    for (int i=0; i<circles.size(); i++){
        
        numPlayers++; // count number of players we're making
        cout << "num players: " << numPlayers << endl;
        
        ofSoundPlayer * player = new ofSoundPlayer();
        player->load("synth.mp3");
        //player->setVolume(ofMap(circles[i][2], 0, 100, 0.1, 1.0));
        //player->setSpeed( 0.1f + ((float)(ofGetHeight() - circles[i][1]) / (float)ofGetHeight()));
        players.push_back(player);
        
        /*
        if(player->isLoaded()){
            player->play();
        }
        */
        //players.clear();
        /*
        if(!player->isPlaying()){
            delete player;
        }
         */
    }
}

}

 //--------------------------------------------------------------
void ofApp::draw(){
gray.draw(0, 0);

ofPushStyle();
ofSetColor(255, 0, 0);
ofNoFill();
for (int i=0; i<circles.size(); i++) {
    ofDrawCircle(circles[i][0], circles[i][1], circles[i][2]);
}
ofPopStyle();

gui.draw();
}

I feel like the way to do this would actually just be to use multiplay (I’ve been working off of the ofSoundPlayer example), but that isn’t supported on iOS…

I tried two methods as you can see in my code: deleting the pointer with the delete keyword after playing, or adding all the players to a vector clearing the vector after playing. Unfortunately I think I’m missing a bit of C++ essentials, but I feel like I’m almost there! Any help and strategies are much appreciated.

i think ofRemove might be what you’re looking for.
i don’t use ofSoundPlayer, but if you can have a bool that’d know if the soundPlayer has played or not then running the ofRemove code, testing whether that bool is true or not will then remove the relevant sound player from memory.