ofBook Sound // Tutorial - Implementation Producing No Sound


#1

TL;DR Implementing the ofBook Sound tutorial successfully draws and updates wave-function on display associated with key-presses but no sound is generated.

Hey there if you’re reading this thanks for stopping by.

I’m new to OF as a student whose required to use the framework for assignments in a computational methods course. We are currently assigned to create a functional digital keyboard synthesizer using C++ & OF. The assignment is simple enough, we have to find creative commons sound bytes and assign them to array of boxes. When each box is clicked it plays the sound and highlights to a different color.

With some key presses functions I could easily just implement something similar to this (below) and call it a day.

class ofApp : public ofBaseApp {
// … other things …
ofSoundPlayer soundPlayer;
};

void ofApp::setup() {
soundPlayer.load(“generic_keyboard_note.mp3”);
soundPlayer.play();
}

Okay! Cool, but that’s way too simple and I want to more. So I ended up reading about the basic synthesizer from the OfBook Sound chapter and tried implementing it (as is, without any other code to muddle it up). To see if I can incorporate it into my assignment. (Eg. rather than playing a simple .mp3 file when a key is pressed, instead it will generate and play a separate note for each key). The first step is to faithfully be able to create sound in OF.

https://openframeworks.cc/ofBook/chapters/sound.html

Here’s my implementation of the tutorial–it should be nearly exactly the same except that I changed the key-pressed functions to map to the letter of the note played, and the lerping for the volume only to trigger for these specific keys.

I’m pretty sure the issue I’m having is that the OfApp::AudioOut and/or SoundStream are not properly implemented because it’s lacking some kind of a device signature. This means despite the draws, update, volume lerping, and key-presses working properly no sound is outputted. I’ve been pouring over code examples of what could fix this, but I’m pretty much in over my head.

Has anyone followed this tutorial before that could shed some light on the manner?

/—main.cpp—/
#include “ofMain.h”
#include “ofApp.h”

//=================================================================
int main( ){
ofSetupOpenGL(1920,1080,OF_WINDOW); // <-------- setup the GL context

// this kicks off the running of my app
// can be OF_WINDOW or OF_FULLSCREEN
// pass in width and height too:
ofRunApp(new ofApp());

}
//--------------------------------------------------------------

/—OfApp.h—/
#pragma once
#include “ofMain.h”

class ofApp : public ofBaseApp {
public:
void setup();
void update();
void draw();

	float volume;

	void updateWaveform(int waveformResolution);
	void audioOut(float * output, int bufferSize, int nChannels);

	std::vector<float> waveform; // this is the lookup table
	double phase;
	float frequency;

	ofMutex waveformMutex;
	ofPolyline waveLine;
	ofPolyline outLine;

	ofSoundPlayer   mySound;

	void keyPressed(int key);
	void keyIsDown(int key);
	float frequencyTarget;

};
//--------------------------------------------------------------

/—OfApp.cpp—/
#define _USE_MATH_DEFINES
#include “ofApp.h”
#include
#include

//--------------------------------------------------------------
void ofApp::setup() {
volume = 0;
phase = 0;
updateWaveform(32);
ofSoundStreamSetup(1, 0); // mono output
}

void ofApp::update() {
if (ofGetKeyPressed(‘a’) || ofGetKeyPressed(‘b’) ||
ofGetKeyPressed(‘c’) || ofGetKeyPressed(‘d’) ||
ofGetKeyPressed(‘e’) || ofGetKeyPressed(‘f’) ||
ofGetKeyPressed(‘g’)) {
volume = ofLerp(volume, 1, 0.8); // jump quickly to 1
}
else {
volume = ofLerp(volume, 0, 0.1); // fade slowly to 0
}

ofScopedLock waveformLock(waveformMutex);
updateWaveform(ofMap(ofGetMouseX(), 0, ofGetWidth(), 3, 64, true));
frequency = ofLerp(frequency, frequencyTarget, 0.4);

}

void ofApp::draw() {
ofBackground(ofColor::black);
ofSetLineWidth(5);
ofSetColor(ofColor::lightGreen);
outLine.draw();
ofSetColor(ofColor::cyan);
waveLine.draw();
}

void ofApp::updateWaveform(int waveformResolution) {
waveform.resize(waveformResolution);
waveLine.clear();

// "waveformStep" maps a full oscillation of sin() to the size 
// of the waveform lookup table
float waveformStep = (M_PI * 2.) / (float)waveform.size();

for (int i = 0; i < waveform.size(); i++) {
	waveform[i] = sin(i * waveformStep);

	waveLine.addVertex(ofMap(i, 0, waveform.size() - 1, 0, ofGetWidth()),
		ofMap(waveform[i], -1, 1, 0, ofGetHeight()));
}

}

void ofApp::audioOut(float * output, int bufferSize, int nChannels) {
ofScopedLock waveformLock(waveformMutex);

float sampleRate = 44100;
float phaseStep = frequency / sampleRate;

outLine.clear();

for (int i = 0; i < bufferSize * nChannels; i += nChannels) {
	phase += phaseStep;
	int waveformIndex = (int)(phase * waveform.size()) % waveform.size();
	output[i] = waveform[waveformIndex] * volume;

	outLine.addVertex(ofMap(i, 0, bufferSize - 1, 0, ofGetWidth()),
		ofMap(output[i], -1, 1, 0, ofGetHeight()));
}

}

void ofApp::keyPressed(int key) {
if (key == ‘c’) {
frequencyTarget = 261.63; // C
}
else if (key == ‘d’) {
frequencyTarget = 293.67; // D
}
else if (key == ‘e’) {
frequencyTarget = 329.63; // E
}
else if (key == ‘f’) {
frequencyTarget = 349.23; // F
}
else if (key == ‘g’) {
frequencyTarget = 392.00; // G
}
else if (key == ‘a’) {
frequencyTarget = 440.00; // A
}
else if (key == ‘b’) {
frequencyTarget = 493.88; // B
}
}