//- LISP API - // playback-set-file (string)fileName -> t/nil base::cell_t set_file(base::lisp &gl, base::cell_t c, base::cells_t &) { if (base::lisp::validate(c, base::cell::list(1), base::cell::typeString)) { const auto &fname = c + 1; // stop current playback ts.stop(); ts.setSource(nullptr); frs = nullptr; AudioFormatReader *r; // ectract CUE information (if any) std::regex cue("^(.*):(\\d+):(\\d+)$"); std::smatch result; std::regex_search(fname->s, result, cue); if (result.size() == 4) { // is cue int32 start = base::fromStr<int32>(result[2].str()); int32 end = base::fromStr<int32>(result[3].str()); int32 duration = end - start; AudioFormatReader *tr = fm.createReaderFor(File(result[1].str())); // start, end are in frames (1 frame = 1/75 second) - convert to sample float samplesInOneSecond = tr->sampleRate; // AudioSubsectionReader will handle channels count float startSecond = (float)start / 75.0f; float durationSecond = (float)duration / 75.0f; float startSample = startSecond * samplesInOneSecond; float durationSamples = durationSecond * samplesInOneSecond; // some CUE may have 0 length (play to end) if (end <= start) durationSamples = tr->lengthInSamples; r = new AudioSubsectionReader(tr, (int)startSample, (int)durationSamples, true); } else { // regular file r = fm.createReaderFor(File(fname->s)); } if (r) { frs = new AudioFormatReaderSource(r, true); ts.setSource(frs, 32768, &thread, r->sampleRate); return gl.t(); } gl.signalError(base::strs("file not found or file format not supported: ", fname->s)); return gl.nil(); } gl.signalError("playback-set-file: invalid arguments, expected (string)"); return gl.nil(); }
// (ctags-remove (string|id)) -> nil/t base::cell_t ctags_remove(base::lisp &gl, base::cell_t c, base::cells_t &ret) { if (base::lisp::validate(c, base::cell::list(1), base::cell::typeString)) { const auto &key = c + 1; removeTag(key->s); return gl.t(); } gl.signalError("ctags-set: invalid arguments, expected (string int any)"); return gl.nil(); }
// playback-seek (float)posSeconds base::cell_t seek(base::lisp &gl, base::cell_t c, base::cells_t &) { if (base::lisp::validate(c, base::cell::list(1), base::cell::typeFloat)) { const auto &pos = c + 1; ts.setPosition((double)pos->f); return gl.nil(); } gl.signalError("playback-seek: invalid arguments, expected (float)"); return gl.nil(); }
// (ctags-load (string|file-name)) -> nil/t base::cell_t ctags_load(base::lisp &gl, base::cell_t c, base::cells_t &ret) { if (base::lisp::validate(c, base::cell::list(1), base::cell::typeString)) { const auto &fileName = c + 1; if (loadTags(fileName->s)) return gl.t(); return gl.nil(); } gl.signalError("ctags-load: invalid arguments, expected (string)"); return gl.nil(); }
//- LISP API // (ctags-get (string|id) (int|items-count)) -> any/nil base::cell_t ctags_get(base::lisp &gl, base::cell_t c, base::cells_t &ret) { if (base::lisp::validate(c, base::cell::list(2), base::cell::typeString, base::cell::typeInt)) { const auto &key = c + 1; const auto &num = c + 2; ret.push_back(getCustomTag(key->s, num->i)); return ret.end(); } gl.signalError("ctags-get: invalid arguments, expected (string int)"); return gl.nil(); }
// (ctags-set (string|id) (int|item-index) any) -> nil/t base::cell_t ctags_set(base::lisp &gl, base::cell_t c, base::cells_t &ret) { if (base::lisp::validate(c, base::cell::list(3), base::cell::typeString, base::cell::typeInt /* any */)) { const auto &key = c + 1; const auto &num = c + 2; const auto &value = c + 3; setCustomTag(key->s, num->i, *value); return gl.t(); } gl.signalError("ctags-set: invalid arguments, expected (string int any)"); return gl.nil(); }
//- LISP API - // playback-set-file (string)fileName -> t/nil base::cell_t set_file(base::lisp &gl, base::cell_t c, base::cells_t &) { if (base::lisp::validate(c, base::cell::list(1), base::cell::typeString)) { const auto &fname = c + 1; // stop current playback ts.stop(); ts.setSource(nullptr); frs = nullptr; AudioFormatReader *r; // ectract CUE information (if any) std::regex cue("^(.*):(\\d+):(\\d+)$"); std::smatch result; std::regex_search(fname->s, result, cue); if (result.size() == 4) { // is cue int32 start = base::fromStr<int32>(result[2].str()); int32 end = base::fromStr<int32>(result[3].str()); AudioFormatReader *tr = fm.createReaderFor(File(result[1].str())); r = new AudioSubsectionReader(tr, start, end - start, true); } else { // regular file r = fm.createReaderFor(File(fname->s)); } if (r) { frs = new AudioFormatReaderSource(r, true); ts.setSource(frs, 32768, &thread, r->sampleRate); return gl.t(); } gl.signalError(base::strs("file not found or file format not supported: ", fname->s)); return gl.nil(); } gl.signalError("playback-set-file: invalid arguments, expected (string)"); return gl.nil(); }
// (bind-playback (id)callback) base::cell_t bind_playback(base::lisp &gl, base::cell_t c, base::cells_t &) { if (pl) { if (base::lisp::validate(c, base::cell::list(1), base::cell::typeIdentifier)) { const auto &fx = c + 1; pl->functionId = fx->s; pl->enabled = true; return gl.t(); } pl->enabled = false; return gl.nil(); } gl.signalError("bind-playback: invalid arguments, expected (id)"); return gl.nil(); }
// (playback-gain (float|optional)gain) -> t/nil | gain base::cell_t gain(base::lisp &gl, base::cell_t c, base::cells_t &ret) { if (pl) { if (base::lisp::validate(c, base::cell::listRange(1), base::cell::typeFloat)) { // setter ts.setGain((c + 1)->f); return gl.t(); } else if (base::lisp::validate(c, base::cell::list(0))) { // getter ret.push_back(base::cell(ts.getGain())); return ret.end(); } gl.signalError("playback-gain: invalid arguments, expected ((optional) float)"); } return gl.nil(); }