93fcbf0fcda989783577779e166cf0c68d378b17
[terminatorX.git] / src / tX_sequencer.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2003  Alexander K├Ânig
4  
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9  
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  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_sequencer.cc
20  
21     Description: Well, implements the sequencer as you might have
22                  guessed.
23 */ 
24
25 #include "tX_sequencer.h"
26 #include "tX_mastergui.h"
27 #include "tX_global.h"
28
29 tX_sequencer sequencer;
30
31 tX_sequencer :: tX_sequencer()
32 {
33         current_timestamp=0;
34         start_timestamp=0;
35         max_timestamp=0;
36         next_event=song_list.begin();
37         mode=TX_SEQMODE_PLAYONLY;
38         run=0;
39         pthread_mutex_init(&record_lock, NULL);
40 }
41
42 tX_sequencer :: ~tX_sequencer()
43 {
44 }
45
46 void tX_sequencer :: set_timestamp(guint32 timestamp)
47 {
48         current_timestamp=0;
49         start_timestamp=0;
50         next_event=song_list.begin();
51 }
52
53 void tX_sequencer :: step()
54 {
55         if (!run) return;
56                 
57         while ((next_event != song_list.end()) && ((*next_event)->get_timestamp()==current_timestamp))
58         {
59                 (*next_event)->playback();
60                 next_event++;
61         }
62
63         current_timestamp++;    
64 }
65
66 tX_event *tX_sequencer :: record_event (tX_seqpar *sp, float value)
67 {
68         tX_event *new_event;
69         
70         new_event=new tX_event(current_timestamp, value, sp);
71         
72         pthread_mutex_lock(&record_lock);
73         record_list.push_back(new_event);
74         pthread_mutex_unlock(&record_lock);
75         
76         return new_event;
77 }
78
79 int tX_sequencer :: trig_rec()
80 {
81         //set_timestamp(0);
82         record_start_timestamp=start_timestamp;
83
84         mode = TX_SEQMODE_PLAYREC;
85         return 1;
86 }
87
88 int tX_sequencer :: trig_play()
89 {
90 //      set_timestamp(0);
91         run=1;
92         return 1;
93 }
94
95
96 //#define SEQ_DEBUG 1
97 //#define SEQ_DEBUG_MAX 1
98
99 void tX_sequencer :: trig_stop()
100 {
101         list <tX_event *> :: iterator song_event;
102         list <tX_event *> :: iterator temp_song_event;
103         list <tX_event *> :: iterator record_event;
104         tX_seqpar *sp;
105
106         int oldmode=mode;
107
108         mode = TX_SEQMODE_PLAYONLY;
109         run=0;
110
111         record_stop_timestamp=current_timestamp;
112         
113         if (oldmode==TX_SEQMODE_PLAYREC)
114         {
115                 pthread_mutex_lock(&record_lock);
116 #ifdef SEQ_DEBUG                
117                 printf ("Recorded from %i to %i.\n", record_start_timestamp, record_stop_timestamp);
118                 printf ("* Song: %i events, Recorded: %i events, sum=%i\n", song_list.size(), record_list.size(), song_list.size() + record_list.size());
119 #endif          
120                 /* removing all events for touched parameters in song_list */
121                 
122                 song_event=song_list.begin();
123
124                 while ((song_event!=song_list.end()) && ((*song_event)->get_timestamp() < record_start_timestamp))
125                         song_event++;
126
127                 while ((song_event!=song_list.end()) && ((*song_event)->get_timestamp() <= record_stop_timestamp))
128                 {
129                         sp = (*song_event)->get_sp();
130 #ifdef SEQ_DEBUG_MAX                    
131                         printf("sp %08x (%i) touched at: %i - timestamp %i.\n", sp, sp->is_touched(), sp->get_touch_timestamp(), (*song_event)->get_timestamp());
132 #endif                  
133                         
134                         if (sp->is_touched() && (sp->get_touch_timestamp()<= (*song_event)->get_timestamp()))
135                         {
136                                 temp_song_event=song_event;
137                                 song_event++;
138                                 delete (*temp_song_event);
139                                 song_list.erase(temp_song_event);
140                         }
141                         else
142                         {
143                                 song_event++;
144                         }
145                 }
146
147                 /* inserting all recorded events into song_list */
148                                         
149                 for (record_event=record_list.begin(), song_event=song_list.begin(); record_event != record_list.end();)
150                 {
151                         if (song_event==song_list.end())
152                         {
153                                 song_list.insert(song_event, record_event, record_list.end());
154                                 break;
155                         }
156                         
157                         if ((*song_event)->get_timestamp() >= (*record_event)->get_timestamp())
158                         {
159 /*                              if (song_event==song_list.begin()) song_list.push_front((*record_event));
160                                 else */
161                                 song_list.insert(song_event, (*record_event));                          
162                                 record_event++;
163                         }
164                         else 
165                         {
166                                 song_event++;
167                         }
168                 }
169 //              swap(song_list, record_list);
170                 record_list.erase(record_list.begin(), record_list.end());      
171
172 #ifdef SEQ_DEBUG                
173                 printf ("- Song: %i events, Recorded: %i events, sum=%i\n", song_list.size(), record_list.size(), song_list.size() + record_list.size());
174 #endif          
175                 
176                 pthread_mutex_unlock(&record_lock);
177         }
178
179         tX_seqpar::untouch_all();
180         
181         song_event=song_list.end();
182         
183         if (song_event!=song_list.begin()) 
184         {
185                 song_event--;
186                 max_timestamp=(*song_event)->get_timestamp();
187         }
188         
189 #ifdef SEQ_DEBUG_MAX
190         /*dump song_list */
191         
192         for (song_event=song_list.begin(); song_event!=song_list.end(); song_event++)
193         {
194                 printf ("%-15s| %-27s| %8i | %10f\n", (*song_event)->get_vtt_name(), (*song_event)->get_seqpar_name(), (*song_event)->get_timestamp(), (*song_event)->get_value());
195         }
196 #endif  
197
198         current_timestamp=start_timestamp;
199         seq_update();
200 }
201
202 void tX_sequencer :: delete_all_events() {
203         while (song_list.size()) {
204                 list <tX_event *> :: iterator ev=song_list.begin();
205                 delete (*ev);
206                 song_list.erase(ev);
207         }
208 }
209
210 void tX_sequencer :: delete_all_events_for_sp(tX_seqpar *sp)
211 {
212         list <tX_event *> :: iterator song_event;
213         list <tX_event *> :: iterator temp_song_event;
214         
215 #ifdef SEQ_DEBUG
216         int ctr=0;
217 #endif          
218         
219         for (song_event=song_list.begin(); song_event!=song_list.end();)
220         {
221                 if (sp == (*song_event)->get_sp())
222                 {
223                         temp_song_event=song_event;
224                         song_event++;
225                         delete (*temp_song_event);
226                         song_list.erase(temp_song_event);
227 #ifdef SEQ_DEBUG
228                         ctr++;
229 #endif                  
230                 }
231                 else
232                 {
233                         song_event++;
234                 }
235         }
236 #ifdef SEQ_DEBUG
237         printf ("removed %i events for seqpar %08x.\n", ctr, sp);
238 #endif                          
239 }
240
241 void tX_sequencer :: save(FILE *rc, char *indent) {
242         guint32 event_count;
243         list <tX_event *> :: iterator song_event;
244         
245         event_count=song_list.size();
246
247         fprintf(rc, "%s<sequencer>\n", indent);
248         strcat(indent, "\t");
249         
250         for (song_event=song_list.begin(); song_event!=song_list.end(); song_event++) {
251                 (*song_event)->store(rc, indent);
252         }
253         
254         indent[strlen(indent)-1]=0;
255         fprintf(rc, "%s</sequencer>\n", indent);
256 }
257
258
259 void tX_sequencer :: clear()
260 {
261         if (song_list.size()==0) return;
262         
263         song_list.erase(song_list.begin(), song_list.end());
264         
265         current_timestamp=0;
266         max_timestamp=0;
267         start_timestamp=0;
268 }
269
270
271 guint32 tX_sequencer :: set_start_timestamp(float pos)
272 {
273         guint32 timestamp;
274         
275         if (pos>99.999) pos=99.999;
276         
277         pos/=100;
278         
279         timestamp = (guint32) (((float) max_timestamp) * pos);
280         
281         start_timestamp=timestamp;
282         
283         return start_timestamp;
284 }
285
286 void tX_sequencer :: forward_to_start_timestamp(int dont_fake)
287 {
288         int gui_update_max, gui_update;
289         int run_save=run;
290         
291         run=1;
292         
293         gui_update_max=(globals.update_idle * (globals.update_delay+1) * 1000) >> 1;
294         gui_update=gui_update_max;
295         
296         current_timestamp=0;
297         
298         next_event=song_list.begin();
299         
300         while (current_timestamp<start_timestamp)
301         {
302                 step();
303                 if (dont_fake)
304                 {
305                         vtt_class :: forward_all_turntables();
306                         
307                         gui_update--;           
308                         if (gui_update < 0)
309                         {
310                                 gui_update=gui_update_max;
311                                 seq_update();
312                                 while (gtk_events_pending()) gtk_main_iteration();
313                         }
314                 }
315         }
316         
317         run=run_save;
318         
319         tX_seqpar :: update_all_graphics();     
320         while (gtk_events_pending()) gtk_main_iteration();
321 }
322
323 void tX_sequencer :: load(xmlDocPtr doc, xmlNodePtr node) {
324         tX_event *ev=NULL;
325         
326         max_timestamp=0;
327         
328         for (xmlNodePtr cur=node->xmlChildrenNode; cur!=NULL; cur=cur->next) {
329                 if (cur->type == XML_ELEMENT_NODE) {
330                         if (xmlStrcmp(cur->name, (xmlChar *) "event")==0) {
331                                 ev=new tX_event(doc, cur);
332                                 song_list.push_back(ev);
333                         } else {
334                                 tX_warning("unhandled sequencer element %s.", cur->name);
335                         }
336                 }
337         }
338         
339         start_timestamp=0;
340         current_timestamp=0;
341 }