1 /*
2 * @(#)Track.cpp 3.00 8 July 2000
3 *
4 * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org)
5 *
6 * This file is part of TSE3 - the Trax Sequencer Engine version 3.00.
7 *
8 * This library is modifiable/redistributable under the terms of the GNU
9 * General Public License.
10 *
11 * You should have received a copy of the GNU General Public License along
12 * with this program; see the file COPYING. If not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14 *
15 */
16
17 #include "tse3/cmd/Track.h"
18
19 #include "tse3/Track.h"
20 #include "tse3/Part.h"
21 #include "tse3/Song.h"
22 #include "tse3/MidiFilter.h"
23 #include "tse3/app/TrackSelection.h"
24
25 #include <algorithm>
26 #include <vector>
27 #include <iterator>
28
29 using namespace TSE3;
30 using namespace TSE3::Cmd;
31
32 /******************************************************************************
33 * Track_SetInfo class
34 *****************************************************************************/
35
Track_SetInfo(TSE3::Track * track,const std::string & title,const TSE3::MidiFilter & smef,const TSE3::MidiParams & mp,const TSE3::DisplayParams & dp)36 Track_SetInfo::Track_SetInfo(TSE3::Track *track,
37 const std::string &title,
38 const TSE3::MidiFilter &smef,
39 const TSE3::MidiParams &mp,
40 const TSE3::DisplayParams &dp)
41 : Command("track info"), track(track),
42 newTitle(title), smef(smef), mp(mp), dp(dp)
43 {
44 }
45
46
executeImpl()47 void Track_SetInfo::executeImpl()
48 {
49 oldTitle = track->title();
50
51 track->setTitle(newTitle);
52 std::swap(smef, *(track->filter()));
53 std::swap(mp, *(track->params()));
54 std::swap(dp, *(track->displayParams()));
55 }
56
57
undoImpl()58 void Track_SetInfo::undoImpl()
59 {
60 track->setTitle(oldTitle);
61 std::swap(smef, *(track->filter()));
62 std::swap(mp, *(track->params()));
63 std::swap(dp, *(track->displayParams()));
64 }
65
66
67 /******************************************************************************
68 * Track_Snip class
69 *****************************************************************************/
70
Track_Snip(TSE3::Track * track,TSE3::Clock snipTime)71 Track_Snip::Track_Snip(TSE3::Track *track,
72 TSE3::Clock snipTime)
73 : Command("snip part"), track(track), snipTime(snipTime), valid(false),
74 shouldDelete(false)
75 {
76 size_t pos = track->index(snipTime);
77 if (pos < track->size() && (*track)[pos]->start() < snipTime)
78 {
79 oldPart = (*track)[pos];
80 oldEndTime = oldPart->end();
81 newPart = new Part(*oldPart);
82 valid = true;
83 shouldDelete = true;
84
85 // Work out new Part's parameters
86 newPart->setStart(snipTime);
87 TSE3::Clock phraseStart = oldPart->start();
88 if (oldPart->repeat())
89 {
90 while (phraseStart+oldPart->repeat() <= snipTime)
91 {
92 phraseStart += oldPart->repeat();
93 }
94 }
95 newPart->filter()->setOffset(snipTime - phraseStart
96 + oldPart->filter()->offset());
97 if (oldPart->repeat())
98 {
99 while (newPart->filter()->offset() >= newPart->repeat())
100 {
101 newPart->filter()->setOffset(newPart->filter()->offset()
102 - newPart->repeat());
103 }
104 }
105 }
106 }
107
108
~Track_Snip()109 Track_Snip::~Track_Snip()
110 {
111 if (shouldDelete)
112 {
113 delete newPart;
114 }
115 }
116
117
executeImpl()118 void Track_Snip::executeImpl()
119 {
120 if (valid)
121 {
122 oldPart->setEnd(snipTime);
123 track->insert(newPart);
124 shouldDelete = false;
125 }
126 }
127
128
undoImpl()129 void Track_Snip::undoImpl()
130 {
131 if (valid)
132 {
133 track->remove(newPart);
134 oldPart->setEnd(oldEndTime);
135 shouldDelete = true;
136 }
137 }
138
139
140 /******************************************************************************
141 * Track_Glue class
142 *****************************************************************************/
143
valid(TSE3::Track * track,TSE3::Clock glueTime)144 bool Track_Glue::valid(TSE3::Track *track,
145 TSE3::Clock glueTime)
146 {
147 size_t pos = track->index(glueTime);
148 if (pos != 0 && pos != track->size() && (*track)[pos]->start() <= glueTime)
149 {
150 if ((*track)[pos-1]->end() == (*track)[pos]->start())
151 {
152 return true;
153 }
154 }
155 return false;
156 }
157
158
Track_Glue(TSE3::Track * track,TSE3::Clock glueTime)159 Track_Glue::Track_Glue(TSE3::Track *track,
160 TSE3::Clock glueTime)
161 : Command("glue parts"), track(track), glueTime(glueTime),
162 _valid(valid(track, glueTime)), oldPart(0)
163 {
164 if (_valid)
165 {
166 pos = track->index(glueTime);
167 oldEndTime = (*track)[pos]->start();
168 }
169 }
170
171
~Track_Glue()172 Track_Glue::~Track_Glue()
173 {
174 delete oldPart;
175 }
176
177
executeImpl()178 void Track_Glue::executeImpl()
179 {
180 if (_valid)
181 {
182 oldPart = (*track)[pos];
183 track->remove(pos);
184 (*track)[pos-1]->setEnd(oldPart->end());
185 }
186 }
187
188
undoImpl()189 void Track_Glue::undoImpl()
190 {
191 if (_valid)
192 {
193 (*track)[pos-1]->setEnd(oldEndTime);
194 track->insert(oldPart);
195 oldPart = 0;
196 }
197 }
198
199
200 /******************************************************************************
201 * Track_RemovePart class
202 *****************************************************************************/
203
Track_RemovePart(Part * p)204 Track_RemovePart::Track_RemovePart(Part *p)
205 : Command("remove part"), track(p->parent()), part(p), partno(0)
206 {
207 if (!track) part=0;
208 }
209
210
Track_RemovePart(Track * t,size_t p)211 Track_RemovePart::Track_RemovePart(Track *t, size_t p)
212 : Command("remove part"), track(t), part(NULL), partno(p)
213 {
214 }
215
216
Track_RemovePart(Track * t,Part * p)217 Track_RemovePart::Track_RemovePart(Track *t, Part *p)
218 : Command("remove part"), track(t), part(p), partno(0)
219 {
220 }
221
222
~Track_RemovePart()223 Track_RemovePart::~Track_RemovePart()
224 {
225 if (done())
226 {
227 delete part;
228 }
229 }
230
231
executeImpl()232 void Track_RemovePart::executeImpl()
233 {
234 if (!part && partno < (int)track->size())
235 {
236 part = (*track)[partno];
237 }
238 else
239 {
240 partno = track->index(part);
241 }
242 track->remove(part);
243 }
244
245
undoImpl()246 void Track_RemovePart::undoImpl()
247 {
248 if (part)
249 {
250 track->insert(part);
251 }
252 }
253
254
255
256 /******************************************************************************
257 * Track_Sort class
258 *****************************************************************************/
259
260 class TSE3::Cmd::Track_SortImpl
261 {
262 public:
263
Track_SortImpl(TSE3::Song * song,TSE3::Cmd::Track_Sort::SortBy by,TSE3::Cmd::Track_Sort::SortOrder order,TSE3::App::TrackSelection * selection)264 Track_SortImpl(TSE3::Song *song,
265 TSE3::Cmd::Track_Sort::SortBy by,
266 TSE3::Cmd::Track_Sort::SortOrder order,
267 TSE3::App::TrackSelection *selection)
268 : song(song), by(by), order(order), selection(selection)
269 {
270 for (size_t trk = 0; trk < song->size(); ++trk)
271 {
272 original_order.push_back((*song)[trk]);
273 }
274 if (selection)
275 {
276 std::copy(selection->begin(), selection->end(),
277 std::back_inserter(selected_tracks));
278 }
279
280 comparator = &Track_SortImpl::compare_name;
281 switch (by)
282 {
283 case Track_Sort::ByName:
284 {
285 comparator = &Track_SortImpl::compare_name;
286 break;
287 }
288 case Track_Sort::ByMuted:
289 {
290 comparator = &Track_SortImpl::compare_muted;
291 break;
292 }
293 case Track_Sort::BySelected:
294 {
295 comparator = &Track_SortImpl::compare_selected;
296 break;
297 }
298 case Track_Sort::ByPort:
299 {
300 comparator = &Track_SortImpl::compare_port;
301 break;
302 }
303 case Track_Sort::ByChannel:
304 {
305 comparator = &Track_SortImpl::compare_channel;
306 break;
307 }
308 case Track_Sort::BySize:
309 {
310 comparator = &Track_SortImpl::compare_size;
311 break;
312 }
313 }
314 }
315
316 void executeImpl();
317 void undoImpl();
318
319 private:
320
321 typedef bool (Track_SortImpl::*comparator_t)(size_t,size_t);
322
323 TSE3::Song *song;
324 TSE3::Cmd::Track_Sort::SortBy by;
325 TSE3::Cmd::Track_Sort::SortOrder order;
326 TSE3::App::TrackSelection *selection;
327 std::vector<TSE3::Track *> original_order;
328 std::vector<TSE3::Track *> selected_tracks;
329 comparator_t comparator;
330
331 void swap(size_t index1, size_t index2);
332 bool compare(size_t index1, size_t index2);
333
334 bool compare_name(size_t index1, size_t index2);
335 bool compare_muted(size_t index1, size_t index2);
336 bool compare_selected(size_t index1, size_t index2);
337 bool compare_port(size_t index1, size_t index2);
338 bool compare_channel(size_t index1, size_t index2);
339 bool compare_size(size_t index1, size_t index2);
340
341 void reselectTracks();
342 };
343
344
executeImpl()345 void TSE3::Cmd::Track_SortImpl::executeImpl()
346 {
347 for (size_t trk = 0; trk < song->size(); ++trk)
348 {
349 size_t bestMatch = trk;
350 for (size_t subtrk = trk+1; subtrk < song->size(); ++subtrk)
351 {
352 bool comparison = (this->*comparator)(bestMatch, subtrk);
353 comparison ^= order;
354 if (comparison)
355 {
356 bestMatch = subtrk;
357 }
358 }
359 swap(trk, bestMatch);
360 }
361 reselectTracks();
362 }
363
364
undoImpl()365 void Track_SortImpl::undoImpl()
366 {
367 while (song->size())
368 {
369 song->remove((size_t)0);
370 }
371 std::vector<TSE3::Track*>::iterator i = original_order.begin();
372 while (i != original_order.end())
373 {
374 song->insert(*i);
375 ++i;
376 }
377 reselectTracks();
378 }
379
380
reselectTracks()381 void Track_SortImpl::reselectTracks()
382 {
383 if (selection)
384 {
385 std::vector<TSE3::Track*>::iterator i = selected_tracks.begin();
386 while (i != selected_tracks.end())
387 {
388 selection->select(*i, true);
389 ++i;
390 }
391 }
392 }
393
394
swap(size_t index1,size_t index2)395 void Track_SortImpl::swap(size_t index1, size_t index2)
396 {
397 if (index1 == index2) return;
398
399 if (index2 < index1)
400 {
401 std::swap(index1, index2);
402 }
403 TSE3::Track *track1 = (*song)[index1];
404 TSE3::Track *track2 = (*song)[index2];
405 song->remove(index2);
406 song->insert(track2, index1);
407 song->remove(index1+1);
408 song->insert(track1, index2);
409 }
410
411
compare_name(size_t index1,size_t index2)412 bool Track_SortImpl::compare_name(size_t index1, size_t index2)
413 {
414 return (*song)[index1]->title().compare((*song)[index2]->title()) > 0;
415 }
416
417
compare_muted(size_t index1,size_t index2)418 bool Track_SortImpl::compare_muted(size_t index1, size_t index2)
419 {
420 return (*song)[index1]->filter()->status()
421 > (*song)[index2]->filter()->status();
422 }
423
424
compare_selected(size_t index1,size_t index2)425 bool Track_SortImpl::compare_selected(size_t index1, size_t index2)
426 {
427 bool res1 = std::find(selected_tracks.begin(), selected_tracks.end(),
428 (*song)[index1])
429 != selected_tracks.end();
430 bool res2 = std::find(selected_tracks.begin(), selected_tracks.end(),
431 (*song)[index2])
432 != selected_tracks.end();
433 return res1 < res2;
434 }
435
436
compare_port(size_t index1,size_t index2)437 bool Track_SortImpl::compare_port(size_t index1, size_t index2)
438 {
439 return (*song)[index1]->filter()->port()
440 > (*song)[index2]->filter()->port();
441 }
442
443
compare_channel(size_t index1,size_t index2)444 bool Track_SortImpl::compare_channel(size_t index1, size_t index2)
445 {
446 return (*song)[index1]->filter()->channel()
447 > (*song)[index2]->filter()->channel();
448 }
449
450
compare_size(size_t index1,size_t index2)451 bool Track_SortImpl::compare_size(size_t index1, size_t index2)
452 {
453 return (*song)[index1]->size() > (*song)[index2]->size();
454 }
455
456
Track_Sort(Song * song,SortBy by,SortOrder order,TSE3::App::TrackSelection * selection)457 Track_Sort::Track_Sort(Song *song, SortBy by, SortOrder order,
458 TSE3::App::TrackSelection *selection)
459 : Command("sort tracks"), pimpl(new Track_SortImpl(song, by, order, selection))
460 {
461 }
462
463
~Track_Sort()464 Track_Sort::~Track_Sort()
465 {
466 delete pimpl;
467 }
468
469
executeImpl()470 void Track_Sort::executeImpl()
471 {
472 pimpl->executeImpl();
473 }
474
475
undoImpl()476 void Track_Sort::undoImpl()
477 {
478 pimpl->undoImpl();
479 }
480