Should I avoid to declare variables outside of a class in ofApp.cpp?

I hope I have the right terms for my question.
So normally I would declare variables in the class of the ofApp.h file or inside ofApp::functions in the ofApp.cpp file. In this case I have Emscripten bindings in ofApp.cpp for some functions of the ofApp.h file.
All variables that need to be accessed from both need to be declared in the ofApp.cpp file outside of the class.
I also tried to put the bindings in the .h file, but its not allowed to declare two ofApp classes in one file.
My question is, should I avoid declaring variables like that? And is there a better way to achieve that?
Before I was using notify, but this attempt seems more direct.
This is the basic part of the code in ofApp.cpp:

#include "ofApp.h"

ofxEmscriptenVideoPlayer videoPlayer;
ofxEmscriptenSoundPlayer audioPlayer;
ofTexture texture;

//--------------------------------------------------------------
void ofApp::setup() {
	emscripten::class_<ofApp>("ofApp")
        .constructor<>()
	.function("loadAudioUrl", &ofApp::loadAudioUrl)
	.function("loadVideoUrl", &ofApp::loadVideoUrl)
	.function("loadImage", &ofApp::loadImage);
}

//--------------------------------------------------------------
void ofApp::bang_1_event(bool & e) { 
	EM_ASM(
	if (canvas.hasFocus) {
		var input = document.createElement('input');
		input.type = 'file';
		input.accept = '.adts, .aiff, .caf, .flac, .mp3, .mp4, .ogg, .wav, .webm';
		input.click();
		canvas.hasFocus = false;
		input.onchange = function(e) {
			canvas.hasFocus = true;
			var file = e.target.files[0]; 
			var url = URL.createObjectURL(file);
			new Module.ofApp().loadAudioUrl(url);
		}
	});
}   

void ofApp::loadAudioUrl(std::string url) {    
	audioPlayer.unload();
	audioPlayer.load(url);
	audioPlayer.setLoop(true);
	audioPlayer.play();
}

Here is the whole code: ofEmscriptenExamples/emscriptenImport_embind_optimized at main · Jonathhhan/ofEmscriptenExamples · GitHub
And here is the old attempt: ofEmscriptenExamples/emscriptenImport_embind at main · Jonathhhan/ofEmscriptenExamples · GitHub

That is the error I get, if I try to define the bindings in ofApp.h:
"Cannot register public name 'ofApp' twice"
If rename it to Test, I get this:
"Cannot register public name 'Test' twice"

This was quite helpful: Using extern to specify global variables - #2 by TimChi
And it seems to okay to declare them there, but I am not sure…

Hi, it shouldn’t be a problem to declare variables outside of the class in the cpp file, although, these will behave somehow as a static variable and you shouldn’t be able to access it from a class on a different file. I am not sure why you would want to declare two ofApp classes but it sounds like a bad idea. It is just calling for confusion.

There are several ways of allowing each class to see the other but I am not sure what it is taht you want to achieve. can you clarify please
?

2 Likes

@roymacdonald of course, i will try (had the feeling that it could be a bad idea…).
When using Emscripten I can call C++ functions from Java Script with Embind.
And I want that those binding functions are part of the ofApp class (I want to load local files with Emscripten and use them with objects from the ofApp.h class).
My old approach worked without two ofApp classes, but seems a bit overcomplicated: ofEmscriptenExamples/emscriptenImport_embind at main · Jonathhhan/ofEmscriptenExamples · GitHub
I would be happy, if there is a better solution.
This is a test result from that code: https://import.handmadeproductions.de/
And here is the binding stuff described: Embind — Emscripten 3.1.26-git (dev) documentation

Edit: Here is a new attempt without two ofApp classes, I still need to declare the shared variables outside the ofApp class in the ofApp.cpp file (because I do not have an idea how to solve this better…):

1 Like

I see. you can use std::bind to bind a function member class to its instance and pass it to emscripten::function(...) already binded.
should look something like he following.
emscripten::function("bla",std::bind(&ofApp::someClassFunction, this, std::placeholders::_1)))

Let me know if ti works

2 Likes

Hi @Jona! I’ve been following along with some of your recent threads, including this one. So what happens if you put these three in ofApp (and include headers as needed), with the most recent attempt (just above)? Also hi @roymacdonald! Fun to see you in the forum and I’ve missed your frequent posts.

Somehow it does not work, this is the error:

candidate template ignored: could not match 'ReturnType (*)(Args...)' against '__bind<void (ofApp::*)(string &), ofApp *, const __ph<1> &>'
void function(const char* name, ReturnType (*fn)(Args...), Policies...) {

I’ve been thinking about this today. I thought maybe a lambda might be a good way to do this. But also maybe emscripten::function() needs to have the video player as well as the string:

// in ofApp.h
#include ofxEmscriptenVideoPlayer.h
ofxEmscriptenVideoPlayer videoPlayer; // maybe this isn't even needed?

// in ofApp
void loadVideoUrl(ofxEmscriptenVideoPlayer& player, std::string url){
	player.load(url);
	player.play();
}

// in ofApp::setup()
// use a lambda
emscripten::function("loadVideoUrl", [this](ofxEmscriptenVideoPlaye& p, std::string s){loadVideoUrl(p, s);});

I wish I could be more help with this. I don’t know emscripten at all and how it works, and I don’t have it set up anywhere so that I can test it out. The fact that I can’t add ofxEmscripten to a project on macOS makes me think that the addon only gets used by emscripten itself, and isn’t intended to be used by ofApp. Anyhow, I’ll keep following this thread and one day I hope to give emscripten a try.

Edit: If you try this and it fails, also try a const params, though this seems like it would not work because of changing the state of the video player. But, just in case it works for some reason:

emscripten::function("loadVideoUrl", [this](const ofxEmscriptenVideoPlaye& p, const std::string s){loadVideoUrl(p, s);});
1 Like

Hi @TimChi I’ve been super busy, that’s why I have not been very active here.
@Jona
Ah, the problem has to do with the function type.
Does something like the following, where loadViewUrl is an ofApp member function?

emscripten::function("loadVideoUrl", this->*loadVideoUrl);

I’ve always have found that passing functions around is ugly and I avoid such by design.

2 Likes

@roymacdonald thank you, thats the solution.
In ofApp.cpp I had to do:
emscripten::function("loadMidiInDevices", this->loadMidiInDevices);
And in ofApp.h I had to make the function static:
static void loadMidiInDevices(std::string string);

I only still need to declare:

unique_ptr<ofxDropdown> midiInputDropdown;
unique_ptr<ofxDropdown> midiOutputDropdown;

in ofApp.cpp to make it work, but that does not bother me, if it is fine to do so.
It prints the error:

error: invalid use of member 'midiInputDropdown' in static member function
        midiInputDropdown->forceRedraw();

If I put it in ofApp.cpp.

1 Like

I still would like to know, if it is possible to bind to a non-static member (because other problems appear because of the static members).
Similar methods are mentioned in this thread, but it does not seem to work in my case.

Hey have you tried shared_ptr instead of unique_ptr? I’m wondering if allowing copies of the pointer would help as it gets passed around.

1 Like

@TimChi thank you, I tried that (after your suggestion), but without luck.