diff options
Diffstat (limited to 'Alc/ambdec.cpp')
-rw-r--r-- | Alc/ambdec.cpp | 575 |
1 files changed, 241 insertions, 334 deletions
diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index f3c96dfa..4239a694 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -3,235 +3,177 @@ #include "ambdec.h" -#include <stdio.h> -#include <string.h> -#include <ctype.h> +#include <cstring> +#include <cctype> -#include <vector> +#include <limits> +#include <string> +#include <fstream> +#include <sstream> #include "compat.h" -static char *lstrip(char *line) -{ - while(isspace(line[0])) - line++; - return line; -} +namespace { -static char *rstrip(char *line) +int readline(std::istream &f, std::string &output) { - size_t len = strlen(line); - while(len > 0 && isspace(line[len-1])) - len--; - line[len] = 0; - return line; -} - -static int readline(FILE *f, std::vector<char> &output) -{ - int c; - while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n')) { - } - if(c == EOF) - return 0; + while(f.good() && f.peek() == '\n') + f.ignore(); - output.clear(); - do { - output.emplace_back(c); - } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); - output.emplace_back((c=0)); - - return 1; + std::getline(f, output); + return !output.empty(); } - -/* Custom strtok_r, since we can't rely on it existing. */ -static char *my_strtok_r(char *str, const char *delim, char **saveptr) +bool read_clipped_line(std::istream &f, std::string &buffer) { - /* Sanity check and update internal pointer. */ - if(!saveptr || !delim) return nullptr; - if(str) *saveptr = str; - str = *saveptr; - - /* Nothing more to do with this string. */ - if(!str) return nullptr; - - /* Find the first non-delimiter character. */ - while(*str != '\0' && strchr(delim, *str) != nullptr) - str++; - if(*str == '\0') + while(readline(f, buffer)) { - /* End of string. */ - *saveptr = nullptr; - return nullptr; + std::size_t pos{0}; + while(pos < buffer.length() && std::isspace(buffer[pos])) + pos++; + buffer.erase(0, pos); + + std::size_t cmtpos{buffer.find_first_of('#')}; + if(cmtpos < buffer.length()) + buffer.resize(cmtpos); + while(!buffer.empty() && std::isspace(buffer.back())) + buffer.pop_back(); + + if(!buffer.empty()) + return true; } - - /* Find the next delimiter character. */ - *saveptr = strpbrk(str, delim); - if(*saveptr) *((*saveptr)++) = '\0'; - - return str; + return false; } -static char *read_int(ALint *num, const char *line, int base) -{ - char *end; - *num = strtol(line, &end, base); - if(end && *end != '\0') - end = lstrip(end); - return end; -} -static char *read_uint(ALuint *num, const char *line, int base) +std::string read_word(std::istream &f) { - char *end; - *num = strtoul(line, &end, base); - if(end && *end != '\0') - end = lstrip(end); - return end; + std::string ret; + f >> ret; + return ret; } -static char *read_float(ALfloat *num, const char *line) +bool is_at_end(const std::string &buffer, std::size_t endpos) { - char *end; -#ifdef HAVE_STRTOF - *num = strtof(line, &end); -#else - *num = (ALfloat)strtod(line, &end); -#endif - if(end && *end != '\0') - end = lstrip(end); - return end; + while(endpos < buffer.length() && std::isspace(buffer[endpos])) + ++endpos; + if(endpos < buffer.length()) + return false; + return true; } -char *read_clipped_line(FILE *f, std::vector<char> &buffer) -{ - while(readline(f, buffer)) - { - char *line, *comment; - - line = lstrip(buffer.data()); - comment = strchr(line, '#'); - if(comment) *(comment++) = 0; - - line = rstrip(line); - if(line[0]) return line; - } - return nullptr; -} - -static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, std::vector<char> &buffer, char **saveptr) +bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer) { ALsizei cur = 0; while(cur < conf->NumSpeakers) { - const char *cmd = my_strtok_r(nullptr, " \t", saveptr); - if(!cmd) + std::istringstream istr{buffer}; + + std::string cmd = read_word(istr); + if(cmd.empty()) { - char *line = read_clipped_line(f, buffer); - if(!line) + if(!read_clipped_line(f, buffer)) { ERR("Unexpected end of file\n"); - return 0; + return false; } - cmd = my_strtok_r(line, " \t", saveptr); + istr = std::istringstream{buffer}; + cmd = read_word(istr); } - if(strcmp(cmd, "add_spkr") == 0) + if(cmd == "add_spkr") { - const char *name = my_strtok_r(nullptr, " \t", saveptr); - const char *dist = my_strtok_r(nullptr, " \t", saveptr); - const char *az = my_strtok_r(nullptr, " \t", saveptr); - const char *elev = my_strtok_r(nullptr, " \t", saveptr); - const char *conn = my_strtok_r(nullptr, " \t", saveptr); - - if(!name) WARN("Name not specified for speaker %u\n", cur+1); - else conf->Speakers[cur].Name = name; - if(!dist) WARN("Distance not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Distance, dist); - if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Azimuth, az); - if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Elevation, elev); - if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); - else conf->Speakers[cur].Connection = conn; + istr >> conf->Speakers[cur].Name; + if(istr.fail()) WARN("Name not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Distance; + if(istr.fail()) WARN("Distance not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Azimuth; + if(istr.fail()) WARN("Azimuth not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Elevation; + if(istr.fail()) WARN("Elevation not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Connection; + if(istr.fail()) TRACE("Connection not specified for speaker %u\n", cur+1); cur++; } else { - ERR("Unexpected speakers command: %s\n", cmd); - return 0; + ERR("Unexpected speakers command: %s\n", cmd.c_str()); + return false; } - cmd = my_strtok_r(nullptr, " \t", saveptr); - if(cmd) + istr.clear(); + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on line: %s\n", cmd); - return 0; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return false; } + buffer.clear(); } - return 1; + return true; } -static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, std::vector<char> &buffer, char **saveptr) +bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, std::istream &f, std::string &buffer) { - int gotgains = 0; + bool gotgains = false; ALsizei cur = 0; while(cur < maxrow) { - const char *cmd = my_strtok_r(nullptr, " \t", saveptr); - if(!cmd) + std::istringstream istr{buffer}; + std::string cmd; + + istr >> cmd; + if(cmd.empty()) { - char *line = read_clipped_line(f, buffer); - if(!line) + if(!read_clipped_line(f, buffer)) { ERR("Unexpected end of file\n"); - return 0; + return false; } - cmd = my_strtok_r(line, " \t", saveptr); + istr = std::istringstream{buffer}; + istr >> cmd; } - if(strcmp(cmd, "order_gain") == 0) + if(cmd == "order_gain") { ALuint curgain = 0; - char *line; - while((line=my_strtok_r(nullptr, " \t", saveptr)) != nullptr) + float value; + while(istr.good()) { - ALfloat value; - line = read_float(&value, line); - if(line && *line != '\0') + istr >> value; + if(istr.fail()) break; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on gain %u: %s\n", curgain+1, line); - return 0; + ERR("Extra junk on gain %u: %s\n", curgain+1, buffer.c_str()+istr.tellg()); + return false; } if(curgain < MAX_AMBI_ORDER+1) - gains[curgain] = value; - curgain++; + gains[curgain++] = value; } while(curgain < MAX_AMBI_ORDER+1) gains[curgain++] = 0.0f; - gotgains = 1; + gotgains = true; } - else if(strcmp(cmd, "add_row") == 0) + else if(cmd == "add_row") { ALuint curidx = 0; - char *line; - while((line=my_strtok_r(nullptr, " \t", saveptr)) != nullptr) + float value; + while(istr.good()) { - ALfloat value; - line = read_float(&value, line); - if(line && *line != '\0') + istr >> value; + if(istr.fail()) break; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, line); - return 0; + ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, + buffer.c_str()+istr.tellg()); + return false; } if(curidx < MAX_AMBI_COEFFS) - matrix[cur][curidx] = value; - curidx++; + matrix[cur][curidx++] = value; } while(curidx < MAX_AMBI_COEFFS) matrix[cur][curidx++] = 0.0f; @@ -239,282 +181,247 @@ static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS] } else { - ERR("Unexpected speakers command: %s\n", cmd); - return 0; + ERR("Unexpected matrix command: %s\n", cmd.c_str()); + return false; } - cmd = my_strtok_r(nullptr, " \t", saveptr); - if(cmd) + istr.clear(); + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on line: %s\n", cmd); - return 0; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return false; } + buffer.clear(); } if(!gotgains) { ERR("Matrix order_gain not specified\n"); - return 0; + return false; } - return 1; + return true; } +} // namespace + int AmbDecConf::load(const char *fname) { - std::vector<char> buffer; - char *line; - FILE *f; - - f = al_fopen(fname, "r"); - if(!f) + al::ifstream f{fname}; + if(!f.is_open()) { ERR("Failed to open: %s\n", fname); return 0; } - while((line=read_clipped_line(f, buffer)) != nullptr) + std::string buffer; + while(read_clipped_line(f, buffer)) { - char *saveptr; - char *command; + std::istringstream istr{buffer}; + std::string command; - command = my_strtok_r(line, "/ \t", &saveptr); - if(!command) + istr >> command; + if(command.empty()) { - ERR("Malformed line: %s\n", line); - goto fail; + ERR("Malformed line: %s\n", buffer.c_str()); + return 0; } - if(strcmp(command, "description") == 0) + if(command == "/description") + istr >> Description; + else if(command == "/version") { - char *value = my_strtok_r(nullptr, "", &saveptr); - Description = lstrip(value); - } - else if(strcmp(command, "version") == 0) - { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_uint(&Version, line, 10); - if(line && *line != '\0') + istr >> Version; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after version: %s\n", line); - goto fail; + ERR("Extra junk after version: %s\n", buffer.c_str()+istr.tellg()); + return 0; } if(Version != 3) { ERR("Unsupported version: %u\n", Version); - goto fail; + return 0; } } - else if(strcmp(command, "dec") == 0) + else if(command == "/dec/chan_mask") { - const char *dec = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(dec, "chan_mask") == 0) + istr >> std::hex >> ChanMask >> std::dec; + if(!istr.eof() && !std::isspace(istr.peek())) { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_uint(&ChanMask, line, 16); - if(line && *line != '\0') - { - ERR("Extra junk after mask: %s\n", line); - goto fail; - } + ERR("Extra junk after mask: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else if(strcmp(dec, "freq_bands") == 0) + } + else if(command == "/dec/freq_bands") + { + istr >> FreqBands; + if(!istr.eof() && !std::isspace(istr.peek())) { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_uint(&FreqBands, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after freq_bands: %s\n", line); - goto fail; - } - if(FreqBands != 1 && FreqBands != 2) - { - ERR("Invalid freq_bands value: %u\n", FreqBands); - goto fail; - } + ERR("Extra junk after freq_bands: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else if(strcmp(dec, "speakers") == 0) + if(FreqBands != 1 && FreqBands != 2) { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_int(&NumSpeakers, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after speakers: %s\n", line); - goto fail; - } - if(NumSpeakers > MAX_OUTPUT_CHANNELS) - { - ERR("Unsupported speaker count: %u\n", NumSpeakers); - goto fail; - } + ERR("Invalid freq_bands value: %u\n", FreqBands); + return 0; } - else if(strcmp(dec, "coeff_scale") == 0) + } + else if(command == "/dec/speakers") + { + istr >> NumSpeakers; + if(!istr.eof() && !std::isspace(istr.peek())) { - line = my_strtok_r(nullptr, " \t", &saveptr); - if(strcmp(line, "n3d") == 0) - CoeffScale = AmbDecScale::N3D; - else if(strcmp(line, "sn3d") == 0) - CoeffScale = AmbDecScale::SN3D; - else if(strcmp(line, "fuma") == 0) - CoeffScale = AmbDecScale::FuMa; - else - { - ERR("Unsupported coeff scale: %s\n", line); - goto fail; - } + ERR("Extra junk after speakers: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else + if(NumSpeakers > MAX_OUTPUT_CHANNELS) { - ERR("Unexpected /dec option: %s\n", dec); - goto fail; + ERR("Unsupported speaker count: %u\n", NumSpeakers); + return 0; } } - else if(strcmp(command, "opt") == 0) + else if(command == "/dec/coeff_scale") { - const char *opt = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(opt, "xover_freq") == 0) - { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_float(&XOverFreq, line); - if(line && *line != '\0') - { - ERR("Extra junk after xover_freq: %s\n", line); - goto fail; - } - } - else if(strcmp(opt, "xover_ratio") == 0) + std::string scale = read_word(istr); + if(scale == "n3d") CoeffScale = AmbDecScale::N3D; + else if(scale == "sn3d") CoeffScale = AmbDecScale::SN3D; + else if(scale == "fuma") CoeffScale = AmbDecScale::FuMa; + else { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_float(&XOverRatio, line); - if(line && *line != '\0') - { - ERR("Extra junk after xover_ratio: %s\n", line); - goto fail; - } + ERR("Unsupported coeff scale: %s\n", scale.c_str()); + return 0; } - else if(strcmp(opt, "input_scale") == 0 || strcmp(opt, "nfeff_comp") == 0 || - strcmp(opt, "delay_comp") == 0 || strcmp(opt, "level_comp") == 0) + } + else if(command == "/opt/xover_freq") + { + istr >> XOverFreq; + if(!istr.eof() && !std::isspace(istr.peek())) { - /* Unused */ - my_strtok_r(nullptr, " \t", &saveptr); + ERR("Extra junk after xover_freq: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else + } + else if(command == "/opt/xover_ratio") + { + istr >> XOverRatio; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Unexpected /opt option: %s\n", opt); - goto fail; + ERR("Extra junk after xover_ratio: %s\n", buffer.c_str()+istr.tellg()); + return 0; } } - else if(strcmp(command, "speakers") == 0) + else if(command == "/opt/input_scale" || command == "/opt/nfeff_comp" || + command == "/opt/delay_comp" || command == "/opt/level_comp") { - const char *value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(value, "{") != 0) + /* Unused */ + read_word(istr); + } + else if(command == "/speakers/{") + { + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Expected { after %s command, got %s\n", command, value); - goto fail; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; } - if(!load_ambdec_speakers(this, f, buffer, &saveptr)) - goto fail; - value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(!value) + buffer.clear(); + + if(!load_ambdec_speakers(this, f, buffer)) + return 0; + + if(!read_clipped_line(f, buffer)) { - line = read_clipped_line(f, buffer); - if(!line) - { - ERR("Unexpected end of file\n"); - goto fail; - } - value = my_strtok_r(line, "/ \t", &saveptr); + ERR("Unexpected end of file\n"); + return 0; } - if(strcmp(value, "}") != 0) + istr = std::istringstream{buffer}; + std::string endmark = read_word(istr); + if(endmark != "/}") { - ERR("Expected } after speaker definitions, got %s\n", value); - goto fail; + ERR("Expected /} after speaker definitions, got %s\n", endmark.c_str()); + return 0; } } - else if(strcmp(command, "lfmatrix") == 0 || strcmp(command, "hfmatrix") == 0 || - strcmp(command, "matrix") == 0) + else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") { - const char *value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(value, "{") != 0) + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Expected { after %s command, got %s\n", command, value); - goto fail; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; } + buffer.clear(); + if(FreqBands == 1) { - if(strcmp(command, "matrix") != 0) + if(command != "/matrix/{") { - ERR("Unexpected \"%s\" type for a single-band decoder\n", command); - goto fail; + ERR("Unexpected \"%s\" type for a single-band decoder\n", command.c_str()); + return 0; } - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer, &saveptr)) - goto fail; + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer)) + return 0; } else { - if(strcmp(command, "lfmatrix") == 0) + if(command == "/lfmatrix/{") { - if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer, - &saveptr)) - goto fail; + if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer)) + return 0; } - else if(strcmp(command, "hfmatrix") == 0) + else if(command == "/hfmatrix/{") { - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer, - &saveptr)) - goto fail; + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer)) + return 0; } else { - ERR("Unexpected \"%s\" type for a dual-band decoder\n", command); - goto fail; + ERR("Unexpected \"%s\" type for a dual-band decoder\n", command.c_str()); + return 0; } } - value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(!value) + + if(!read_clipped_line(f, buffer)) { - line = read_clipped_line(f, buffer); - if(!line) - { - ERR("Unexpected end of file\n"); - goto fail; - } - value = my_strtok_r(line, "/ \t", &saveptr); + ERR("Unexpected end of file\n"); + return 0; } - if(strcmp(value, "}") != 0) + istr = std::istringstream{buffer}; + std::string endmark = read_word(istr); + if(endmark != "/}") { - ERR("Expected } after matrix definitions, got %s\n", value); - goto fail; + ERR("Expected /} after matrix definitions, got %s\n", endmark.c_str()); + return 0; } } - else if(strcmp(command, "end") == 0) + else if(command == "/end") { - line = my_strtok_r(nullptr, "/ \t", &saveptr); - if(line) + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on end: %s\n", line); - goto fail; + ERR("Unexpected junk on end: %s\n", buffer.c_str()+endpos); + return 0; } - fclose(f); return 1; } else { - ERR("Unexpected command: %s\n", command); - goto fail; + ERR("Unexpected command: %s\n", command.c_str()); + return 0; } - line = my_strtok_r(nullptr, "/ \t", &saveptr); - if(line) + istr.clear(); + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on line: %s\n", line); - goto fail; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; } + buffer.clear(); } ERR("Unexpected end of file\n"); -fail: - fclose(f); return 0; } |