Fixing configure for FreeBSD and Gentoo, some compilation probs with
[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         start_timestamp=0;
210         current_timestamp=0;
211         max_timestamp=0;
212 }
213
214 void tX_sequencer :: delete_all_events_for_sp(tX_seqpar *sp)
215 {
216         list <tX_event *> :: iterator song_event;
217         list <tX_event *> :: iterator temp_song_event;
218         
219 #ifdef SEQ_DEBUG
220         int ctr=0;
221 #endif          
222         
223         for (song_event=song_list.begin(); song_event!=song_list.end();)
224         {
225                 if (sp == (*song_event)->get_sp())
226                 {
227                         temp_song_event=song_event;
228                         song_event++;
229                         delete (*temp_song_event);
230                         song_list.erase(temp_song_event);
231 #ifdef SEQ_DEBUG
232                         ctr++;
233 #endif                  
234                 }
235                 else
236                 {
237                         song_event++;
238                 }
239         }
240 #ifdef SEQ_DEBUG
241         printf ("removed %i events for seqpar %08x.\n", ctr, sp);
242 #endif                          
243 }
244
245 void tX_sequencer :: save(FILE *rc, gzFile rz, char *indent) {
246         guint32 event_count;
247         list <tX_event *> :: iterator song_event;
248         
249         event_count=song_list.size();
250
251         tX_store("%s<sequencer>\n", indent);
252         strcat(indent, "\t");
253         
254         for (song_event=song_list.begin(); song_event!=song_list.end(); song_event++) {
255                 (*song_event)->store(rc, rz, indent);
256         }
257         
258         indent[strlen(indent)-1]=0;
259         tX_store("%s</sequencer>\n", indent);
260 }
261
262 guint32 tX_sequencer :: set_start_timestamp(float pos)
263 {
264         guint32 timestamp;
265         
266         if (pos>99.999) pos=99.999;
267         
268         pos/=100;
269         
270         timestamp = (guint32) (((float) max_timestamp) * pos);
271         
272         start_timestamp=timestamp;
273         
274         return start_timestamp;
275 }
276
277 void tX_sequencer :: forward_to_start_timestamp(int dont_fake)
278 {
279         int gui_update_max, gui_update;
280         int run_save=run;
281         
282         run=1;
283         
284         gui_update_max=(globals.update_idle * (globals.update_delay+1) * 1000) >> 1;
285         gui_update=gui_update_max;
286         
287         current_timestamp=0;
288         
289         next_event=song_list.begin();
290         
291         while (current_timestamp<start_timestamp)
292         {
293                 step();
294                 if (dont_fake)
295                 {
296                         vtt_class :: forward_all_turntables();
297                         
298                         gui_update--;           
299                         if (gui_update < 0)
300                         {
301                                 gui_update=gui_update_max;
302                                 seq_update();
303                                 while (gtk_events_pending()) gtk_main_iteration();
304                         }
305                 }
306         }
307         
308         run=run_save;
309         
310         tX_seqpar :: update_all_graphics();     
311         while (gtk_events_pending()) gtk_main_iteration();
312 }
313
314 void tX_sequencer :: load(xmlDocPtr doc, xmlNodePtr node) {
315         tX_event *ev=NULL;
316         
317         max_timestamp=0;
318         
319         for (xmlNodePtr cur=node->xmlChildrenNode; cur!=NULL; cur=cur->next) {
320                 if (cur->type == XML_ELEMENT_NODE) {
321                         if (xmlStrcmp(cur->name, (xmlChar *) "event")==0) {
322                                 ev=new tX_event(doc, cur);
323                                 max_timestamp=ev->get_timestamp();
324                                 song_list.push_back(ev);
325                         } else {
326                                 tX_warning("unhandled sequencer element %s.", cur->name);
327                         }
328                 }
329         }
330         
331         start_timestamp=0;
332         current_timestamp=0;
333 }