fix messed up cut/paste in thirdparty/Makefile / last checkin
[goodguy/history.git] / cinelerra-5.1 / plugins / cdripper / cdripper.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "errorbox.h"
23 #include "bcdisplayinfo.h"
24 #include "cdripper.h"
25 #include "cdripwindow.h"
26 #include "bchash.h"
27 #include "language.h"
28 #include "mainprogress.h"
29 #include "mwindow.inc"
30 #include "samples.h"
31
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37
38 PluginClient* new_plugin(PluginServer *server)
39 {
40         return new CDRipMain(server);
41 }
42
43
44 CDRipMain::CDRipMain(PluginServer *server)
45  : PluginAClient(server)
46 {
47 }
48
49 CDRipMain::~CDRipMain()
50 {
51 }
52
53 const char* CDRipMain::plugin_title() { return _("CD Ripper"); }
54 int CDRipMain::is_realtime() { return 0; }
55 int CDRipMain::is_multichannel() { return 1; }
56
57
58 int CDRipMain::load_defaults()
59 {
60 // set the default directory
61         char directory[1024];
62         sprintf(directory, "%scdripper.rc", BCASTDIR);
63
64 // load the defaults
65         defaults = new BC_Hash(directory);
66         defaults->load();
67
68         track1 = defaults->get("TRACK1", 1);
69         min1 = defaults->get("MIN1", 0);
70         sec1 = defaults->get("SEC1", 0);
71         track2 = defaults->get("TRACK2", 2);
72         min2 = defaults->get("MIN2", 0);
73         sec2 = defaults->get("SEC2", 0);
74         sprintf(device, "/dev/cdrom");
75         defaults->get("DEVICE", device);
76         startlba = defaults->get("STARTLBA", 0);
77         endlba = defaults->get("ENDLBA", 0);
78         return 0;
79 }
80
81 int CDRipMain::save_defaults()
82 {
83         defaults->update("TRACK1", track1);
84         defaults->update("MIN1", min1);
85         defaults->update("SEC1", sec1);
86         defaults->update("TRACK2", track2);
87         defaults->update("MIN2", min2);
88         defaults->update("SEC2", sec2);
89         defaults->update("DEVICE", device);
90         defaults->update("STARTLBA", startlba);
91         defaults->update("ENDLBA", endlba);
92         defaults->save();
93         return 0;
94 }
95
96 int CDRipMain::get_parameters()
97 {
98         int result, result2;
99
100         result = 0;
101         result2 = 1;
102
103         while(result2 && !result)
104         {
105                 {
106                         BC_DisplayInfo info;
107 //printf("CDRipMain::get_parameters 1\n");
108                         CDRipWindow window(this, info.get_abs_cursor_x(), info.get_abs_cursor_y());
109 //printf("CDRipMain::get_parameters 2\n");
110                         window.create_objects();
111 //printf("CDRipMain::get_parameters 3\n");
112                         result = window.run_window();
113 //printf("CDRipMain::get_parameters 4\n");
114                 }
115                 if(!result) result2 = get_toc();
116 //printf("CDRipMain::get_parameters 5 %d\n", result);
117         }
118         PluginAClient::sample_rate = 44100;
119         return result;
120 }
121
122 int CDRipMain::open_drive()
123 {
124         if((cdrom = open(device, O_RDONLY)) < 0)
125         {
126                 BC_DisplayInfo info;
127                 ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
128                         info.get_abs_cursor_x(), 
129                         info.get_abs_cursor_y());
130                 window.create_objects(_("Can't open cdrom drive."));
131                 window.run_window();
132                 return 1;
133         }
134
135         ioctl(cdrom, CDROMSTART);         // start motor
136         return 0;
137 }
138
139 int CDRipMain::close_drive()
140 {
141         ioctl(cdrom, CDROMSTOP);
142         close(cdrom);
143         return 0;
144 }
145
146 int CDRipMain::get_toc()
147 {
148 // test CD
149         int result = 0, i, tracks;
150         struct cdrom_tochdr hdr;
151         struct cdrom_tocentry entry[100];
152         BC_DisplayInfo info;
153         
154         result = open_drive();
155         
156         if(ioctl(cdrom, CDROMREADTOCHDR, &hdr) < 0)
157         {
158                 close(cdrom);
159                 ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
160                         info.get_abs_cursor_x(), 
161                         info.get_abs_cursor_y());
162                 window.create_objects(_("Can't get total from table of contents."));
163                 window.run_window();
164                 result = 1;
165         }
166
167         for(i = 0; i < hdr.cdth_trk1; i++)
168         {
169                 entry[i].cdte_track = 1 + i;
170                 entry[i].cdte_format = CDROM_LBA;
171                 if(ioctl(cdrom, CDROMREADTOCENTRY, &entry[i]) < 0)
172                 {
173                         ioctl(cdrom, CDROMSTOP);
174                         close(cdrom);
175                         ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
176                                 info.get_abs_cursor_x(), 
177                                 info.get_abs_cursor_y());
178                         window.create_objects(_("Can't get table of contents entry."));
179                         window.run_window();
180                         result = 1;
181                         break;
182                 }
183         }
184
185         entry[i].cdte_track = CDROM_LEADOUT;
186         entry[i].cdte_format = CDROM_LBA;
187         if(ioctl(cdrom, CDROMREADTOCENTRY, &entry[i]) < 0)
188         {
189                 ioctl(cdrom, CDROMSTOP);
190                 close(cdrom);
191                 ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
192                         info.get_abs_cursor_x(), 
193                         info.get_abs_cursor_y());
194                 window.create_objects(_("Can't get table of contents leadout."));
195                 window.run_window();
196                 result = 1;
197         }
198                         
199                         
200         tracks = hdr.cdth_trk1+1;
201
202         if(track1 <= 0 || track1 > tracks)
203         {
204                 ioctl(cdrom, CDROMSTOP);
205                 close(cdrom);
206                 ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
207                         info.get_abs_cursor_x(), 
208                         info.get_abs_cursor_y());
209                 window.create_objects(_("Start track is out of range."));
210                 window.run_window();
211                 result = 1;
212         }
213
214 // Clamp to highest track
215         if(track2 > tracks)
216         {
217                 track2 = tracks;
218         }
219         
220         if(track2 < track1 || track2 <= 0)
221         {
222                 ioctl(cdrom, CDROMSTOP);
223                 close(cdrom);
224                 ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
225                         info.get_abs_cursor_x(), 
226                         info.get_abs_cursor_y());
227                 window.create_objects(_("End track is out of range."));
228                 window.run_window();
229                 result = 1;
230         }
231         
232         if(track1 == track2 && min2 == 0 && sec2 == 0)
233         {
234                 ioctl(cdrom, CDROMSTOP);
235                 close(cdrom);
236                 ErrorBox window(_(PROGRAM_NAME ": CD Ripper"),
237                         info.get_abs_cursor_x(), 
238                         info.get_abs_cursor_y());
239                 window.create_objects(_("End position is out of range."));
240                 window.run_window();
241                 result = 1;
242         }
243
244         startlba = endlba = 0;
245         if(!result)
246         {
247                 startlba = entry[track1 - 1].cdte_addr.lba;
248                 startlba += (min1 * 44100 * 4 * 60 + sec1 * 44100 * 4) / FRAMESIZE;
249
250                 endlba = entry[track2 - 1].cdte_addr.lba;
251                 if(track2 < tracks)
252                 {
253                         endlba += (min2 * 44100 * 4 * 60 + sec2 * 44100 * 4) / FRAMESIZE;
254                 }
255         }
256
257 //printf("CDRipMain::get_toc %jd %jd\n", startlba, endlba);
258         close_drive();
259         return result;
260 }
261
262 int CDRipMain::start_loop()
263 {
264 // get CD parameters
265         int result = 0;
266
267 //printf("CDRipMain::start_loop 1\n");
268         result = get_toc();
269         FRAME = 4;    // 2 bytes 2 channels
270         previewing = 3;     // defeat bug in hardware
271         fragment_length = PluginClient::in_buffer_size * FRAME;
272         fragment_length /= NFRAMES * FRAMESIZE;
273         fragment_length *= NFRAMES * FRAMESIZE;
274         total_length = (endlba - startlba) * FRAMESIZE / fragment_length + previewing + 1;
275         result = open_drive();
276 //printf("CDRipMain::start_loop 1 %d\n", interactive);
277
278 // thread out progress
279         if(interactive)
280         {
281                 char string[BCTEXTLEN];
282                 sprintf(string, "%s...", plugin_title());
283                 progress = start_progress(string, total_length);
284         }
285 //printf("CDRipMain::start_loop 1\n");
286
287 // get still more CD parameters
288         endofselection = 0;
289         currentlength = 0;
290         startlba_fragment = startlba - fragment_length * previewing / FRAMESIZE;
291         buffer = new char[fragment_length];
292         arg.addr.lba = startlba_fragment;
293         arg.addr_format = CDROM_LBA;
294         arg.nframes = NFRAMES;
295 //printf("CDRipMain::start_loop 2\n");
296
297         return result;
298 }
299
300
301 int CDRipMain::stop_loop()
302 {
303         if(interactive)
304         {
305                 progress->stop_progress();
306                 delete progress;
307         }
308
309         delete buffer;
310         close_drive();
311         return 0;
312 }
313
314 int CDRipMain::process_loop(Samples **plugin_buffer, int64_t &write_length)
315 {
316         int result = 0;
317 //printf("CDRipMain::process_loop 1\n");
318
319 // render it
320         if(arg.addr.lba < endlba && !endofselection)
321         {
322                 if(arg.addr.lba + fragment_length / FRAMESIZE > endlba)
323                 {
324                         fragment_length = (endlba - arg.addr.lba) / NFRAMES;
325                         fragment_length *= NFRAMES * FRAMESIZE;
326                         endofselection = 1;
327                 }
328 //printf("CDRipMain::process_loop 2 %d %jd\n", arg.addr.lba, endlba);
329
330                 for(i = 0; i < fragment_length; 
331                         i += NFRAMES * FRAMESIZE,
332                         arg.addr.lba += NFRAMES)
333                 {
334                         arg.buf = (unsigned char*)&buffer[i];
335                         for(attempts = 0; attempts < 3; attempts++)
336                         {
337                                 if(!(ioctl(cdrom, CDROMREADAUDIO, &arg)))
338                                 {
339                                         attempts = 3;
340                                 }
341                                 else
342                                 if(attempts == 2 && !previewing) printf("Can't read CD audio.\n");
343                         }
344                 }
345 //printf("CDRipMain::process_loop 3\n");
346
347                 if(arg.addr.lba > startlba)
348                 {
349 // convert to doubles
350                         fragment_samples = fragment_length / FRAME;
351                         for(j = 0; j < 2 && j < PluginClient::total_in_buffers; j++)
352                         {
353                                 buffer_channel = (int16_t*)buffer + j;
354                                 output_buffer = plugin_buffer[j]->get_data();
355                                 for(k = 0, l = 0; l < fragment_samples; k += 2, l++)
356                                 {
357                                         output_buffer[l] = buffer_channel[k];
358                                         output_buffer[l] /= 0x7fff;
359                                 }
360                         }
361
362                         write_length = fragment_samples;
363                 }
364 //printf("CDRipMain::process_loop 5 %d\n", interactive);
365
366                 currentlength++;
367                 if(interactive)
368                 {
369                         if(!result) result = progress->update(currentlength);
370                 }
371 //printf("CDRipMain::process_loop 6\n");
372         }
373         else
374         {
375 //printf("CDRipMain::process_loop 7\n");
376                 endofselection = 1;
377                 write_length = 0;
378         }
379
380 //printf("CDRipMain::process_loop 8 %d %d\n", endofselection, result);
381         return endofselection || result;
382 }