| 1 | // foo_sli.cpp : Defines the exported functions for the DLL application.
|
|---|
| 2 | //
|
|---|
| 3 |
|
|---|
| 4 | // Licence: GPL v2 (check kirikiri 2 SDK License)
|
|---|
| 5 |
|
|---|
| 6 | /*
|
|---|
| 7 | see also:
|
|---|
| 8 | * http://devdoc.kikyou.info/tvp/docs/kr2doc/contents/LoopTuner.html
|
|---|
| 9 | * https://sv.kikyou.info/trac/kirikiri/browser/kirikiri2/trunk/license.txt
|
|---|
| 10 | * https://sv.kikyou.info/trac/kirikiri/browser/kirikiri2/trunk/kirikiri2/src/core/sound/WaveLoopManager.h
|
|---|
| 11 | * https://sv.kikyou.info/trac/kirikiri/browser/kirikiri2/trunk/kirikiri2/src/core/sound/WaveLoopManager.cpp
|
|---|
| 12 | * https://sv.kikyou.info/trac/kirikiri/browser/kirikiri2/trunk/kirikiri2/src/core/sound/WaveSegmentQueue.h
|
|---|
| 13 | * https://sv.kikyou.info/trac/kirikiri/browser/kirikiri2/trunk/kirikiri2/src/core/sound/WaveSegmentQueue.cpp
|
|---|
| 14 | */
|
|---|
| 15 |
|
|---|
| 16 | #include "stdafx.h"
|
|---|
| 17 |
|
|---|
| 18 | #define SLI_FLAGS 16
|
|---|
| 19 | #define SLI_MIN_FLAG_VALUE 0
|
|---|
| 20 | #define SLI_MAX_FLAG_VALUE 9999
|
|---|
| 21 |
|
|---|
| 22 | namespace {
|
|---|
| 23 | typedef pfc::array_staticsize_t<int> t_flags_array;
|
|---|
| 24 | class loop_condition : public pfc::refcounted_object_root {
|
|---|
| 25 | public:
|
|---|
| 26 | const char * const confname;
|
|---|
| 27 | const char * const symbol;
|
|---|
| 28 | const bool is_valid;
|
|---|
| 29 | loop_condition(const char * confname, const char * symbol, bool is_valid) :
|
|---|
| 30 | confname(confname), symbol(symbol), is_valid(is_valid) {}
|
|---|
| 31 | virtual bool check(unsigned int a, unsigned int b) = 0;
|
|---|
| 32 | };
|
|---|
| 33 |
|
|---|
| 34 | class loop_condition_no : public loop_condition {
|
|---|
| 35 | public:
|
|---|
| 36 | loop_condition_no() : loop_condition("no", NULL, false) {};
|
|---|
| 37 | virtual bool check(unsigned int a, unsigned int b) { return true; }
|
|---|
| 38 | };
|
|---|
| 39 |
|
|---|
| 40 | #define DEFINE_LOOP_CONDITION(name, op) \
|
|---|
| 41 | class loop_condition_ ##name : public loop_condition { \
|
|---|
| 42 | public: \
|
|---|
| 43 | loop_condition_ ##name () : loop_condition( #name, #op, true ) {}; \
|
|---|
| 44 | virtual bool check(unsigned int a, unsigned int b) { return a op b; } \
|
|---|
| 45 | };
|
|---|
| 46 |
|
|---|
| 47 | DEFINE_LOOP_CONDITION(eq, ==);
|
|---|
| 48 | DEFINE_LOOP_CONDITION(ne, !=);
|
|---|
| 49 | DEFINE_LOOP_CONDITION(gt, >);
|
|---|
| 50 | DEFINE_LOOP_CONDITION(ge, >=);
|
|---|
| 51 | DEFINE_LOOP_CONDITION(lt, <);
|
|---|
| 52 | DEFINE_LOOP_CONDITION(le, <=);
|
|---|
| 53 | #undef DEFINE_LOOP_CONDITION
|
|---|
| 54 |
|
|---|
| 55 | class formula_operator : public pfc::refcounted_object_root {
|
|---|
| 56 | public:
|
|---|
| 57 | const char * const symbol;
|
|---|
| 58 | const bool require_operand;
|
|---|
| 59 | formula_operator(const char * symbol, bool require_operand) :
|
|---|
| 60 | symbol(symbol), require_operand(require_operand) {}
|
|---|
| 61 | virtual unsigned int calculate(unsigned int original, unsigned int operand) = 0;
|
|---|
| 62 | };
|
|---|
| 63 |
|
|---|
| 64 | class formula_operator_set : public formula_operator {
|
|---|
| 65 | public:
|
|---|
| 66 | formula_operator_set() : formula_operator("=", true) {}
|
|---|
| 67 | virtual unsigned int calculate(unsigned int original, unsigned int operand) {
|
|---|
| 68 | return operand;
|
|---|
| 69 | }
|
|---|
| 70 | };
|
|---|
| 71 |
|
|---|
| 72 | class formula_operator_add : public formula_operator {
|
|---|
| 73 | public:
|
|---|
| 74 | formula_operator_add() : formula_operator("+=", true) {}
|
|---|
| 75 | virtual unsigned int calculate(unsigned int original, unsigned int operand) {
|
|---|
| 76 | return pfc::min_t<unsigned int>(original + operand, SLI_MAX_FLAG_VALUE);
|
|---|
| 77 | }
|
|---|
| 78 | };
|
|---|
| 79 |
|
|---|
| 80 | class formula_operator_sub : public formula_operator {
|
|---|
| 81 | public:
|
|---|
| 82 | formula_operator_sub() : formula_operator("-=", true) {}
|
|---|
| 83 | virtual unsigned int calculate(unsigned int original, unsigned int operand) {
|
|---|
| 84 | if (original >= operand) return original - operand;
|
|---|
| 85 | else return 0;
|
|---|
| 86 | }
|
|---|
| 87 | };
|
|---|
| 88 |
|
|---|
| 89 | class formula_operator_inc : public formula_operator {
|
|---|
| 90 | public:
|
|---|
| 91 | formula_operator_inc() : formula_operator("++", false) {}
|
|---|
| 92 | virtual unsigned int calculate(unsigned int original, unsigned int operand) {
|
|---|
| 93 | if (original == SLI_MAX_FLAG_VALUE) return original;
|
|---|
| 94 | else return original + 1;
|
|---|
| 95 | }
|
|---|
| 96 | };
|
|---|
| 97 |
|
|---|
| 98 | class formula_operator_dec : public formula_operator {
|
|---|
| 99 | public:
|
|---|
| 100 | formula_operator_dec() : formula_operator("--", true) {}
|
|---|
| 101 | virtual unsigned int calculate(unsigned int original, unsigned int operand) {
|
|---|
| 102 | if (original >= 1) return original - 1;
|
|---|
| 103 | else return 0;
|
|---|
| 104 | }
|
|---|
| 105 | };
|
|---|
| 106 |
|
|---|
| 107 | class formula_operand {
|
|---|
| 108 | public:
|
|---|
| 109 | bool indirect;
|
|---|
| 110 | unsigned int value;
|
|---|
| 111 | unsigned int resolve(t_flags_array & flags) {
|
|---|
| 112 | if (!indirect) return value;
|
|---|
| 113 | if (flags.get_size() < value)
|
|---|
| 114 | throw pfc::exception_overflow();
|
|---|
| 115 | return flags[value];
|
|---|
| 116 | }
|
|---|
| 117 | };
|
|---|
| 118 |
|
|---|
| 119 | struct sli_link {
|
|---|
| 120 | unsigned __int64 from;
|
|---|
| 121 | unsigned __int64 to;
|
|---|
| 122 | bool smooth;
|
|---|
| 123 | pfc::refcounted_object_ptr_t<loop_condition> condition;
|
|---|
| 124 | unsigned int refvalue;
|
|---|
| 125 | unsigned int condvar;
|
|---|
| 126 |
|
|---|
| 127 | bool operator<(const sli_link& p_other) const {return this->from < p_other.from;}
|
|---|
| 128 | bool operator<(const unsigned __int64 other) const {return this->from < other;}
|
|---|
| 129 | bool operator>(const sli_link& p_other) const {return this->from > p_other.from;}
|
|---|
| 130 | bool operator>(const unsigned __int64 other) const {return this->from > other;}
|
|---|
| 131 | bool operator<=(const sli_link& p_other) const {return this->from <= p_other.from;}
|
|---|
| 132 | bool operator<=(const unsigned __int64 other) const {return this->from <= other;}
|
|---|
| 133 | bool operator>=(const sli_link& p_other) const {return this->from >= p_other.from;}
|
|---|
| 134 | bool operator>=(const unsigned __int64 other) const {return this->from >= other;}
|
|---|
| 135 | };
|
|---|
| 136 |
|
|---|
| 137 | struct sli_label {
|
|---|
| 138 | unsigned __int64 position;
|
|---|
| 139 | pfc::string8 name;
|
|---|
| 140 |
|
|---|
| 141 | bool operator<(const sli_label& p_other) const {return this->position < p_other.position;}
|
|---|
| 142 | bool operator<(const unsigned __int64 other) const {return this->position < other;}
|
|---|
| 143 | bool operator>(const sli_label& p_other) const {return this->position > p_other.position;}
|
|---|
| 144 | bool operator>(const unsigned __int64 other) const {return this->position > other;}
|
|---|
| 145 | bool operator<=(const sli_label& p_other) const {return this->position <= p_other.position;}
|
|---|
| 146 | bool operator<=(const unsigned __int64 other) const {return this->position <= other;}
|
|---|
| 147 | bool operator>=(const sli_label& p_other) const {return this->position >= p_other.position;}
|
|---|
| 148 | bool operator>=(const unsigned __int64 other) const {return this->position >= other;}
|
|---|
| 149 | };
|
|---|
| 150 |
|
|---|
| 151 | struct sli_label_formula {
|
|---|
| 152 | unsigned int flag;
|
|---|
| 153 | pfc::refcounted_object_ptr_t<formula_operator> oper;
|
|---|
| 154 | bool indirect;
|
|---|
| 155 | unsigned int value;
|
|---|
| 156 | };
|
|---|
| 157 |
|
|---|
| 158 | class t_sli_link_list : public pfc::list_t<sli_link> {
|
|---|
| 159 | public:
|
|---|
| 160 | void sort() {
|
|---|
| 161 | return this->sort_t(pfc::compare_t<sli_link, sli_link>);
|
|---|
| 162 | }
|
|---|
| 163 | bool bsearch(unsigned __int64 from,t_size &p_index) {
|
|---|
| 164 | return this->bsearch_t(pfc::compare_t<sli_link, unsigned __int64>, from, p_index);
|
|---|
| 165 | }
|
|---|
| 166 | };
|
|---|
| 167 |
|
|---|
| 168 | class t_sli_label_list : public pfc::list_t<sli_label> {
|
|---|
| 169 | public:
|
|---|
| 170 | void sort() {
|
|---|
| 171 | return this->sort_t(pfc::compare_t<sli_label, sli_label>);
|
|---|
| 172 | }
|
|---|
| 173 | bool bsearch(unsigned __int64 from,t_size &p_index) {
|
|---|
| 174 | return this->bsearch_t(pfc::compare_t<sli_label, unsigned __int64>, from, p_index);
|
|---|
| 175 | }
|
|---|
| 176 | };
|
|---|
| 177 |
|
|---|
| 178 | bool parse_sli_entity(const char * & parseptr,pfc::string8 & name,pfc::string8 & value) {
|
|---|
| 179 | char delimiter = '\0';
|
|---|
| 180 | char tmp;
|
|---|
| 181 | t_size ptr = 0;
|
|---|
| 182 | while(tmp = parseptr[ptr], tmp && !isspace(tmp) && tmp != '=') ptr++;
|
|---|
| 183 | if (!parseptr[ptr]) return false;
|
|---|
| 184 | name.set_string(parseptr, ptr);
|
|---|
| 185 | parseptr += ptr;
|
|---|
| 186 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 187 | if (*parseptr != '=') return false;
|
|---|
| 188 | parseptr++;
|
|---|
| 189 | // check delimiter
|
|---|
| 190 | if (*parseptr == '\'') {
|
|---|
| 191 | delimiter = *parseptr;
|
|---|
| 192 | parseptr++;
|
|---|
| 193 | }
|
|---|
| 194 | if (!*parseptr) false;
|
|---|
| 195 |
|
|---|
| 196 | ptr = 0;
|
|---|
| 197 | if (delimiter == '\0') {
|
|---|
| 198 | while (tmp = parseptr[ptr], tmp && !isspace(tmp) && tmp != ';') ptr++;
|
|---|
| 199 | } else {
|
|---|
| 200 | while (tmp = parseptr[ptr], tmp && tmp != delimiter) ptr++;
|
|---|
| 201 | }
|
|---|
| 202 | if (!parseptr[ptr]) return false;
|
|---|
| 203 | value.set_string(parseptr, ptr);
|
|---|
| 204 | parseptr += ptr;
|
|---|
| 205 | if (*parseptr == delimiter) parseptr++;
|
|---|
| 206 | return true;
|
|---|
| 207 | }
|
|---|
| 208 |
|
|---|
| 209 | bool parse_sli_link(const char * & parseptr,sli_link &link) {
|
|---|
| 210 | // must point '{' , which indicates start of the block.
|
|---|
| 211 | if(*parseptr != '{') return false;
|
|---|
| 212 | parseptr++;
|
|---|
| 213 |
|
|---|
| 214 | while (*parseptr) {
|
|---|
| 215 | if (isspace(*parseptr)) {
|
|---|
| 216 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 217 | } else if (*parseptr == '}') {
|
|---|
| 218 | break;
|
|---|
| 219 | } else {
|
|---|
| 220 | pfc::string8 name, value;
|
|---|
| 221 | if (!parse_sli_entity(parseptr, name, value)) return false;
|
|---|
| 222 | if (!pfc::stricmp_ascii(name, "From")) {
|
|---|
| 223 | if (!pfc::string_is_numeric(value)) return false;
|
|---|
| 224 | link.from = pfc::atoui64_ex(value, strlen(value));
|
|---|
| 225 | } else if (!pfc::stricmp_ascii(name, "To")) {
|
|---|
| 226 | if (!pfc::string_is_numeric(value)) return false;
|
|---|
| 227 | link.to = pfc::atoui64_ex(value, strlen(value));
|
|---|
| 228 | } else if (!pfc::stricmp_ascii(name, "Smooth")) {
|
|---|
| 229 | if (!pfc::stricmp_ascii(value, "True")) {
|
|---|
| 230 | link.smooth = true;
|
|---|
| 231 | } else if (!pfc::stricmp_ascii(value, "False")) {
|
|---|
| 232 | link.smooth = false;
|
|---|
| 233 | } else if (!pfc::stricmp_ascii(value, "Yes")) {
|
|---|
| 234 | link.smooth = true;
|
|---|
| 235 | } else if (!pfc::stricmp_ascii(value, "No")) {
|
|---|
| 236 | link.smooth = false;
|
|---|
| 237 | } else {
|
|---|
| 238 | // parse error
|
|---|
| 239 | return false;
|
|---|
| 240 | }
|
|---|
| 241 | } else if (!pfc::stricmp_ascii(name, "Condition")) {
|
|---|
| 242 | if (!pfc::stricmp_ascii(value, "no")) {
|
|---|
| 243 | link.condition = new loop_condition_no();
|
|---|
| 244 | } else if (!pfc::stricmp_ascii(value, "eq")) {
|
|---|
| 245 | link.condition = new loop_condition_eq();
|
|---|
| 246 | } else if (!pfc::stricmp_ascii(value, "ne")) {
|
|---|
| 247 | link.condition = new loop_condition_ne();
|
|---|
| 248 | } else if (!pfc::stricmp_ascii(value, "gt")) {
|
|---|
| 249 | link.condition = new loop_condition_gt();
|
|---|
| 250 | } else if (!pfc::stricmp_ascii(value, "ge")) {
|
|---|
| 251 | link.condition = new loop_condition_ge();
|
|---|
| 252 | } else if (!pfc::stricmp_ascii(value, "lt")) {
|
|---|
| 253 | link.condition = new loop_condition_lt();
|
|---|
| 254 | } else if (!pfc::stricmp_ascii(value, "le")) {
|
|---|
| 255 | link.condition = new loop_condition_le();
|
|---|
| 256 | } else {
|
|---|
| 257 | return false;
|
|---|
| 258 | }
|
|---|
| 259 | } else if (!pfc::stricmp_ascii(name, "RefValue")) {
|
|---|
| 260 | if (!pfc::string_is_numeric(value)) return false;
|
|---|
| 261 | link.refvalue = pfc::clip_t(atoi(value), SLI_MIN_FLAG_VALUE, SLI_MAX_FLAG_VALUE);
|
|---|
| 262 | } else if (!pfc::stricmp_ascii(name, "CondVar")) {
|
|---|
| 263 | if (!pfc::string_is_numeric(value)) return false;
|
|---|
| 264 | link.condvar = pfc::clip_t(atoi(value), 0, SLI_FLAGS-1);
|
|---|
| 265 | } else {
|
|---|
| 266 | return false;
|
|---|
| 267 | }
|
|---|
| 268 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 269 | if (*parseptr != ';') return false;
|
|---|
| 270 | parseptr++;
|
|---|
| 271 | }
|
|---|
| 272 | }
|
|---|
| 273 |
|
|---|
| 274 | if (*parseptr != '}') return false;
|
|---|
| 275 | parseptr++;
|
|---|
| 276 | return true;
|
|---|
| 277 | }
|
|---|
| 278 |
|
|---|
| 279 | bool parse_sli_label(const char * & parseptr,sli_label &label) {
|
|---|
| 280 | // must point '{' , which indicates start of the block.
|
|---|
| 281 | if(*parseptr != '{') return false;
|
|---|
| 282 | parseptr++;
|
|---|
| 283 |
|
|---|
| 284 | while (*parseptr) {
|
|---|
| 285 | if (isspace(*parseptr)) {
|
|---|
| 286 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 287 | } else if (*parseptr == '}') {
|
|---|
| 288 | break;
|
|---|
| 289 | } else {
|
|---|
| 290 | pfc::string8 name, value;
|
|---|
| 291 | if (!parse_sli_entity(parseptr, name, value)) return false;
|
|---|
| 292 | if (!pfc::stricmp_ascii(name, "Position")) {
|
|---|
| 293 | if (!pfc::string_is_numeric(value)) return false;
|
|---|
| 294 | label.position = pfc::atoui64_ex(value, strlen(value));
|
|---|
| 295 | } else if (!pfc::stricmp_ascii(name, "Name")) {
|
|---|
| 296 | label.name.set_string(value);
|
|---|
| 297 | } else {
|
|---|
| 298 | return false;
|
|---|
| 299 | }
|
|---|
| 300 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 301 | if (*parseptr != ';') return false;
|
|---|
| 302 | parseptr++;
|
|---|
| 303 | }
|
|---|
| 304 | }
|
|---|
| 305 |
|
|---|
| 306 | if (*parseptr != '}') return false;
|
|---|
| 307 | parseptr++;
|
|---|
| 308 | return true;
|
|---|
| 309 | }
|
|---|
| 310 |
|
|---|
| 311 | bool parse_sli(const char * p_slitext,t_sli_link_list & p_outlinks,t_sli_label_list &p_outlabels) {
|
|---|
| 312 | const char * parseptr = p_slitext;
|
|---|
| 313 | if (!*parseptr) { return false; }
|
|---|
| 314 | if (*parseptr != '#') {
|
|---|
| 315 | // v1
|
|---|
| 316 | const char * p_length = strstr(parseptr, "LoopLength=");
|
|---|
| 317 | const char * p_start = strstr(parseptr, "LoopStart=");
|
|---|
| 318 | if (!p_length || !p_start) return false;
|
|---|
| 319 | p_length += 11;
|
|---|
| 320 | p_start += 10;
|
|---|
| 321 | if (!pfc::char_is_numeric(*p_length) || !pfc::char_is_numeric(*p_start)) return false;
|
|---|
| 322 | sli_link link;
|
|---|
| 323 | link.smooth = false;
|
|---|
| 324 | link.condition = new loop_condition_no();
|
|---|
| 325 | link.refvalue = 0;
|
|---|
| 326 | link.condvar = 0;
|
|---|
| 327 | __int64 start = _atoi64(p_start);
|
|---|
| 328 | link.from = start + _atoi64(p_length);
|
|---|
| 329 | link.to = start;
|
|---|
| 330 | p_outlinks.add_item(link);
|
|---|
| 331 |
|
|---|
| 332 | return true;
|
|---|
| 333 | }
|
|---|
| 334 | if (!pfc::strcmp_partial(parseptr, "#2.00")) {
|
|---|
| 335 | // v2
|
|---|
| 336 | while (*parseptr) {
|
|---|
| 337 | if (*parseptr == '#') {
|
|---|
| 338 | // FIXME: original source checks only beginning-of-line...
|
|---|
| 339 | while (*parseptr && *parseptr != '\n') parseptr++;
|
|---|
| 340 | } else if (isspace(*parseptr)) {
|
|---|
| 341 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 342 | } else if (pfc::stricmp_ascii(parseptr, "Link") && !pfc::char_is_ascii_alpha(parseptr[4])) {
|
|---|
| 343 | parseptr += 4;
|
|---|
| 344 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 345 | if (!*parseptr) return false;
|
|---|
| 346 | sli_link link;
|
|---|
| 347 | if (!parse_sli_link(parseptr, link)) return false;
|
|---|
| 348 | p_outlinks.add_item(link);
|
|---|
| 349 | } else if (pfc::stricmp_ascii(parseptr, "Label") && !pfc::char_is_ascii_alpha(parseptr[5])) {
|
|---|
| 350 | parseptr += 5;
|
|---|
| 351 | while (isspace(*parseptr)) parseptr++;
|
|---|
| 352 | if (!*parseptr) return false;
|
|---|
| 353 | sli_label label;
|
|---|
| 354 | if (!parse_sli_label(parseptr, label)) return false;
|
|---|
| 355 | p_outlabels.add_item(label);
|
|---|
| 356 | } else {
|
|---|
| 357 | return false;
|
|---|
| 358 | }
|
|---|
| 359 | }
|
|---|
| 360 | return true;
|
|---|
| 361 | }
|
|---|
| 362 | return false;
|
|---|
| 363 | }
|
|---|
| 364 |
|
|---|
| 365 | bool parse_sli_label_formula(const char * p_formula, sli_label_formula & p_out) {
|
|---|
| 366 | const char * p = p_formula;
|
|---|
| 367 | t_size ptr;
|
|---|
| 368 | // starts with '['
|
|---|
| 369 | if (*p != '[') return false;
|
|---|
| 370 | p++;
|
|---|
| 371 | ptr = 0;
|
|---|
| 372 | while (pfc::char_is_numeric(p[ptr])) ptr++;
|
|---|
| 373 | if (ptr == 0) return false;
|
|---|
| 374 | p_out.flag = pfc::clip_t<unsigned int>(pfc::atoui_ex(p, ptr), 0, SLI_FLAGS-1);
|
|---|
| 375 | p += ptr;
|
|---|
| 376 | // after flag, should be ']'
|
|---|
| 377 | if (*p != ']') return false;
|
|---|
| 378 | p++;
|
|---|
| 379 | bool sign = false;
|
|---|
| 380 | switch (*p) {
|
|---|
| 381 | case '=':
|
|---|
| 382 | p_out.oper = new formula_operator_set();
|
|---|
| 383 | break;
|
|---|
| 384 | case '+':
|
|---|
| 385 | sign = true;
|
|---|
| 386 | case '-':
|
|---|
| 387 | if (*p == *(p+1)) {
|
|---|
| 388 | if (sign)
|
|---|
| 389 | p_out.oper = new formula_operator_inc();
|
|---|
| 390 | else
|
|---|
| 391 | p_out.oper = new formula_operator_dec();
|
|---|
| 392 | p++;
|
|---|
| 393 | break;
|
|---|
| 394 | } else if (*(p+1) == '=') {
|
|---|
| 395 | if (sign)
|
|---|
| 396 | p_out.oper = new formula_operator_add();
|
|---|
| 397 | else
|
|---|
| 398 | p_out.oper = new formula_operator_sub();
|
|---|
| 399 | p++;
|
|---|
| 400 | break;
|
|---|
| 401 | }
|
|---|
| 402 | default:
|
|---|
| 403 | // unknown operator
|
|---|
| 404 | return false;
|
|---|
| 405 | }
|
|---|
| 406 | p++;
|
|---|
| 407 | if (!p_out.oper->require_operand) return true;
|
|---|
| 408 | p_out.indirect = false;
|
|---|
| 409 | if (*p == '[') {
|
|---|
| 410 | p_out.indirect = true;
|
|---|
| 411 | p++;
|
|---|
| 412 | }
|
|---|
| 413 | ptr = 0;
|
|---|
| 414 | while (pfc::char_is_numeric(p[ptr])) ptr++;
|
|---|
| 415 | if (ptr == 0) return false;
|
|---|
| 416 | p_out.value = pfc::clip_t<unsigned int>(pfc::atoui_ex(p, ptr), SLI_MIN_FLAG_VALUE,
|
|---|
| 417 | (p_out.indirect ? SLI_FLAGS-1 : SLI_MAX_FLAG_VALUE));
|
|---|
| 418 | p += ptr;
|
|---|
| 419 | if (p_out.indirect) {
|
|---|
| 420 | if (*p != ']') return false;
|
|---|
| 421 | p++;
|
|---|
| 422 | }
|
|---|
| 423 | if (*p) return false;
|
|---|
| 424 | return true;
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | void combine_audio_chunks(audio_chunk & p_first,const audio_chunk & p_second) {
|
|---|
| 428 | if (p_first.is_empty()) {
|
|---|
| 429 | p_first = p_second;
|
|---|
| 430 | return;
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | // sanity check
|
|---|
| 434 | if (p_first.get_sample_rate() != p_second.get_sample_rate() ||
|
|---|
| 435 | p_first.get_channel_config() != p_second.get_channel_config() ||
|
|---|
| 436 | p_first.get_channels() != p_second.get_channels()) {
|
|---|
| 437 | throw exception_unexpected_audio_format_change();
|
|---|
| 438 | }
|
|---|
| 439 | int nch = p_first.get_channels();
|
|---|
| 440 | t_size first_samples = p_first.get_sample_count();
|
|---|
| 441 | t_size offset = first_samples * nch;
|
|---|
| 442 | t_size second_samples = p_second.get_sample_count();
|
|---|
| 443 | t_size size = second_samples * nch;
|
|---|
| 444 | p_first.set_data_size(offset + size);
|
|---|
| 445 | pfc::memcpy_t(p_first.get_data()+offset,p_second.get_data(),size);
|
|---|
| 446 | p_first.set_sample_count(first_samples + second_samples);
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 | void do_crossfade(audio_sample * p_dest, const audio_sample * p_src1, const audio_sample * p_src2,
|
|---|
| 450 | int nch, t_size samples, t_uint ratiostart, t_uint ratioend) {
|
|---|
| 451 | audio_sample blend_step =
|
|---|
| 452 | (audio_sample)((ratioend - ratiostart) / 100.0 / samples);
|
|---|
| 453 | audio_sample ratio = (audio_sample)ratiostart / 100;
|
|---|
| 454 | while (samples) {
|
|---|
| 455 | for (int ch = nch-1; ch >= 0; ch--) {
|
|---|
| 456 | *p_dest = *p_src1 + (*p_src2 - *p_src1) * ratio;
|
|---|
| 457 | p_dest++; p_src1++; p_src2++;
|
|---|
| 458 | }
|
|---|
| 459 | samples--;
|
|---|
| 460 | ratio += blend_step;
|
|---|
| 461 | }
|
|---|
| 462 | }
|
|---|
| 463 |
|
|---|
| 464 | void do_crossfade(audio_chunk & p_dest,t_size destpos,const audio_chunk & p_src1,t_size src1pos,
|
|---|
| 465 | const audio_chunk & p_src2,t_size src2pos,t_size samples,t_uint ratiostart,t_uint ratioend)
|
|---|
| 466 | {
|
|---|
| 467 | if(samples == 0) return; // nothing to do
|
|---|
| 468 |
|
|---|
| 469 | // sanity check
|
|---|
| 470 | if (p_src1.get_srate() != p_src2.get_srate() ||
|
|---|
| 471 | p_src1.get_channel_config() != p_src2.get_channel_config() ||
|
|---|
| 472 | p_src1.get_channels() != p_src2.get_channels() ||
|
|---|
| 473 | p_dest.get_srate() != p_src1.get_srate() ||
|
|---|
| 474 | p_dest.get_channel_config() != p_src1.get_channel_config() ||
|
|---|
| 475 | p_dest.get_channels() != p_src1.get_channels()) {
|
|---|
| 476 | throw exception_unexpected_audio_format_change();
|
|---|
| 477 | }
|
|---|
| 478 | // length check
|
|---|
| 479 | if (p_src1.get_sample_count() < (src1pos + samples) ||
|
|---|
| 480 | p_src2.get_sample_count() < (src2pos + samples)) {
|
|---|
| 481 | throw exception_io("p_src1 or p_src2 unsufficient sample");
|
|---|
| 482 | }
|
|---|
| 483 | p_dest.pad_with_silence(destpos + samples);
|
|---|
| 484 | int nch = p_dest.get_channels();
|
|---|
| 485 | audio_sample * pd = p_dest.get_data() + (destpos*nch);
|
|---|
| 486 | const audio_sample * ps1 = p_src1.get_data() + (src1pos*nch);
|
|---|
| 487 | const audio_sample * ps2 = p_src2.get_data() + (src2pos*nch);
|
|---|
| 488 | do_crossfade(pd, ps1, ps2, nch, samples, ratiostart, ratioend);
|
|---|
| 489 | }
|
|---|
| 490 |
|
|---|
| 491 | void do_crossfade(audio_chunk & p_dest,t_size destpos,const audio_chunk & p_src,t_size srcpos,
|
|---|
| 492 | t_size samples,t_uint ratiostart,t_uint ratioend)
|
|---|
| 493 | {
|
|---|
| 494 | if(samples == 0) return; // nothing to do
|
|---|
| 495 |
|
|---|
| 496 | // sanity check
|
|---|
| 497 | if (p_dest.get_srate() != p_src.get_srate() ||
|
|---|
| 498 | p_dest.get_channel_config() != p_src.get_channel_config() ||
|
|---|
| 499 | p_dest.get_channels() != p_src.get_channels()) {
|
|---|
| 500 | throw exception_unexpected_audio_format_change();
|
|---|
| 501 | }
|
|---|
| 502 | // length check
|
|---|
| 503 | if (p_dest.get_sample_count() < (destpos + samples) ||
|
|---|
| 504 | p_src.get_sample_count() < (srcpos + samples)) {
|
|---|
| 505 | throw exception_io("p_dest or p_src unsufficient sample");
|
|---|
| 506 | }
|
|---|
| 507 | int nch = p_dest.get_channels();
|
|---|
| 508 | audio_sample * pd = p_dest.get_data() + (destpos*nch);
|
|---|
| 509 | const audio_sample * ps = p_src.get_data() + (srcpos*nch);
|
|---|
| 510 | do_crossfade(pd, pd, ps, nch, samples, ratiostart, ratioend);
|
|---|
| 511 | }
|
|---|
| 512 |
|
|---|
| 513 | class format_samples_ex {
|
|---|
| 514 | private:
|
|---|
| 515 | pfc::string_fixed_t<193> m_buffer;
|
|---|
| 516 | public:
|
|---|
| 517 | format_samples_ex(t_uint64 p_samples,t_uint32 p_sample_rate,unsigned p_extra = 3) {
|
|---|
| 518 | m_buffer << pfc::format_time_ex(audio_math::samples_to_time(p_samples,p_sample_rate),p_extra);
|
|---|
| 519 | m_buffer << " (";
|
|---|
| 520 | m_buffer << pfc::format_int(p_samples);
|
|---|
| 521 | m_buffer << ")";
|
|---|
| 522 | };
|
|---|
| 523 | const char * get_ptr() const {return m_buffer;}
|
|---|
| 524 | operator const char * () const {return m_buffer;}
|
|---|
| 525 | };
|
|---|
| 526 | }
|
|---|
| 527 |
|
|---|
| 528 |
|
|---|
| 529 | class input_sli
|
|---|
| 530 | {
|
|---|
| 531 | public:
|
|---|
| 532 | void open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
|
|---|
| 533 | if (p_reason == input_open_info_write) throw exception_io_unsupported_format();//our input does not support retagging.
|
|---|
| 534 | m_slifile = p_filehint;
|
|---|
| 535 | m_path = p_path;
|
|---|
| 536 | input_open_file_helper(m_slifile,p_path,p_reason,p_abort);//if m_file is null, opens file with appropriate privileges for our operation (read/write for writing tags, read-only otherwise).
|
|---|
| 537 | {
|
|---|
| 538 | t_sli_link_list sli_links;
|
|---|
| 539 | t_sli_label_list sli_labels;
|
|---|
| 540 | bool is_utf8;
|
|---|
| 541 | text_file_loader::read(m_slifile,p_abort,m_slicontent,is_utf8);
|
|---|
| 542 |
|
|---|
| 543 | if (!parse_sli(m_slicontent, sli_links, sli_labels)) {
|
|---|
| 544 | throw exception_io_unsupported_format();
|
|---|
| 545 | }
|
|---|
| 546 | m_links = sli_links;
|
|---|
| 547 | m_links.sort();
|
|---|
| 548 | m_labels = sli_labels;
|
|---|
| 549 | m_labels.sort();
|
|---|
| 550 | {
|
|---|
| 551 | no_flags = true;
|
|---|
| 552 | t_size num = m_links.get_count();
|
|---|
| 553 | for ( t_size i = 0; i < num; i++ ) {
|
|---|
| 554 | loop_condition * cond = m_links[i].condition.get_ptr();
|
|---|
| 555 | if (cond && cond->is_valid) {
|
|---|
| 556 | no_flags = false;
|
|---|
| 557 | break;
|
|---|
| 558 | }
|
|---|
| 559 | }
|
|---|
| 560 | }
|
|---|
| 561 | if (!no_flags) {
|
|---|
| 562 | m_flags.set_size_discard(SLI_FLAGS);
|
|---|
| 563 | pfc::fill_array_t(m_flags, 0);
|
|---|
| 564 | }
|
|---|
| 565 | }
|
|---|
| 566 | pfc::string8 p_content_path;
|
|---|
| 567 | p_content_path.set_string(p_path, pfc::strlen_utf8(p_path) - 4); // .sli
|
|---|
| 568 | in.open_path(NULL, p_content_path, p_abort, false, false);
|
|---|
| 569 | file_info_impl p_info;
|
|---|
| 570 | in.get_info(0, p_info, p_abort);
|
|---|
| 571 | sample_rate = (t_uint32) p_info.info_get_int("samplerate");
|
|---|
| 572 | crossfade_samples_half = MulDiv_Size(sample_rate, 25 /* ms */, 1000);
|
|---|
| 573 | }
|
|---|
| 574 |
|
|---|
| 575 | void get_info(file_info & p_info,abort_callback & p_abort) {
|
|---|
| 576 | in.get_info(0, p_info, p_abort);
|
|---|
| 577 | p_info.info_set("sli_content", m_slicontent);
|
|---|
| 578 | for (t_size n = 0, m = m_links.get_count(); n < m; ++n ) {
|
|---|
| 579 | sli_link link = m_links[n];
|
|---|
| 580 | pfc::string8 name;
|
|---|
| 581 | pfc::string8 buf;
|
|---|
| 582 | t_size prefixlen;
|
|---|
| 583 | name << "sli_link_" << pfc::format_int(n, 2) << "_";
|
|---|
| 584 | prefixlen = name.get_length();
|
|---|
| 585 |
|
|---|
| 586 | name.truncate(prefixlen);
|
|---|
| 587 | name << "from";
|
|---|
| 588 | p_info.info_set(name, format_samples_ex(link.from, sample_rate));
|
|---|
| 589 |
|
|---|
| 590 | name.truncate(prefixlen);
|
|---|
| 591 | name << "to";
|
|---|
| 592 | p_info.info_set(name, format_samples_ex(link.to, sample_rate));
|
|---|
| 593 |
|
|---|
| 594 | name.truncate(prefixlen);
|
|---|
| 595 | name << "extra";
|
|---|
| 596 | if (link.smooth) {
|
|---|
| 597 | buf << "smooth";
|
|---|
| 598 | }
|
|---|
| 599 | if (link.condition->is_valid) {
|
|---|
| 600 | if (!buf.is_empty())
|
|---|
| 601 | buf << "; ";
|
|---|
| 602 | buf << "cond:";
|
|---|
| 603 | buf << "[" << link.condvar << "]";
|
|---|
| 604 | buf << link.condition->symbol << link.refvalue;
|
|---|
| 605 | }
|
|---|
| 606 |
|
|---|
| 607 | if (!buf.is_empty())
|
|---|
| 608 | p_info.info_set(name, buf);
|
|---|
| 609 | }
|
|---|
| 610 | for (t_size n = 0, m = m_labels.get_count(); n < m; ++n ) {
|
|---|
| 611 | sli_label label = m_labels[n];
|
|---|
| 612 | pfc::string8 name;
|
|---|
| 613 | t_size prefixlen;
|
|---|
| 614 | name << "sli_label_" << pfc::format_int(n, 2) << "_";
|
|---|
| 615 | prefixlen = name.get_length();
|
|---|
| 616 |
|
|---|
| 617 | name.truncate(prefixlen);
|
|---|
| 618 | name << "pos";
|
|---|
| 619 | p_info.info_set(name, format_samples_ex(label.position, sample_rate));
|
|---|
| 620 |
|
|---|
| 621 | if (label.name) {
|
|---|
| 622 | if (label.name[0] == ':') {
|
|---|
| 623 | name.truncate(prefixlen);
|
|---|
| 624 | name << "formula";
|
|---|
| 625 | p_info.info_set(name, label.name.get_ptr() + 1);
|
|---|
| 626 | } else {
|
|---|
| 627 | name.truncate(prefixlen);
|
|---|
| 628 | name << "name";
|
|---|
| 629 | p_info.info_set(name, label.name);
|
|---|
| 630 | }
|
|---|
| 631 | }
|
|---|
| 632 | }
|
|---|
| 633 | // FIXME
|
|---|
| 634 | }
|
|---|
| 635 | t_filestats get_file_stats(abort_callback & p_abort) {return m_slifile->get_stats(p_abort);}
|
|---|
| 636 |
|
|---|
| 637 | void decode_initialize(unsigned p_flags,abort_callback & p_abort) {
|
|---|
| 638 | no_looping = (p_flags & input_flag_simpledecode) != 0;
|
|---|
| 639 | in.open_decoding(0,p_flags,p_abort);
|
|---|
| 640 | if (!no_looping) {
|
|---|
| 641 | cur = 0;
|
|---|
| 642 | schedule_nextevent(cur);
|
|---|
| 643 | check_event(p_abort);
|
|---|
| 644 | }
|
|---|
| 645 | }
|
|---|
| 646 |
|
|---|
| 647 | t_size get_nearest_link(t_uint64 pos) {
|
|---|
| 648 | t_size nums = m_links.get_count();
|
|---|
| 649 | if (!nums) return infinite_size;
|
|---|
| 650 | t_size index;
|
|---|
| 651 | m_links.bsearch(pos, index);
|
|---|
| 652 | if (index < nums) {
|
|---|
| 653 | return index;
|
|---|
| 654 | } else {
|
|---|
| 655 | return infinite_size;
|
|---|
| 656 | }
|
|---|
| 657 | }
|
|---|
| 658 |
|
|---|
| 659 | t_size get_nearest_label(t_uint64 pos) {
|
|---|
| 660 | t_size nums = m_labels.get_count();
|
|---|
| 661 | if (!nums) return infinite_size;
|
|---|
| 662 | t_size index;
|
|---|
| 663 | m_labels.bsearch(pos, index);
|
|---|
| 664 | if (index < nums) {
|
|---|
| 665 | return index;
|
|---|
| 666 | } else {
|
|---|
| 667 | return infinite_size;
|
|---|
| 668 | }
|
|---|
| 669 | }
|
|---|
| 670 |
|
|---|
| 671 | inline t_uint64 link_get_process_start_samples(sli_link & link) {
|
|---|
| 672 | if (!link.smooth) return link.from;
|
|---|
| 673 | else if (link.from > crossfade_samples_half) return link.from - crossfade_samples_half;
|
|---|
| 674 | else return 0;
|
|---|
| 675 | }
|
|---|
| 676 |
|
|---|
| 677 | void schedule_nextevent(t_uint64 pos) {
|
|---|
| 678 | t_size index;
|
|---|
| 679 | if (no_looping) return;
|
|---|
| 680 |
|
|---|
| 681 | index = get_nearest_link(pos);
|
|---|
| 682 | if (index != infinite_size) {
|
|---|
| 683 | sli_link link = m_links[index];
|
|---|
| 684 | m_nextlinkpos = link_get_process_start_samples(link);
|
|---|
| 685 | } else {
|
|---|
| 686 | m_nextlinkpos = infinite64;
|
|---|
| 687 | }
|
|---|
| 688 |
|
|---|
| 689 | if (no_flags) return;
|
|---|
| 690 | index = get_nearest_label(pos);
|
|---|
| 691 | if (index != infinite_size) {
|
|---|
| 692 | m_nextlabelpos = m_labels[index].position;
|
|---|
| 693 | } else {
|
|---|
| 694 | m_nextlabelpos = infinite64;
|
|---|
| 695 | }
|
|---|
| 696 | }
|
|---|
| 697 |
|
|---|
| 698 | inline void check_event(abort_callback & p_abort) {
|
|---|
| 699 | if (no_looping) return;
|
|---|
| 700 | if (m_nextlinkpos == cur) {
|
|---|
| 701 | // seeking (ignore crossfade)
|
|---|
| 702 | t_size num = m_links.get_count();
|
|---|
| 703 | t_size index = get_nearest_link(cur);
|
|---|
| 704 | while (index < num) {
|
|---|
| 705 | sli_link nextlink = m_links[index];
|
|---|
| 706 | if (nextlink.from != cur) break;
|
|---|
| 707 | loop_condition * cond = nextlink.condition.get_ptr();
|
|---|
| 708 | if (!cond || !cond->is_valid || cond->check(m_flags[nextlink.condvar], nextlink.refvalue)) {
|
|---|
| 709 | in.seek(audio_math::samples_to_time(nextlink.to,sample_rate),p_abort);
|
|---|
| 710 | cur = nextlink.to;
|
|---|
| 711 | schedule_nextevent(cur);
|
|---|
| 712 | check_event(p_abort);
|
|---|
| 713 | return;
|
|---|
| 714 | }
|
|---|
| 715 | index++;
|
|---|
| 716 | }
|
|---|
| 717 | }
|
|---|
| 718 | }
|
|---|
| 719 |
|
|---|
| 720 | inline bool process_labels(t_uint64 p_start, t_uint64 p_end) {
|
|---|
| 721 | if (no_looping || no_flags) return false;
|
|---|
| 722 | if (p_start == cur && m_nextlabelpos > p_end) {
|
|---|
| 723 | // use cached result and no match
|
|---|
| 724 | return false;
|
|---|
| 725 | }
|
|---|
| 726 | t_size num = m_labels.get_count();
|
|---|
| 727 | t_size index = get_nearest_label(p_start);
|
|---|
| 728 | while (index < num) {
|
|---|
| 729 | sli_label label = m_labels[index];
|
|---|
| 730 | if (label.position > p_end) break;
|
|---|
| 731 | if (!label.name.is_empty() && label.name[0] == ':') {
|
|---|
| 732 | sli_label_formula formula;
|
|---|
| 733 | if (parse_sli_label_formula(label.name.get_ptr() + 1, formula)) {
|
|---|
| 734 | t_size flagnum = m_flags.get_size();
|
|---|
| 735 | t_size flag = formula.flag;
|
|---|
| 736 | unsigned int value = formula.value;
|
|---|
| 737 | if (formula.indirect) {
|
|---|
| 738 | value = m_flags[value];
|
|---|
| 739 | }
|
|---|
| 740 | m_flags[flag] = formula.oper->calculate(m_flags[flag], value);
|
|---|
| 741 | }
|
|---|
| 742 | }
|
|---|
| 743 | index++;
|
|---|
| 744 | }
|
|---|
| 745 | return true;
|
|---|
| 746 | }
|
|---|
| 747 |
|
|---|
| 748 | bool decode_run(audio_chunk & p_chunk,abort_callback & p_abort) {
|
|---|
| 749 | if (no_looping) return in.run(p_chunk,p_abort);
|
|---|
| 750 | check_event(p_abort);
|
|---|
| 751 | bool succ = in.run(p_chunk,p_abort);
|
|---|
| 752 | t_size samples = p_chunk.get_sample_count();
|
|---|
| 753 | t_uint64 end = cur + samples;
|
|---|
| 754 | if (m_nextlinkpos <= end) {
|
|---|
| 755 | process_link(succ, p_chunk, p_abort);
|
|---|
| 756 | } else {
|
|---|
| 757 | if (process_labels(cur, end)) {
|
|---|
| 758 | schedule_nextevent(end);
|
|---|
| 759 | }
|
|---|
| 760 | cur = end;
|
|---|
| 761 | }
|
|---|
| 762 | check_event(p_abort);
|
|---|
| 763 | return succ;
|
|---|
| 764 | }
|
|---|
| 765 |
|
|---|
| 766 | void process_link(bool & succ,audio_chunk & p_chunk,abort_callback & p_abort) {
|
|---|
| 767 | // FIXME: be able to dispatch first matched event only
|
|---|
| 768 | t_size num = m_links.get_count();
|
|---|
| 769 | t_size index = get_nearest_link(cur);
|
|---|
| 770 | t_size samples = p_chunk.get_sample_count();
|
|---|
| 771 | t_uint64 end = cur + samples;
|
|---|
| 772 | t_uint64 labelprocessed = cur;
|
|---|
| 773 | while (index < num) {
|
|---|
| 774 | sli_link nextlink = m_links[index];
|
|---|
| 775 | if (link_get_process_start_samples(nextlink) > end) break;
|
|---|
| 776 | // process labels until nextlink
|
|---|
| 777 | process_labels(labelprocessed, nextlink.from);
|
|---|
| 778 | labelprocessed = nextlink.from;
|
|---|
| 779 | loop_condition * cond = nextlink.condition.get_ptr();
|
|---|
| 780 | if (cond && cond->is_valid && !cond->check(m_flags[nextlink.condvar], nextlink.refvalue)) {
|
|---|
| 781 | // condition failed. dispatch next event
|
|---|
| 782 | index++;
|
|---|
| 783 | continue;
|
|---|
| 784 | }
|
|---|
| 785 | // must not occured event on start point (processed in previous decode)
|
|---|
| 786 | PFC_ASSERT(cur != nextlink.from);
|
|---|
| 787 | // ok; continue..
|
|---|
| 788 | if (!nextlink.smooth) {
|
|---|
| 789 | // tiny seeking
|
|---|
| 790 | in.seek(audio_math::samples_to_time(nextlink.to,sample_rate),p_abort);
|
|---|
| 791 | // cut tail
|
|---|
| 792 | p_chunk.set_sample_count(pfc::downcast_guarded<t_size>(nextlink.from - cur));
|
|---|
| 793 | cur = end = nextlink.to;
|
|---|
| 794 | break;
|
|---|
| 795 | }
|
|---|
| 796 | // crossfading
|
|---|
| 797 | t_size cf_samples_first = pfc::downcast_guarded<t_size>(
|
|---|
| 798 | nextlink.from - link_get_process_start_samples(nextlink));
|
|---|
| 799 | t_size cf_samples_latter = crossfade_samples_half;
|
|---|
| 800 | t_size src_cf_center_samples = pfc::downcast_guarded<t_size>(nextlink.from - cur);
|
|---|
| 801 | t_size candidate = src_cf_center_samples + cf_samples_latter;
|
|---|
| 802 | t_size tmpsize;
|
|---|
| 803 | while (succ && candidate > p_chunk.get_sample_count()) {
|
|---|
| 804 | // more data
|
|---|
| 805 | audio_chunk_impl_temporary ptmp_chunk;
|
|---|
| 806 | succ = in.run(ptmp_chunk,p_abort);
|
|---|
| 807 | combine_audio_chunks(p_chunk, ptmp_chunk);
|
|---|
| 808 | }
|
|---|
| 809 | tmpsize = p_chunk.get_sample_count();
|
|---|
| 810 | if (candidate > tmpsize) {
|
|---|
| 811 | // encount eof
|
|---|
| 812 | cf_samples_latter = tmpsize - src_cf_center_samples;
|
|---|
| 813 | }
|
|---|
| 814 | t_uint64 dest_first = nextlink.to;
|
|---|
| 815 | if (cf_samples_first > dest_first) {
|
|---|
| 816 | cf_samples_first = static_cast<t_size>(dest_first);
|
|---|
| 817 | dest_first = 0;
|
|---|
| 818 | } else {
|
|---|
| 819 | dest_first -= cf_samples_first;
|
|---|
| 820 | }
|
|---|
| 821 | // seeking to destination
|
|---|
| 822 | in.seek(audio_math::samples_to_time(dest_first,sample_rate),p_abort);
|
|---|
| 823 | succ = true;
|
|---|
| 824 | audio_chunk_impl_temporary ptmp_dest_chunk;
|
|---|
| 825 | candidate = cf_samples_first + cf_samples_latter;
|
|---|
| 826 | while (succ && candidate > ptmp_dest_chunk.get_sample_count()) {
|
|---|
| 827 | // get data
|
|---|
| 828 | audio_chunk_impl_temporary ptmp_chunk;
|
|---|
| 829 | succ = in.run(ptmp_chunk,p_abort);
|
|---|
| 830 | combine_audio_chunks(ptmp_dest_chunk,ptmp_chunk);
|
|---|
| 831 | }
|
|---|
| 832 | t_size destsamples = ptmp_dest_chunk.get_sample_count();
|
|---|
| 833 | if (destsamples < candidate) {
|
|---|
| 834 | cf_samples_latter = destsamples - cf_samples_first;
|
|---|
| 835 | }
|
|---|
| 836 | t_size cf_samples = cf_samples_first + cf_samples_latter;
|
|---|
| 837 | do_crossfade(
|
|---|
| 838 | p_chunk, src_cf_center_samples-cf_samples_first,
|
|---|
| 839 | ptmp_dest_chunk, 0,
|
|---|
| 840 | cf_samples_first, 0, 50);
|
|---|
| 841 | do_crossfade(
|
|---|
| 842 | p_chunk, src_cf_center_samples,
|
|---|
| 843 | ptmp_dest_chunk, cf_samples_first,
|
|---|
| 844 | cf_samples_latter, 50, 100);
|
|---|
| 845 | p_chunk.set_sample_count(src_cf_center_samples+cf_samples_latter);
|
|---|
| 846 | audio_chunk_partial_ref latter = audio_chunk_partial_ref(
|
|---|
| 847 | ptmp_dest_chunk, cf_samples, destsamples - cf_samples);
|
|---|
| 848 | combine_audio_chunks(p_chunk, latter);
|
|---|
| 849 | samples = p_chunk.get_sample_count();
|
|---|
| 850 | cur = end = nextlink.to + destsamples - cf_samples_first;
|
|---|
| 851 | process_labels(nextlink.to, cur);
|
|---|
| 852 | break;
|
|---|
| 853 | }
|
|---|
| 854 | if (cur != end) {
|
|---|
| 855 | // dispatch labels (because all link not matched)
|
|---|
| 856 | process_labels(labelprocessed, end);
|
|---|
| 857 | }
|
|---|
| 858 | schedule_nextevent(end);
|
|---|
| 859 | }
|
|---|
| 860 |
|
|---|
| 861 | void decode_seek(double p_seconds,abort_callback & p_abort) {
|
|---|
| 862 | in.seek(p_seconds,p_abort);
|
|---|
| 863 | if (no_looping) return;
|
|---|
| 864 | cur = audio_math::time_to_samples(p_seconds,sample_rate);
|
|---|
| 865 | schedule_nextevent(cur);
|
|---|
| 866 | check_event(p_abort);
|
|---|
| 867 | }
|
|---|
| 868 |
|
|---|
| 869 | bool decode_can_seek() {return in.can_seek();}
|
|---|
| 870 | bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) {
|
|---|
| 871 | bool ret = in.get_dynamic_info(p_out, p_timestamp_delta);
|
|---|
| 872 | if (!no_looping && (cur < m_lastupdatedynamic || cur - m_lastupdatedynamic > (sample_rate / 2))) {
|
|---|
| 873 | if (p_timestamp_delta == 0) {
|
|---|
| 874 | p_timestamp_delta = 0.5;
|
|---|
| 875 | } else {
|
|---|
| 876 | p_timestamp_delta = pfc::min_t<double>(0.5, p_timestamp_delta);
|
|---|
| 877 | }
|
|---|
| 878 | p_out.info_set("sli_current", format_samples_ex(cur, sample_rate));
|
|---|
| 879 | p_out.info_set("sli_wait_link_pos", (m_nextlinkpos != infinite64) ?
|
|---|
| 880 | format_samples_ex(m_nextlinkpos, sample_rate) : "None");
|
|---|
| 881 | if (!no_flags) {
|
|---|
| 882 | p_out.info_set("sli_wait_label_pos", (m_nextlabelpos != infinite64) ?
|
|---|
| 883 | format_samples_ex(m_nextlabelpos, sample_rate) : "None");
|
|---|
| 884 | pfc::string8 buf;
|
|---|
| 885 | t_size num = m_flags.get_size();
|
|---|
| 886 | for ( t_size i = 0; i < num; i++ ) {
|
|---|
| 887 | if (!buf.is_empty())
|
|---|
| 888 | buf << "/";
|
|---|
| 889 | buf << "[" << i << "]=" << m_flags[i];
|
|---|
| 890 | }
|
|---|
| 891 | p_out.info_set("sli_flags", buf);
|
|---|
| 892 | }
|
|---|
| 893 | m_lastupdatedynamic = cur;
|
|---|
| 894 | ret = true;
|
|---|
| 895 | }
|
|---|
| 896 | return ret;
|
|---|
| 897 | }
|
|---|
| 898 | bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) {
|
|---|
| 899 | return in.get_dynamic_info_track(p_out, p_timestamp_delta);
|
|---|
| 900 | }
|
|---|
| 901 |
|
|---|
| 902 | void decode_on_idle(abort_callback & p_abort) {in.on_idle(p_abort);}
|
|---|
| 903 |
|
|---|
| 904 | void retag(const file_info & p_info,abort_callback & p_abort) {throw exception_io_unsupported_format();}
|
|---|
| 905 |
|
|---|
| 906 | void set_logger(event_logger::ptr ptr) { in.set_logger(ptr);}
|
|---|
| 907 |
|
|---|
| 908 | static bool g_is_our_content_type(const char * p_content_type) {return false;}
|
|---|
| 909 | static bool g_is_our_path(const char * p_path,const char * p_extension) {return stricmp_utf8(p_extension, "sli") == 0;}
|
|---|
| 910 |
|
|---|
| 911 | private:
|
|---|
| 912 | t_uint64 m_nextlabelpos;
|
|---|
| 913 | t_uint64 m_nextlinkpos;
|
|---|
| 914 | t_uint64 m_lastupdatedynamic;
|
|---|
| 915 | service_ptr_t<file> m_slifile;
|
|---|
| 916 | pfc::string8 m_path;
|
|---|
| 917 | pfc::string8 m_slicontent;
|
|---|
| 918 | t_uint64 cur;
|
|---|
| 919 | t_size crossfade_samples_half;
|
|---|
| 920 | bool no_looping;
|
|---|
| 921 | bool no_flags;
|
|---|
| 922 | t_sli_link_list m_links;
|
|---|
| 923 | t_sli_label_list m_labels;
|
|---|
| 924 | pfc::array_staticsize_t<int> m_flags;
|
|---|
| 925 |
|
|---|
| 926 | t_uint32 sample_rate;
|
|---|
| 927 |
|
|---|
| 928 | input_helper in;
|
|---|
| 929 | };
|
|---|
| 930 |
|
|---|
| 931 |
|
|---|
| 932 | static input_singletrack_factory_t<input_sli> g_input_sli_factory;
|
|---|
| 933 |
|
|---|
| 934 |
|
|---|
| 935 | DECLARE_COMPONENT_VERSION("sli repeator","0.1-test",NULL);
|
|---|
| 936 | DECLARE_FILE_TYPE("sli loop information file","*.SLI"); |
|---|