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