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