initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / indexthread.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program 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 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "clip.h"
25 #include "condition.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "filexml.h"
29 #include "indexfile.h"
30 #include "indexstate.h"
31 #include "indexthread.h"
32 #include "language.h"
33 #include "maxchannels.h"
34 #include "mwindow.h"
35 #include "mwindowgui.h"
36 #include "preferences.h"
37 #include "mainsession.h"
38 #include "samples.h"
39 #include <unistd.h>
40 #include "trackcanvas.h"
41 #include "tracks.h"
42
43 // Read data from buffers and calculate peaks
44
45 IndexThread::IndexThread(MWindow *mwindow, 
46         IndexFile *index_file,
47         char *index_filename,
48         int64_t buffer_size, 
49         int64_t length_source)
50  : Thread(1, 0, 0)
51 {
52         this->buffer_size = buffer_size;
53         this->length_source = length_source;
54         this->mwindow = mwindow;
55         this->index_filename = index_filename;
56         this->index_file = index_file;
57         IndexState *index_state = index_file->get_state();
58
59 // initialize output data
60 // size of output file in floats
61         int64_t index_size = mwindow->preferences->index_size / 
62                 sizeof(float) + 1;
63
64         delete [] index_state->index_buffer;
65         delete [] index_state->index_offsets;
66         delete [] index_state->index_sizes;
67
68         index_state->channels = index_file->source_channels;
69 // buffer used for drawing during the build.  This is not deleted in the index_state
70         index_state->index_buffer = new float[index_size];  
71 // This is deleted in the index_state's destructor
72         index_state->index_offsets = new int64_t[index_state->channels];
73         index_state->index_sizes = new int64_t[index_state->channels];
74         bzero(index_state->index_buffer, index_size * sizeof(float));
75
76 // initialization is completed in run
77         for(int i = 0; i < TOTAL_INDEX_BUFFERS; i++)
78         {
79 // Must allocate MAX_CHANNELS for a nested EDL
80                 int min_channels = MAX(MAX_CHANNELS, index_file->source_channels);
81                 buffer_in[i] = new Samples*[min_channels];
82                 bzero(buffer_in[i], sizeof(Samples*) * min_channels);
83
84                 output_lock[i] = new Condition(0, "IndexThread::output_lock");
85                 input_lock[i] = new Condition(1, "IndexThread::input_lock");
86
87
88                 for(int j = 0; j < index_file->source_channels; j++)
89                 {
90                         buffer_in[i][j] = new Samples(buffer_size);
91                 }
92         }
93
94 //printf("IndexThread::IndexThread %d\n", __LINE__);
95 //index_state->dump();
96
97         interrupt_flag = 0;
98 }
99
100 IndexThread::~IndexThread()
101 {
102         IndexState *index_state = index_file->get_state();
103
104         for(int i = 0; i < TOTAL_INDEX_BUFFERS; i++)
105         {
106                 for(int j = 0; j < index_file->source_channels; j++)
107                 {
108                         delete buffer_in[i][j];
109                 }
110                 delete [] buffer_in[i];
111                 delete output_lock[i];
112                 delete input_lock[i];
113         }
114         
115         delete [] index_state->index_buffer;
116         index_state->index_buffer = 0;
117 }
118
119 int IndexThread::start_build()
120 {
121         interrupt_flag = 0;
122         current_buffer = 0;
123         for(int i = 0; i <  TOTAL_INDEX_BUFFERS; i++) last_buffer[i] = 0;
124         start();
125         return 0;
126 }
127
128 int IndexThread::stop_build()
129 {
130         join();
131         return 0;
132 }
133
134 void IndexThread::run()
135 {
136         int done = 0;
137
138 // current high samples in index
139         int64_t *highpoint;            
140 // current low samples in the index
141         int64_t *lowpoint;             
142 // position in current indexframe
143         int64_t *frame_position;
144         int first_point = 1;
145         IndexState *index_state = index_file->get_state();
146
147         highpoint = new int64_t[index_file->source_channels];
148         lowpoint = new int64_t[index_file->source_channels];
149         frame_position = new int64_t[index_file->source_channels];
150
151 // predict first highpoint for each channel plus padding and initialize it
152         for(int64_t channel = 0; channel < index_file->source_channels; channel++)
153         {
154                 highpoint[channel] = 
155                         index_state->index_offsets[channel] = 
156                         (length_source / index_state->index_zoom * 2 + 1) * channel;
157                 lowpoint[channel] = highpoint[channel] + 1;
158
159                 index_state->index_sizes[channel] = 0;
160                 frame_position[channel] = 0;
161         }
162
163         //int64_t index_start = 0;    // end of index during last edit update
164         index_state->index_end = 0;      // samples in source completed
165         index_state->old_index_end = 0;
166         index_state->index_status = INDEX_BUILDING;
167         int64_t zoomx = index_state->index_zoom;
168         float *index_buffer = index_state->index_buffer;    // output of index build
169         int64_t *index_sizes = index_state->index_sizes;
170         int64_t *index_offsets = index_state->index_offsets;
171 //printf("IndexThread::run %d\n", __LINE__);
172 //index_state->dump();
173 //printf("IndexThread::run %d\n", __LINE__);
174
175         while(!interrupt_flag && !done)
176         {
177                 output_lock[current_buffer]->lock("IndexThread::run");
178
179                 if(last_buffer[current_buffer]) done = 1;
180                 if(!interrupt_flag && !done)
181                 {
182 // process buffer
183                         int64_t fragment_size = input_len[current_buffer];
184
185 // printf("IndexThread::run %d index_state->channels=%d index_file->source_channels=%d index_state->index_buffer=%p buffer_in=%p\n", 
186 // __LINE__,
187 // index_state->channels,
188 // index_file->source_channels,
189 // index_state->index_buffer,
190 // buffer_in);
191                         for(int channel = 0; channel < index_file->source_channels; channel++)
192                         {
193 SET_TRACE
194                                 int64_t *highpoint_channel = &highpoint[channel];
195                                 int64_t *lowpoint_channel = &lowpoint[channel];
196                                 int64_t *frame_position_channel = &frame_position[channel];
197                                 double *buffer_source = buffer_in[current_buffer][channel]->get_data();
198
199 SET_TRACE
200                                 for(int64_t i = 0; i < fragment_size; i++)
201                                 {
202                                         if(*frame_position_channel == zoomx)
203                                         {
204                                                 *highpoint_channel += 2;
205                                                 *lowpoint_channel += 2;
206                                                 *frame_position_channel = 0;
207 // store and reset output values
208                                                 index_buffer[*highpoint_channel] = 
209                                                         index_buffer[*lowpoint_channel] = 
210                                                         buffer_source[i];
211                                                 index_sizes[channel] = 
212                                                         *lowpoint_channel - 
213                                                         index_offsets[channel] + 
214                                                         1;
215                                         }
216                                         else
217                                         {
218 // get high and low points
219                                                 if(first_point)
220                                                 {
221                                                         index_buffer[*highpoint_channel] = 
222                                                                 index_buffer[*lowpoint_channel] = buffer_source[i];
223                                                         first_point = 0;
224                                                 }
225                                                 else
226                                                 {
227                                                         if(buffer_source[i] > index_buffer[*highpoint_channel]) 
228                                                                 index_buffer[*highpoint_channel] = buffer_source[i];
229                                                         else 
230                                                         if(buffer_source[i] < index_buffer[*lowpoint_channel]) 
231                                                                 index_buffer[*lowpoint_channel] = buffer_source[i];
232                                                 }
233                                         }
234                                         (*frame_position_channel)++;
235                                 } // end index one buffer
236 SET_TRACE
237                         }
238
239                         index_state->index_end += fragment_size;
240
241 // draw simultaneously with build
242                         index_file->redraw_edits(0);
243                         //index_start = index_state->index_end;
244                 }
245
246                 input_lock[current_buffer]->unlock();
247                 current_buffer++;
248                 if(current_buffer >= TOTAL_INDEX_BUFFERS) current_buffer = 0;
249         }
250
251         index_file->redraw_edits(1);
252
253 // write the index file to disk
254         index_state->write_index(index_filename, 
255                 (lowpoint[index_file->source_channels - 1] + 1) * sizeof(float),
256                 index_file->indexable->is_asset ? (Asset*)index_file->indexable : 0,
257                 index_file->source_length);
258
259
260         delete [] highpoint;
261         delete [] lowpoint;
262         delete [] frame_position;
263 }
264
265
266