Hello dear coding people:
I hope you are in good health and everything is ending with code 0.
I am currently implementing a sequencer with a sample-accurate metronome with oF. This metronome class was originally written by me using the JUCE framework and was tested and working properly under that paradigm. Anyway, because of things that do not matter now, I want to write my app using oF. The metronome class counts the samples in the output buffer using the scheduled call to audioOut() to calculate when the next bang should be to start copying the sample data.
I succeded in “translating” the class from JUCE to oF but found that the metronome under oF was running very slow, so I started checking the chain of methods that were called from ofApp onwards.
Long story short: with bufferSize = 512 and sampleRate = 48000, I found out that the audioIn() and audioOut() methods are called every 42647 plus minus 135 microseconds (!!?). This number should be 10666.7 microseconds, almost exactly one fourth of the figure I’m measuring.
So I went to a minimal code for testing this. Below is just what I wrote based on the audioInputExample and the chrono c++ library for showing this issue.
Other useful data: oF version: of_v20230709_linux64gcc6_release, running on a Lenovo T450, compiled using g++ (Debian 12.2.0-14) 12.2.0.
Any hints on this, please? Thank you very much in advance.
GusCarr
ofApp.h:
#pragma once
#include "ofMain.h"
#include "chrono"
#include <iostream>
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
void audioIn(ofSoundBuffer & input);
void audioOut(ofSoundBuffer & buffer);
vector <float> left;
vector <float> right;
vector <float> volHistory;
int bufferSize {512};
int sampleRate {48000};
int bufferCounter {0};
int drawCounter {0};
double secondsCounter {0};
float smoothedVol;
float scaledVol;
ofSoundStream soundStream;
std::chrono::steady_clock::time_point ibegin;
std::chrono::steady_clock::time_point iend; /
std::chrono::steady_clock::time_point obegin;
std::chrono::steady_clock::time_point oend;
string idife {""};
string odife {""};
};
ofApp.cpp (relevant methods only)
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofSetVerticalSync(true);
ofSetCircleResolution(80);
ofBackground(54, 54, 54);
left.assign(bufferSize, 0.0);
right.assign(bufferSize, 0.0);
volHistory.assign(400, 0.0);
bufferCounter = 0;
drawCounter = 0;
smoothedVol = 0.0;
scaledVol = 0.0;
ofSoundStreamSettings settings;
auto devices = soundStream.getMatchingDevices("default");
if(!devices.empty()) settings.setInDevice(devices[0]);
settings.setInListener(this);
settings.setOutListener(this);
settings.sampleRate = sampleRate;
settings.numOutputChannels = 2;
settings.numInputChannels = 2;
settings.bufferSize = bufferSize;
soundStream.setup(settings);
ibegin = std::chrono::steady_clock::now();
iend = std::chrono::steady_clock::now();
obegin = std::chrono::steady_clock::now();
oend = std::chrono::steady_clock::now();
}
//--------------------------------------------------------------
void ofApp::update(){}
//--------------------------------------------------------------
void ofApp::draw(){
ofSetColor(225);
ofDrawBitmapString("AUDIO INPUT EXAMPLE", 32, 32);
ofDrawBitmapString("press 's' to unpause the audio\n'e' to pause the audio", 31, 92);
drawCounter++;
ofSetColor(225);
string reportString = "buffers received: " + ofToString(bufferCounter)
+ "\nseconds received: " + ofToString(secondsCounter)
+ "\ndraw routines called: " + ofToString(drawCounter)
+ "\nticks: " + ofToString(soundStream.getTickCount());
ofDrawBitmapString(reportString, 32, 200);
string timespans = " In time span: " + idife + "\nOut time span: " + odife;
ofDrawBitmapString(timespans, 32, 330);
}
//--------------------------------------------------------------
void ofApp::audioIn(ofSoundBuffer & input){
bufferCounter++;
secondsCounter += (static_cast<double>(bufferSize) / static_cast<double>(sampleRate));
iend = std::chrono::steady_clock::now();
idife = ofToString (std::chrono::duration_cast<std::chrono::microseconds> (iend - ibegin).count());
ibegin = std::chrono::steady_clock::now();
}
//--------------------------------------------------------------
void ofApp::audioOut(ofSoundBuffer & buffer)
{
oend = std::chrono::steady_clock::now();
odife = ofToString (std::chrono::duration_cast<std::chrono::microseconds> (oend - obegin).count());
obegin = std::chrono::steady_clock::now();
}
//--------------------------------------------------------------
void ofApp::keyPressed (int key){
if( key == 's' ) soundStream.start();
if( key == 'e' ) soundStream.stop();
}
main.cpp
#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
//Use ofGLFWWindowSettings for more options like multi-monitor fullscreen
ofGLWindowSettings settings;
settings.setSize(1024, 768);
settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN
auto window = ofCreateWindow(settings);
ofRunApp(window, make_shared<ofApp>());
ofRunMainLoop();
}