For a CODON project, I came up with two useful methods for loading .wav and .mov files into their respective std::maps. This way I could call the movie/sound by its name in the map and call the methods I want on it.
For the mentioned project I was already receiving TCP messages containing the name of the asset I needed to play from a client app. Users would have interacted with an Android app on a tablet and as the result of their interaction, the tablet would ask the main Cinder app (the server) to play a specific asset (movie and sound). Having the assets loaded in a map with asset names as keys, made playback super easy by calling something like mMovies[tcpMessageString]->play()
in the TCP event.
Here are the methods:
// loads all movies from the folder and returns a map with the movies' names as keys, not recursive | |
std::map<std::string, ci::qtime::MovieGlRef> loadMovies(const ci::fs::path& aMoviesFolder, const std::vector<std::string>& aAllowedExtensions = {".mov"}); | |
// loads all sounds from the folder and returns a map with the sounds' names as keys, not recursive | |
std::map<std::string, ci::audio::VoiceRef> loadSounds(const ci::fs::path& aSoundsFolder, const std::vector<std::string>& aAllowedExtensions = {".wav"}); |
The main concept behind the implementation is the use of fs::directory_iterator
to iterate over all of the files in a folder. The method then checks for allowed extensions (“.mov” in the case of Quicktime movies for instance) and again using methods for fs::path
detects the name of the file and use that as the key in our map. As a note, the extension()
method extracts the extension such as “.txt” or “.mov” (remember the dot is there), the stem()
method obtains the name of the file (“my-good-movie” in “my-good-movie.mov”) and the filename()
method strips the path and shows the full name along with the extension. Here is a good reference for methods associated with the fs::path
.
This implementation is not recursive but could easily become recursive if for every sub-folder (fs::is_directory() == true
) we used the same method and the joined the result maps together.
map<string, qtime::MovieGlRef> loadMovies(const fs::path& aMoviesFolder, const vector<string>& aAllowedExtensions) | |
{ | |
// make the empty result | |
map<string, qtime::MovieGlRef> result; | |
// check if the path is a directory | |
if (!fs::is_directory(aMoviesFolder)) { | |
CI_LOG_W("Movies folder was actually not a folder!"); | |
return result; | |
} | |
for (auto& file : fs::directory_iterator(aMoviesFolder)) { | |
auto path = file.path(); | |
if (fs::is_regular_file(path)) { | |
for (auto& extension : aAllowedExtensions) { | |
if (path.extension().string() == extension) { | |
auto movie = qtime::MovieGl::create(path); | |
movie->setVolume(1); | |
movie->stop(); | |
result[path.stem().string()] = movie; | |
CI_LOG_V ("Movie loaded with name " + path.filename().string()); | |
break; // if the extension was found don't bother with the other extensions | |
} | |
} | |
} | |
} | |
return result; | |
} | |
map<string, audio::VoiceRef> loadSounds(const fs::path& aSoundsFolder, const vector<string>& aAllowedExtensions) | |
{ | |
// make the empty result | |
map<string, audio::VoiceRef> result; | |
// check if the path is a directory | |
if (!fs::is_directory(aSoundsFolder)) { | |
CI_LOG_W("Sounds folder was actually not a folder!"); | |
return result; | |
} | |
for (auto& file : fs::directory_iterator(aSoundsFolder)) { | |
auto path = file.path(); | |
if (fs::is_regular_file(path)) { | |
for (auto& extension : aAllowedExtensions) { | |
if (path.extension().string() == extension) { | |
auto sound = audio::Voice::create(audio::load(loadFile(path))); | |
sound->setVolume(1); | |
sound->stop(); | |
result[path.stem().string()] = sound; | |
CI_LOG_V ("Sound loaded with name " + path.filename().string()); | |
break; // if the extension was found don't bother with the other extensions | |
} | |
} | |
} | |
} | |
return result; | |
} |