tempomap.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. This file is part of QTau
  3. Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
  4. Copyright (C) 2013 digited <https://github.com/digited>
  5. Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
  6. QTau is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. SPDX-License-Identifier: GPL-3.0+
  17. */
  18. #include "tempomap.h"
  19. #include <Utils.h>
  20. #include <QJsonObject>
  21. #define __devloglevel__ 4
  22. bool indexCompare(const tempoindex &i1, const tempoindex &i2) {
  23. return i1.pos < i2.pos;
  24. }
  25. void TempoMap::updateIndexList() {
  26. qSort(_index.begin(), _index.end(), indexCompare);
  27. // calculate bar offsets for gui and sound
  28. }
  29. TempoMap::TempoMap() {
  30. }
  31. void TempoMap::addTempo(int pos, float tempo) {
  32. beginInsertRows(QModelIndex(), 1, 1);
  33. _tempo[pos] = tempo;
  34. tempoindex idx;
  35. idx.pos = pos;
  36. idx.type = 0;
  37. _index.append(idx);
  38. updateIndexList();
  39. endInsertRows();
  40. }
  41. void TempoMap::addTimeSignature(int pos, int numerator, int denominator) {
  42. beginInsertRows(QModelIndex(), 1, 1);
  43. fraction time;
  44. time.denominator = denominator;
  45. time.numerator = numerator;
  46. tempoindex idx;
  47. idx.pos = pos;
  48. idx.type = 1;
  49. _index.append(idx);
  50. _time[pos] = time;
  51. updateIndexList();
  52. endInsertRows();
  53. }
  54. void TempoMap::removeEventAt(int index) {
  55. if (index < _index.size() && index >= 0) {
  56. beginRemoveRows(QModelIndex(), index, index);
  57. if (_index[index].type == 1) {
  58. _time.remove(_index[index].pos);
  59. } else if (_index[index].type == 0) {
  60. _tempo.remove(_index[index].pos);
  61. }
  62. _index.removeAt(index);
  63. updateIndexList();
  64. endRemoveRows();
  65. }
  66. }
  67. void TempoMap::removeTempoForBar(int pos)
  68. {
  69. for(int index=0; index<_index.size(); index++)
  70. {
  71. if(_index[index].pos==pos && _index[index].type == 0)
  72. {
  73. removeEventAt(index);
  74. return;
  75. }
  76. }
  77. }
  78. void TempoMap::removeTimeSignatureForBar(int pos)
  79. {
  80. for(int index=0; index<_index.size(); index++)
  81. {
  82. if(_index[index].pos==pos && _index[index].type == 1)
  83. {
  84. removeEventAt(index);
  85. return;
  86. }
  87. }
  88. }
  89. fraction TempoMap::getTimeSignatureForBar(int pos) {
  90. fraction time = _time[pos];
  91. while (time.denominator == 0 && time.numerator == 0) {
  92. pos--;
  93. time = _time[pos];
  94. }
  95. return time;
  96. }
  97. QModelIndex TempoMap::index(int row, int column,
  98. const QModelIndex &parent) const {
  99. Q_UNUSED(parent);
  100. return createIndex(row, column);
  101. }
  102. QModelIndex TempoMap::parent(const QModelIndex &child) const {
  103. Q_UNUSED(child);
  104. return QModelIndex();
  105. }
  106. int TempoMap::rowCount(const QModelIndex &parent) const {
  107. Q_UNUSED(parent);
  108. return _index.count();
  109. }
  110. int TempoMap::columnCount(const QModelIndex &parent) const {
  111. Q_UNUSED(parent);
  112. return 3;
  113. }
  114. QVariant TempoMap::data(const QModelIndex &index, int role) const {
  115. if (role != Qt::DisplayRole) return QVariant();
  116. int row = index.row();
  117. int col = index.column();
  118. int pos = _index[row].pos;
  119. int type = _index[row].type;
  120. if (col == 0) return QVariant(pos + 1).toString();
  121. if (col == 1) {
  122. if (type == 0) return "Tempo";
  123. if (type == 1) return "Time Signature";
  124. }
  125. if (col == 2) {
  126. if (type == 0) return _tempo[pos];
  127. if (type == 1)
  128. return QVariant(_time[pos].numerator).toString() + "/" +
  129. QVariant(_time[pos].denominator).toString();
  130. }
  131. return QVariant();
  132. }
  133. void TempoMap::beginEditing() {
  134. _origIndex = _index;
  135. _origTempo = _tempo;
  136. _origTime = _time;
  137. }
  138. void TempoMap::toJson(QJsonArray &array) {
  139. DEVLOG_DEBUG("tempoMap::toJson "+STR(_index.size()));
  140. for (int i = 0; i < _index.length(); i++) {
  141. int pos = _index[i].pos;
  142. int type = _index[i].type;
  143. if (type == 1) {
  144. QJsonObject val;
  145. val["pos"] = pos;
  146. val["type"] = "timeSig";
  147. val["denominator"] = _time[pos].denominator;
  148. val["numerator"] = _time[pos].numerator;
  149. DEVLOG_DEBUG("type==1");
  150. array.append(val);
  151. } else if (type == 0) {
  152. QJsonObject val;
  153. val["pos"] = pos;
  154. val["type"] = "tempo";
  155. val["tempo"] = _tempo[pos];
  156. DEVLOG_DEBUG("type==0");
  157. array.append(val);
  158. }
  159. else {
  160. DEVLOG_DEBUG("type is invalid");
  161. }
  162. }
  163. }
  164. void TempoMap::fromJson(QJsonArray &array) {
  165. _index.clear();
  166. _time.clear();
  167. _tempo.clear();
  168. for (int i = 0; i < array.size(); i++) {
  169. QJsonObject val = array[i].toObject();
  170. if (val["type"].toString() == "timeSig") {
  171. int pos = val["pos"].toInt();
  172. int denominator = val["denominator"].toInt();
  173. int numerator = val["numerator"].toInt();
  174. this->addTimeSignature(pos, numerator, denominator);
  175. } else if (val["type"].toString() == "tempo") {
  176. int pos = val["pos"].toInt();
  177. int tempo = val["tempo"].toInt();
  178. this->addTempo(pos, tempo);
  179. }
  180. }
  181. }
  182. void TempoMap::undo() {
  183. _index = _origIndex;
  184. _tempo = _origTempo;
  185. _time = _origTime;
  186. }
  187. bool TempoMap::getBar(int pulses, float &time, int &bar, int end) {
  188. time = 0;
  189. for (int i = 0; i < 128; i++) {
  190. fraction ts = getTimeSignatureForBar(i);
  191. float bpm = getBPMforBar(i);
  192. int barLength = ts.numerator * 480 * 4 / ts.denominator;
  193. if (pulses >= barLength) {
  194. pulses -= barLength;
  195. time += ts.numerator * 60 / bpm;
  196. } else {
  197. pulses += end;
  198. time += pulses * 60 / bpm / 480;
  199. bar = i;
  200. return true;
  201. }
  202. }
  203. return false;
  204. }
  205. float TempoMap::getBPMforBar(int pos) {
  206. bool found = _tempo.keys().contains(pos);
  207. if(found) return _tempo[pos];
  208. while (pos>0) {
  209. pos--;
  210. found = _tempo.keys().contains(pos);
  211. if(found) return _tempo[pos];
  212. }
  213. return 120.0;
  214. }
  215. QString TempoMap::getLabel(int bar, tmlabel mode) {
  216. if (mode == TM_BPM) {
  217. if (_tempo.keys().contains(bar) && _tempo[bar] > 0)
  218. return STR(_tempo[bar]) + " BPM";
  219. }
  220. if (mode == TM_SIG) {
  221. if (_time.keys().contains(bar) && _time[bar].denominator > 0)
  222. return STR(_time[bar].numerator) + "/" + STR(_time[bar].denominator);
  223. }
  224. return "";
  225. }
  226. bool TempoMap::setLabel(tmlabel mode, int bar, QString label) {
  227. if (mode == TM_BPM) {
  228. if (label.length() == 0) {
  229. this->removeTempoForBar(bar);
  230. return true;
  231. } else {
  232. float tempo = QVariant(label).toFloat();
  233. if (tempo > 0) {
  234. this->removeTempoForBar(bar);
  235. this->addTempo(bar, tempo);
  236. return true;
  237. }
  238. }
  239. }
  240. if (mode == TM_SIG) {
  241. if (label.length() == 0) {
  242. this->removeTimeSignatureForBar(bar);
  243. return true;
  244. } else {
  245. QStringList tmp = label.split("/");
  246. if (tmp.length() == 2) {
  247. fraction time;
  248. time.numerator = QVariant(tmp[0]).toInt();
  249. time.denominator = QVariant(tmp[1]).toInt();
  250. if (time.denominator > 0 && time.numerator > 0) {
  251. this->removeTimeSignatureForBar(bar);
  252. this->addTimeSignature(bar,time.numerator,time.denominator);
  253. return true;
  254. }
  255. }
  256. }
  257. }
  258. return false;
  259. }