diff --git a/include/symusic/ops.h b/include/symusic/ops.h index 1994ca2..d0c308a 100644 --- a/include/symusic/ops.h +++ b/include/symusic/ops.h @@ -43,6 +43,17 @@ void sort_pedals(vec> & pedals, const bool reverse = false) { #undef KEY } +template +void sort_tracks(vec> & tracks, const bool reverse = false) { + #define KEY(TRACK) std::make_tuple(TRACK.is_drum, TRACK.program, TRACK.name, TRACK.note_num()) + if (reverse) { + pdqsort_branchless(tracks.begin(), tracks.end(), [](const Track & a, const Track & b) {return KEY(a) > KEY(b);}); + } else { + pdqsort_branchless(tracks.begin(), tracks.end(), [](const Track & a, const Track & b) {return KEY(a) < KEY(b);}); + } + #undef KEY +} + template void sort(Iter begin, Iter end, Compare cmp) { diff --git a/py_src/core.cpp b/py_src/core.cpp index 94dd168..4255f78 100644 --- a/py_src/core.cpp +++ b/py_src/core.cpp @@ -43,16 +43,21 @@ NB_MAKE_OPAQUE(vec) // PYBIND11_MAKE_OPAQUE(vec) template -void sort_by_py_key(vec &self, const py::callable & key) { +void sort_by_key(vec &self, const py::callable & key) { pdqsort(self.begin(), self.end(), [&key](const T &a, const T &b) { return key(a) < key(b); }); } -template -vec & py_sort_inplace(vec &self, const py::object & key, const bool reverse) { - if (key.is_none()) ops::sort_by_time(self); - else sort_by_py_key(self, py::cast(key)); +template typename T, typename U> +vec> & py_sort_inplace(vec> &self, const py::object & key, const bool reverse) { + if (key.is_none()) { + if constexpr (std::is_same_v, Note>) ops::sort_notes(self); + else if constexpr (std::is_same_v, Pedal>) ops::sort_pedals(self); + else if constexpr (std::is_same_v, Track>) ops::sort_tracks(self); + else ops::sort_by_time(self); + } + else sort_by_key>(self, py::cast(key)); if (reverse) std::reverse(self.begin(), self.end()); return self; } @@ -536,19 +541,7 @@ py::class_> bind_track_class(py::module_ &m, const std::string & name_) }, py::arg("modes"), py::arg("pitchRange")=std::pair(0, 127), py::arg("encodeVelocity")=false); py::bind_vector>>(m, std::string(name + "List").c_str()) - .def("sort", [](vec> &self, const py::object & key, const bool reverse, const bool inplace) { - if (key.is_none()) throw std::invalid_argument("key must be specified"); - if (inplace) { - sort_by_py_key(self, py::cast(key)); - if (reverse) std::reverse(self.begin(), self.end()); - return py::cast(self, py::rv_policy::reference); - } else { // copy - auto copy = vec>(self); - sort_by_py_key(copy, py::cast(key)); - if (reverse) std::reverse(copy.begin(), copy.end()); - return py::cast(copy, py::rv_policy::move); - } - }, py::arg("key"), py::arg("reverse")=false, py::arg("inplace")=true) + .def("sort", &py_sort>, py::arg("key")=py::none(), py::arg("reverse")=false, py::arg("inplace")=true) .def("__repr__", [](const vec> &self) { vec strs; strs.reserve(self.size()); for(const auto & track: self) { @@ -724,69 +717,6 @@ py::object convert_score(const Score &self, const py::object &ttype, const py if (ttype_str == "second") return py::cast(convert(self, cast_time(min_dur)), py::rv_policy::move); } throw std::invalid_argument("ttype must be Tick, Quarter, Second or string"); } -// -// template -// py::class_> bind_note_arr(py::module_ &m, const std::string & name_) { -// const auto name = "NoteArr" + name_; -// -// return py::class_>(m, name.c_str()) -// .def(py::init &>(), "Copy constructor", py::arg("other")) -// .def(py::init(), "create with name, program and is_drum", py::arg("name")="", py::arg("program")=0, py::arg("is_drum")=false) -// // .def(py::init([]( -// // std::string name, u8 program, bool is_drum, -// // const py::array_t &time, -// // const py::array_t &duration, -// // const py::array_t &pitch, -// // const py::array_t &velocity) { -// // if (time.size() != duration.size() || time.size() != pitch.size() || time.size() != velocity.size()) -// // throw std::invalid_argument("time, duration, pitch and velocity must have the same size"); -// // const auto size = time.size(); -// // NoteArr arr(name, program, is_drum); -// // arr.reserve(size); -// // for (size_t i = 0; i < size; ++i) { -// // arr.emplace_back(time.at(i), duration.at(i), pitch.at(i), velocity.at(i)); -// // } -// // return arr; -// // }), "Creat from numpy", py::arg("name")="", py::arg("program")=0, py::arg("is_drum")=false, -// // py::arg("time")=py::array_t(), -// // py::arg("duration")=py::array_t(), -// // py::arg("pitch")=py::array_t(), -// // py::arg("velocity")=py::array_t()) -// .def("copy", &NoteArr::copy, "Deep copy", py::rv_policy::move) -// .def("__copy__", &NoteArr::copy, "Deep copy") -// .def("__deepcopy__", &NoteArr::copy, "Deep copy") -// .def("__repr__", &NoteArr::to_string) -// .def(py::self == py::self) // NOLINT -// .def(py::self != py::self) // NOLINT -// // getter convert vector to numpy array (reference) -// // setter accept numpy array using copy -// // .def(py::pickle( &py_to_bytes>, &py_from_bytes>)) -// .def("__getstate__", &py_to_bytes>) -// .def("__setstate__", &py_from_bytes>) -// .def("start", &NoteArr::start) -// .def("end", &NoteArr::end) -// .def("note_num", &NoteArr::note_num) -// .def("empty", &NoteArr::empty) -// .def("valid", &NoteArr::valid) -// .def("summary" , &NoteArr::summary) -// .def("sort", &NoteArr::sort, py::arg("reverse")=false) -// .def("clip", &NoteArr::clip, "Clip notes and controls to a given time range", py::arg("start"), py::arg("end"), py::arg("clip_end")=false) -// .def("reserve", &NoteArr::reserve, "Reserve memory for notes", py::arg("size")) -// .def("push_back", &NoteArr::emplace_back, py::arg("time"), py::arg("duration"), py::arg("pitch"), py::arg("velocity")) -// .def("push_back", &NoteArr::push_back, py::arg("note")) -// .def_rw("pitch", &NoteArr::pitch) -// .def_rw("velocity", &NoteArr::velocity) -// .def_rw("time", &NoteArr::time) -// .def_rw("duration", &NoteArr::duration); -// // .def("numpy", [](NoteArr &self) { -// // using namespace pybind11::literals; // to bring in the `_a` literal -// // // convert vector to numpy array -// // return py::dict("time"_a=py::array_t(self.time.size(), self.time.data()), -// // "duration"_a=py::array_t(self.duration.size(), self.duration.data()), -// // "pitch"_a=py::array_t(self.pitch.size(), self.pitch.data()), -// // "velocity"_a=py::array_t(self.velocity.size(), self.velocity.data())); -// // }); -// } py::module_ & core_module(py::module_ & m){ const std::string tick = "Tick", quarter = "Quarter", second = "Second"; diff --git a/symusic/__init__.py b/symusic/__init__.py index a7ca450..9df8f31 100644 --- a/symusic/__init__.py +++ b/symusic/__init__.py @@ -12,7 +12,7 @@ Track, ) -__version__ = "0.3.0" +__version__ = "0.3.1" __all__ = [ "TimeUnit",