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