summaryrefslogtreecommitdiffstats
path: root/loadSongs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'loadSongs.cpp')
-rwxr-xr-xloadSongs.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/loadSongs.cpp b/loadSongs.cpp
new file mode 100755
index 0000000..0948212
--- /dev/null
+++ b/loadSongs.cpp
@@ -0,0 +1,367 @@
+#include <dirent.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <sstream>
+#include <algorithm>
+#include <string>
+
+#include "logging.h"
+#include "files.h"
+
+const char *songsPath = "/sdcard/Songs/";
+
+void split(std::vector<std::string> &tokens, const std::string &text, const char *sep) {
+ int start = 0, end = 0;
+ while ((end = text.find(sep, start)) != std::string::npos) {
+ tokens.push_back(text.substr(start, end - start));
+ start = end + 1;
+ }
+ tokens.push_back(text.substr(start));
+}
+
+// trim from start
+static inline std::string &ltrim(std::string &s) {
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(isspace))));
+ return s;
+}
+
+// trim from end
+static inline std::string &rtrim(std::string &s) {
+ s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(isspace))).base(), s.end());
+ return s;
+}
+
+// trim from both ends
+static inline std::string &trim(std::string &s) {
+ return ltrim(rtrim(s));
+}
+
+/* Returns a list of directories (except the ones that begin with a dot) */
+
+void GetDirectories(std::vector<std::string> &out, const char *directory)
+{
+#ifdef WINDOWS
+ HANDLE dir;
+ WIN32_FIND_DATA file_data;
+
+ if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
+ return; /* No files found */
+
+ do {
+ const string file_name = file_data.cFileName;
+ const string full_file_name = directory + "/" + file_name;
+ const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+
+ if (file_name[0] == '.')
+ continue;
+
+ if (!is_directory)
+ continue;
+
+ out.push_back(full_file_name);
+ } while (FindNextFile(dir, &file_data));
+
+ FindClose(dir);
+#else
+ DIR *dir;
+ class dirent *ent;
+ class stat st;
+
+ dir = opendir(directory);
+ if(dir == NULL)
+ {
+ std::string errmsg = "Cannot open directory ";
+ logstdError("GetDirectories", errmsg + directory);
+ }
+ else
+ {
+ while ((ent = readdir(dir)) != NULL) {
+ const std::string file_name = ent->d_name;
+ std::string full_file_name = directory;
+ full_file_name.append("/" + file_name + "/");
+
+ if (file_name[0] == '.')
+ continue;
+
+ if (stat(full_file_name.c_str(), &st) == -1)
+ continue;
+
+ if (!S_ISDIR(st.st_mode))
+ continue;
+
+ out.push_back(full_file_name);
+ }
+ closedir(dir);
+ if(out.empty())
+ {
+ std::string errmsg = "Directory empty: ";
+ logstdError("GetDirectories", errmsg + directory);
+ }
+ }
+#endif
+} // GetFilesInDirectory
+
+/* Returns a list of sm files */
+
+void GetSmFiles(std::vector<std::string> &out, const std::string directory)
+{
+#ifdef WINDOWS
+ HANDLE dir;
+ WIN32_FIND_DATA file_data;
+
+ if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
+ return; /* No files found */
+
+ do {
+ const string file_name = file_data.cFileName;
+ const string full_file_name = directory + "/" + file_name;
+ const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+
+ std::vector<std::string> tokens;
+ split(tokens, file_name, ".");
+
+ if (strcmp(tokens.back(), "sm"))
+ continue;
+
+ if (is_directory)
+ continue;
+
+ out.push_back(full_file_name);
+ } while (FindNextFile(dir, &file_data));
+
+ FindClose(dir);
+#else
+ DIR *dir;
+ class dirent *ent;
+ class stat st;
+
+ dir = opendir(directory.c_str());
+ if(dir == NULL)
+ {
+ std::string errmsg = "Cannot open directory ";
+ logstdError("GetDirectories", errmsg + directory);
+ }
+ else
+ {
+ while ((ent = readdir(dir)) != NULL) {
+ const std::string file_name = ent->d_name;
+ std::string full_file_name = directory;
+ full_file_name.append("/" + file_name);
+
+ std::vector<std::string> tokens;
+ split(tokens, file_name, ".");
+
+ if (tokens.back() != "sm")
+ continue;
+
+ if (stat(full_file_name.c_str(), &st) == -1)
+ continue;
+
+ const bool is_readable = (st.st_mode & S_IRUSR) != 0;
+
+ if (!is_readable)
+ continue;
+
+ out.push_back(file_name);
+ }
+ closedir(dir);
+ if(out.empty())
+ {
+ std::string errmsg = "Directory empty: ";
+ logstdError("GetDirectories", errmsg + directory);
+ }
+ }
+#endif
+} // GetSmFiles
+
+
+int readSongFile(std::string &path, musicfile &songFile)
+{
+ bool reading_note = false;
+ int current_note_line = 0;
+ std::vector<Note> currentNoteData;
+ std::vector<std::vector<Note>> currentLineNoteData;
+ notes currentNotes;
+
+ std::string line;
+ std::ifstream file;
+ file.open(path.c_str(), std::ifstream::in);
+ if (!file)
+ {
+ std::string msg = "Could not open ";
+ msg.append(path);
+ logstdError("loadFile", msg);
+ return 1;
+ }
+ while(file.good())
+ {
+ std::getline(file, line);
+ line = trim(line);
+ if(line.length() == 0)
+ continue;
+ else if(line[0] == '/')
+ continue;
+ else if(line[0] == '#')
+ {
+ std::vector<std::string> tokens;
+ split(tokens, line, ":");
+
+ if(tokens[0].compare("#NOTES") == 0)
+ {
+ reading_note = true;
+ continue;
+ }
+ else
+ reading_note = false;
+
+ if(*tokens[1].rbegin() == ';')
+ tokens[1].pop_back();
+
+ if(tokens[0].compare("#TITLE") == 0)
+ {
+ songFile.title = tokens[1];
+ }
+ else if(tokens[0].compare("#ARTIST") == 0)
+ {
+ songFile.artist = tokens[1];
+ }
+ else if(tokens[0].compare("#BANNER") == 0)
+ {
+ songFile.banner = tokens[1];
+ }
+ else if(tokens[0].compare("#BACKGROUND") == 0)
+ {
+ songFile.background = tokens[1];
+ }
+ else if(tokens[0].compare("#MUSIC") == 0)
+ {
+ songFile.file = tokens[1];
+ }
+ else if(tokens[0].compare("#OFFSET") == 0)
+ {
+ std::istringstream(tokens[1]) >> songFile.offset;
+ }
+ else if(tokens[0].compare("#BPMS") == 0)
+ {
+ std::vector<std::string> listBpms;
+ split(listBpms, tokens[1], ",");
+ for(std::vector<std::string>::iterator bpmData = listBpms.begin(); bpmData != listBpms.end(); ++bpmData)
+ {
+ std::vector<std::string> bpm;
+ split(bpm, *bpmData, "=");
+ songBpm bpms;
+ std::istringstream(bpm[0]) >> bpms.beat;
+ std::istringstream(bpm[1]) >> bpms.bpm;
+ songFile.bpms.push_back(bpms);
+ }
+ }
+ }
+ else if(reading_note)
+ {
+ std::vector<std::string> tokens;
+ split(tokens, line, ":");
+
+ if((*line.rbegin() == ':') || (tokens.size() > 1))
+ {
+ switch(current_note_line)
+ {
+ case 0:
+ currentNotes.type = tokens[0];
+ break;
+ case 1:
+ currentNotes.description = tokens[0];
+ break;
+ case 2:
+ currentNotes.difficultyClass = tokens[0];
+ break;
+ case 3:
+ std::istringstream ( tokens[1] ) >> currentNotes.difficultyMeter;
+ break;
+ case 4:
+ currentNotes.radarValues = tokens[0];
+ break;
+ default:
+ std::string msg = "Too much ':' for #NOTES in ";
+ msg.append(path);
+ logstdError("readSongFile", msg);
+ break;
+ }
+ current_note_line += 1;
+ }
+ else if(line[0] == ',')
+ {
+ currentNotes.noteData.push_back(currentLineNoteData);
+ currentLineNoteData.clear();
+ }
+ else if(line[0] == ';')
+ {
+ current_note_line = 0;
+ songFile.songNotes.push_back(currentNotes);
+ static const notes tempStruct;
+ currentNotes = tempStruct;
+ }
+ else
+ {
+ for(std::string::iterator c = line.begin(); c != line.end(); ++c) {
+ switch(*c)
+ {
+ case '0':
+ currentNoteData.push_back(None);
+ break;
+ case '1':
+ currentNoteData.push_back(Tap);
+ break;
+ case '2':
+ currentNoteData.push_back(Hold_begin);
+ break;
+ case '3':
+ currentNoteData.push_back(Hold_end);
+ break;
+ case '4':
+ currentNoteData.push_back(Roll);
+ break;
+ case 'M':
+ currentNoteData.push_back(Mine);
+ break;
+ case 'L':
+ currentNoteData.push_back(Lift);
+ break;
+ case 'F':
+ currentNoteData.push_back(Fake);
+ break;
+ }
+ }
+ currentLineNoteData.push_back(currentNoteData);
+ currentNoteData.clear();
+ }
+ }
+ }
+ if(!file.eof())
+ {
+ logstdError("readSongFile", "Line cannot be read");
+ }
+ file.close();
+ return 0;
+}
+
+std::vector<musicfile> loadSongs()
+{
+ std::vector<std::string> directories;
+ std::vector<std::string> smfiles;
+ std::vector<musicfile> songs;
+
+ GetDirectories(directories, songsPath);
+
+ for(std::vector<std::string>::iterator it = directories.begin(); it != directories.end(); ++it) {
+ GetSmFiles(smfiles, *it);
+ for(std::vector<std::string>::iterator ite = smfiles.begin(); ite != smfiles.end(); ++ite) {
+ musicfile songData;
+ std::string file = *it + *ite;
+ if(!readSongFile(file, songData))
+ songData.path = *it;
+ songs.push_back(songData);
+ }
+ }
+ return songs;
+}
+