1 #include "cdiomodule.h"
2 #include <limits.h>
3 #include <cdio/cd_types.h>
4 #include <cdio/audio.h>
5 #include <cdio/track.h>
6 #include <cdio/types.h>
7 #include "pcm.h"
8 #include "pcmconv.h"
9 #include "mod_defs.h"
10
11 /********************************************************
12 Audio Tools, a module and set of tools for manipulating audio data
13 Copyright (C) 2007-2014 Brian Langenberger
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 *******************************************************/
29
30
31 #if PY_MAJOR_VERSION >= 3
32 #ifndef PyInt_FromLong
33 #define PyInt_FromLong PyLong_FromLong
34 #endif
35 #endif
36
37 #ifndef MIN
38 #define MIN(x, y) ((x) < (y) ? (x) : (y))
39 #endif
40 #ifndef MAX
41 #define MAX(x, y) ((x) > (y) ? (x) : (y))
42 #endif
43
MOD_INIT(cdio)44 MOD_INIT(cdio)
45 {
46 PyObject* m;
47
48 MOD_DEF(m, "cdio", "a CDDA reading module", cdioMethods)
49
50 cdio_CDDAReaderType.tp_new = PyType_GenericNew;
51 if (PyType_Ready(&cdio_CDDAReaderType) < 0)
52 return MOD_ERROR_VAL;
53
54 Py_INCREF(&cdio_CDDAReaderType);
55 PyModule_AddObject(m, "CDDAReader", (PyObject *)&cdio_CDDAReaderType);
56
57 return MOD_SUCCESS_VAL(m);
58 }
59
60 static PyObject*
CDDAReader_new(PyTypeObject * type,PyObject * args,PyObject * kwds)61 CDDAReader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
62 {
63 cdio_CDDAReader *self;
64
65 self = (cdio_CDDAReader *)type->tp_alloc(type, 0);
66
67 return (PyObject *)self;
68 }
69
70 static int
CDDAReader_init(cdio_CDDAReader * self,PyObject * args,PyObject * kwds)71 CDDAReader_init(cdio_CDDAReader *self, PyObject *args, PyObject *kwds)
72 {
73 char *device = NULL;
74 struct stat buf;
75
76 self->is_cd_image = 0;
77 self->is_logging = 0;
78 self->dealloc = NULL;
79 self->closed = 0;
80 self->audiotools_pcm = NULL;
81 cddareader_reset_log(&(self->log));
82
83 if (!PyArg_ParseTuple(args, "s|i", &device, &(self->is_logging)))
84 return -1;
85
86 if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL)
87 return -1;
88
89 /*identify whether drive is physical or a CD image*/
90 if (stat(device, &buf)) {
91 PyErr_SetFromErrno(PyExc_IOError);
92 return -1;
93 }
94 if (S_ISREG(buf.st_mode)) {
95 if (cdio_is_cuefile(device) ||
96 cdio_is_binfile(device) ||
97 cdio_is_tocfile(device) ||
98 cdio_is_nrg(device)) {
99 /*open CD image and set function pointers*/
100 self->is_cd_image = 1;
101 self->is_logging = 0;
102 return CDDAReader_init_image(self, device);
103 } else {
104 /*unsupported file*/
105 PyErr_SetString(PyExc_ValueError, "unsupported CD image type");
106 return -1;
107 }
108 } else if (S_ISBLK(buf.st_mode)) {
109 if (cdio_is_device(device, DRIVER_LINUX)) {
110 /*open CD device and set function pointers*/
111 self->is_cd_image = 0;
112 return CDDAReader_init_device(self, device);
113 } else {
114 /*unsupported block device*/
115 PyErr_SetString(PyExc_ValueError, "unsupported block device");
116 return -1;
117 }
118 } else {
119 /*unsupported file type*/
120 PyErr_SetString(PyExc_ValueError, "unsupported file type");
121 return -1;
122 }
123 }
124
125 static int
CDDAReader_init_image(cdio_CDDAReader * self,const char * device)126 CDDAReader_init_image(cdio_CDDAReader *self, const char *device)
127 {
128 self->_.image.image = NULL;
129 self->_.image.current_sector = 0;
130 self->_.image.final_sector = 0;
131 self->first_track_num = CDDAReader_first_track_num_image;
132 self->last_track_num = CDDAReader_last_track_num_image;
133 self->track_lsn = CDDAReader_track_lsn_image;
134 self->track_last_lsn = CDDAReader_track_last_lsn_image;
135 self->first_sector = CDDAReader_first_sector_image;
136 self->last_sector = CDDAReader_last_sector_image;
137 self->read = CDDAReader_read_image;
138 self->seek = CDDAReader_seek_image;
139 self->set_speed = CDDAReader_set_speed_image;
140 self->dealloc = CDDAReader_dealloc_image;
141
142 /*open CD image based on what type it is*/
143 if (cdio_is_cuefile(device)) {
144 self->_.image.image = cdio_open_cue(device);
145 } else if (cdio_is_tocfile(device)) {
146 self->_.image.image = cdio_open_bincue(device);
147 } else if (cdio_is_tocfile(device)) {
148 self->_.image.image = cdio_open_cdrdao(device);
149 } else if (cdio_is_nrg(device)) {
150 self->_.image.image = cdio_open_nrg(device);
151 }
152 if (self->_.image.image == NULL) {
153 PyErr_SetString(PyExc_IOError, "unable to open CD image");
154 return -1;
155 }
156 self->_.image.final_sector = (lsn_t)self->last_sector(self);
157 return 0;
158 }
159
160 static int
CDDAReader_init_device(cdio_CDDAReader * self,const char * device)161 CDDAReader_init_device(cdio_CDDAReader *self, const char *device)
162 {
163 self->_.drive.drive = NULL;
164 self->_.drive.paranoia = NULL;
165 self->_.drive.current_sector = 0;
166 self->_.drive.final_sector = 0;
167
168 if ((self->_.drive.drive = cdio_cddap_identify(device, 0, NULL)) == NULL) {
169 PyErr_SetString(PyExc_IOError, "error opening CD-ROM");
170 return -1;
171 }
172 if (cdio_cddap_open(self->_.drive.drive) != 0) {
173 PyErr_SetString(PyExc_IOError, "error opening CD-ROM");
174 return -1;
175 }
176 self->_.drive.paranoia = cdio_paranoia_init(self->_.drive.drive);
177 paranoia_modeset(self->_.drive.paranoia,
178 PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
179
180 self->first_track_num = CDDAReader_first_track_num_device;
181 self->last_track_num = CDDAReader_last_track_num_device;
182 self->track_lsn = CDDAReader_track_lsn_device;
183 self->track_last_lsn = CDDAReader_track_last_lsn_device;
184 self->first_sector = CDDAReader_first_sector_device;
185 self->last_sector = CDDAReader_last_sector_device;
186 self->read = CDDAReader_read_device;
187 self->seek = CDDAReader_seek_device;
188 self->set_speed = CDDAReader_set_speed_device;
189 self->dealloc = CDDAReader_dealloc_device;
190
191 self->_.drive.final_sector = self->last_sector(self);
192
193 if ((self->_.drive.final_sector == -1) ||
194 (self->first_sector(self) == -1)) {
195 PyErr_SetString(PyExc_IOError, "no disc in CD-ROM drive");
196 return -1;
197 }
198
199 return 0;
200 }
201
202 static void
CDDAReader_dealloc(cdio_CDDAReader * self)203 CDDAReader_dealloc(cdio_CDDAReader *self)
204 {
205 if (self->dealloc) {
206 self->dealloc(self);
207 }
208 Py_XDECREF(self->audiotools_pcm);
209 Py_TYPE(self)->tp_free((PyObject*)self);
210 }
211
212 static void
CDDAReader_dealloc_image(cdio_CDDAReader * self)213 CDDAReader_dealloc_image(cdio_CDDAReader *self)
214 {
215 if (self->_.image.image != NULL) {
216 cdio_destroy(self->_.image.image);
217 }
218 }
219
220 static void
CDDAReader_dealloc_device(cdio_CDDAReader * self)221 CDDAReader_dealloc_device(cdio_CDDAReader *self)
222 {
223 if (self->_.drive.paranoia) {
224 cdio_paranoia_free(self->_.drive.paranoia);
225 }
226 if (self->_.drive.drive) {
227 cdio_cddap_close(self->_.drive.drive);
228 }
229 }
230
231 static PyObject*
CDDAReader_sample_rate(cdio_CDDAReader * self,void * closure)232 CDDAReader_sample_rate(cdio_CDDAReader *self, void *closure)
233 {
234 const int sample_rate = 44100;
235 return Py_BuildValue("i", sample_rate);
236 }
237
238 static PyObject*
CDDAReader_bits_per_sample(cdio_CDDAReader * self,void * closure)239 CDDAReader_bits_per_sample(cdio_CDDAReader *self, void *closure)
240 {
241 const int bits_per_sample = 16;
242 return Py_BuildValue("i", bits_per_sample);
243 }
244
245 static PyObject*
CDDAReader_channels(cdio_CDDAReader * self,void * closure)246 CDDAReader_channels(cdio_CDDAReader *self, void *closure)
247 {
248 const int channels = 2;
249 return Py_BuildValue("i", channels);
250 }
251
252 static PyObject*
CDDAReader_channel_mask(cdio_CDDAReader * self,void * closure)253 CDDAReader_channel_mask(cdio_CDDAReader *self, void *closure)
254 {
255 const int channel_mask = 0x3;
256 return Py_BuildValue("i", channel_mask);
257 }
258
259 static PyObject*
CDDAReader_is_cd_image(cdio_CDDAReader * self,void * closure)260 CDDAReader_is_cd_image(cdio_CDDAReader *self, void *closure)
261 {
262 return PyBool_FromLong(self->is_cd_image);
263 }
264
265 static int
CDDAReader_first_track_num_image(cdio_CDDAReader * self)266 CDDAReader_first_track_num_image(cdio_CDDAReader *self)
267 {
268 return cdio_get_first_track_num(self->_.image.image);
269 }
270
271 static int
CDDAReader_first_track_num_device(cdio_CDDAReader * self)272 CDDAReader_first_track_num_device(cdio_CDDAReader *self)
273 {
274 /*FIXME - not sure if there's a more accurate way to get this*/
275 return 1;
276 }
277
278 static int
CDDAReader_last_track_num_image(cdio_CDDAReader * self)279 CDDAReader_last_track_num_image(cdio_CDDAReader *self)
280 {
281 return cdio_get_last_track_num(self->_.image.image);
282 }
283
284 static int
CDDAReader_last_track_num_device(cdio_CDDAReader * self)285 CDDAReader_last_track_num_device(cdio_CDDAReader *self)
286 {
287 /*FIXME - not sure if there's a more accurate way to get this*/
288 return cdio_cddap_tracks(self->_.drive.drive);
289 }
290
291 static int
CDDAReader_track_lsn_image(cdio_CDDAReader * self,int track_num)292 CDDAReader_track_lsn_image(cdio_CDDAReader *self, int track_num)
293 {
294 const lsn_t lsn = cdio_get_track_lsn(self->_.image.image,
295 (track_t)track_num);
296 return (int)lsn;
297 }
298
299 static int
CDDAReader_track_lsn_device(cdio_CDDAReader * self,int track_num)300 CDDAReader_track_lsn_device(cdio_CDDAReader *self, int track_num)
301 {
302 const lsn_t lsn = cdio_cddap_track_firstsector(self->_.drive.drive,
303 (track_t)track_num);
304 return lsn;
305 }
306
307 static int
CDDAReader_track_last_lsn_image(cdio_CDDAReader * self,int track_num)308 CDDAReader_track_last_lsn_image(cdio_CDDAReader *self, int track_num)
309 {
310 const lsn_t lsn = cdio_get_track_last_lsn(self->_.image.image,
311 (track_t)track_num);
312 return (int)lsn;
313 }
314
315 static int
CDDAReader_track_last_lsn_device(cdio_CDDAReader * self,int track_num)316 CDDAReader_track_last_lsn_device(cdio_CDDAReader *self, int track_num)
317 {
318 const lsn_t lsn = cdio_cddap_track_lastsector(self->_.drive.drive,
319 (track_t)track_num);
320 return lsn;
321 }
322
323 static PyObject*
CDDAReader_track_offsets(cdio_CDDAReader * self,void * closure)324 CDDAReader_track_offsets(cdio_CDDAReader *self, void *closure)
325 {
326 const int first_track_num = self->first_track_num(self);
327 const int last_track_num = self->last_track_num(self);
328 int i;
329 PyObject *offsets = PyDict_New();
330
331 if (offsets == NULL) {
332 /*error creating the dict*/
333 return NULL;
334 }
335
336 for (i = first_track_num; i <= last_track_num; i++) {
337 PyObject *track_num = PyInt_FromLong(i);
338 PyObject *track_offset = PyInt_FromLong(
339 self->track_lsn(self, i) * 588);
340 int result;
341 if ((track_num == NULL) || (track_offset == NULL)) {
342 /*error creating one of the two int values*/
343 Py_XDECREF(track_num);
344 Py_XDECREF(track_offset);
345 Py_DECREF(offsets);
346 return NULL;
347 }
348 result = PyDict_SetItem(offsets, track_num, track_offset);
349 Py_DECREF(track_num);
350 Py_DECREF(track_offset);
351 if (result == -1) {
352 /*error setting dictionary item*/
353 Py_DECREF(offsets);
354 return NULL;
355 }
356 }
357
358 return offsets;
359 }
360
361 static PyObject*
CDDAReader_track_lengths(cdio_CDDAReader * self,void * closure)362 CDDAReader_track_lengths(cdio_CDDAReader *self, void *closure)
363 {
364 const int first_track_num = self->first_track_num(self);
365 const int last_track_num = self->last_track_num(self);
366 int i;
367 PyObject *lengths = PyDict_New();
368
369 if (lengths == NULL) {
370 /*error creating the dict*/
371 return NULL;
372 }
373
374 for (i = first_track_num; i <= last_track_num; i++) {
375 PyObject *track_num = PyInt_FromLong(i);
376 PyObject *track_length = PyInt_FromLong(
377 (self->track_last_lsn(self, i) -
378 self->track_lsn(self, i) + 1) * 588);
379 int result;
380 if ((track_num == NULL) || (track_length == NULL)) {
381 /*error creating one of the two int values*/
382 Py_XDECREF(track_num);
383 Py_XDECREF(track_length);
384 Py_DECREF(lengths);
385 return NULL;
386 }
387 result = PyDict_SetItem(lengths, track_num, track_length);
388 Py_DECREF(track_num);
389 Py_DECREF(track_length);
390 if (result == -1) {
391 /*error setting dictionary item*/
392 Py_DECREF(lengths);
393 return NULL;
394 }
395 }
396
397 return lengths;
398 }
399
400 static PyObject*
CDDAReader_first_sector(cdio_CDDAReader * self,void * closure)401 CDDAReader_first_sector(cdio_CDDAReader *self, void *closure)
402 {
403 const int first_sector = self->first_sector(self);
404 return Py_BuildValue("i", first_sector);
405 }
406
407 static int
CDDAReader_first_sector_image(cdio_CDDAReader * self)408 CDDAReader_first_sector_image(cdio_CDDAReader *self)
409 {
410 return cdio_get_track_lsn(self->_.image.image,
411 self->first_track_num(self));
412 }
413
414 static int
CDDAReader_first_sector_device(cdio_CDDAReader * self)415 CDDAReader_first_sector_device(cdio_CDDAReader *self)
416 {
417 return cdio_cddap_track_firstsector(self->_.drive.drive,
418 self->first_track_num(self));
419 }
420
421 static PyObject*
CDDAReader_last_sector(cdio_CDDAReader * self,void * closure)422 CDDAReader_last_sector(cdio_CDDAReader *self, void *closure)
423 {
424 const int last_sector = self->last_sector(self);
425 return Py_BuildValue("i", last_sector);
426 }
427
428 static int
CDDAReader_last_sector_image(cdio_CDDAReader * self)429 CDDAReader_last_sector_image(cdio_CDDAReader *self)
430 {
431 return cdio_get_track_last_lsn(self->_.image.image,
432 self->last_track_num(self));
433 }
434
435 static int
CDDAReader_last_sector_device(cdio_CDDAReader * self)436 CDDAReader_last_sector_device(cdio_CDDAReader *self)
437 {
438 return cdio_cddap_track_lastsector(self->_.drive.drive,
439 self->last_track_num(self));
440 }
441
442 static PyObject*
CDDAReader_read(cdio_CDDAReader * self,PyObject * args)443 CDDAReader_read(cdio_CDDAReader* self, PyObject *args)
444 {
445 int pcm_frames;
446 unsigned sectors_to_read;
447 a_int *samples = a_int_new();
448 int successful;
449 PyThreadState *thread_state = NULL;
450 PyObject *to_return;
451
452 if (!PyArg_ParseTuple(args, "i", &pcm_frames)) {
453 return NULL;
454 }
455
456 if (self->closed) {
457 PyErr_SetString(PyExc_ValueError, "cannot read closed stream");
458 return NULL;
459 }
460
461 sectors_to_read = MAX(pcm_frames, 0) / (44100 / 75);
462 if (sectors_to_read < 1) {
463 sectors_to_read = 1;
464 }
465
466 /*if logging is in progress, only let a single thread
467 into this function at once so that the global callback
468 can be set and used atomically
469
470 since the callback function doesn't take any state
471 we're forced to stick it in a global variable*/
472 if (!self->is_logging) {
473 thread_state = PyEval_SaveThread();
474 }
475 successful = !self->read(self, sectors_to_read, samples);
476 if (!self->is_logging) {
477 PyEval_RestoreThread(thread_state);
478 }
479
480 if (successful) {
481 to_return = a_int_to_FrameList(self->audiotools_pcm,
482 samples, 2, 16);
483 samples->del(samples);
484 return to_return;
485 } else {
486 samples->del(samples);
487 PyErr_SetString(PyExc_IOError, "I/O error reading stream");
488 return NULL;
489 }
490 }
491
492 static int
CDDAReader_read_image(cdio_CDDAReader * self,unsigned sectors_to_read,a_int * samples)493 CDDAReader_read_image(cdio_CDDAReader *self,
494 unsigned sectors_to_read,
495 a_int *samples)
496 {
497 while (sectors_to_read &&
498 (self->_.image.current_sector <= self->_.image.final_sector)) {
499 uint8_t sector[CDIO_CD_FRAMESIZE_RAW];
500 uint8_t *data = sector;
501 const int result = cdio_read_audio_sector(
502 self->_.image.image,
503 sector,
504 self->_.image.current_sector);
505
506 if (result == DRIVER_OP_SUCCESS) {
507 unsigned i;
508 samples->resize_for(samples, (44100 / 75) * 2);
509 for (i = 0; i < ((44100 / 75) * 2); i++) {
510 a_append(samples, FrameList_SL16_char_to_int(data));
511 data += 2;
512 }
513 self->_.image.current_sector++;
514 sectors_to_read--;
515 } else {
516 return 1;
517 }
518 }
519
520 return 0;
521 }
522
523 static int
CDDAReader_read_device(cdio_CDDAReader * self,unsigned sectors_to_read,a_int * samples)524 CDDAReader_read_device(cdio_CDDAReader *self,
525 unsigned sectors_to_read,
526 a_int *samples)
527 {
528 if (self->is_logging) {
529 log_state = &(self->log);
530 }
531
532 while (sectors_to_read &&
533 (self->_.drive.current_sector <= self->_.drive.final_sector)) {
534 int16_t *raw_sector =
535 cdio_paranoia_read_limited(
536 self->_.drive.paranoia,
537 self->is_logging ? cddareader_callback : NULL,
538 10);
539 unsigned i;
540
541 samples->resize_for(samples, (44100 / 75) * 2);
542 for (i = 0; i < ((44100 / 75) * 2); i++) {
543 a_append(samples, raw_sector[i]);
544 }
545
546 self->_.drive.current_sector++;
547 sectors_to_read--;
548 }
549
550 if (self->is_logging) {
551 log_state = NULL;
552 }
553
554 return 0;
555 }
556
557 static PyObject*
CDDAReader_seek(cdio_CDDAReader * self,PyObject * args)558 CDDAReader_seek(cdio_CDDAReader* self, PyObject *args)
559 {
560 long long seeked_offset;
561 unsigned seeked_sector;
562 unsigned found_sector;
563
564 if (self->closed) {
565 PyErr_SetString(PyExc_ValueError, "cannot seek closed stream");
566 return NULL;
567 }
568 if (!PyArg_ParseTuple(args, "L", &seeked_offset))
569 return NULL;
570
571 if (seeked_offset < 0) {
572 seeked_offset = 0;
573 }
574
575 if (seeked_offset > UINT_MAX) {
576 seeked_sector = UINT_MAX;
577 } else {
578 seeked_sector = (unsigned)(seeked_offset / (44100 / 75));
579 }
580 found_sector = self->seek(self, seeked_sector);
581 return Py_BuildValue("I", found_sector * (44100 / 75));
582 }
583
584 static unsigned
CDDAReader_seek_image(cdio_CDDAReader * self,unsigned sector)585 CDDAReader_seek_image(cdio_CDDAReader *self, unsigned sector)
586 {
587 self->_.image.current_sector =
588 MIN(sector, self->_.image.final_sector - 1);
589 return self->_.image.current_sector;
590 }
591
592 static unsigned
CDDAReader_seek_device(cdio_CDDAReader * self,unsigned sector)593 CDDAReader_seek_device(cdio_CDDAReader *self, unsigned sector)
594 {
595 const unsigned desired_sector = MIN(sector, self->_.drive.final_sector - 1);
596 /*not sure what this returns, but it isn't the sector seeked to*/
597 cdio_paranoia_seek(self->_.drive.paranoia,
598 (int32_t)desired_sector,
599 (int)SEEK_SET);
600 self->_.drive.current_sector = desired_sector;
601 return self->_.drive.current_sector;
602 }
603
604 static PyObject*
CDDAReader_close(cdio_CDDAReader * self,PyObject * args)605 CDDAReader_close(cdio_CDDAReader* self, PyObject *args)
606 {
607 self->closed = 1;
608
609 Py_INCREF(Py_None);
610 return Py_None;
611 }
612
613 static PyObject*
CDDAReader_set_speed(cdio_CDDAReader * self,PyObject * args)614 CDDAReader_set_speed(cdio_CDDAReader *self, PyObject *args)
615 {
616 int new_speed;
617
618 if (!PyArg_ParseTuple(args, "i", &new_speed))
619 return NULL;
620
621 self->set_speed(self, new_speed);
622
623 Py_INCREF(Py_None);
624 return Py_None;
625 }
626
627 static void
CDDAReader_set_speed_image(cdio_CDDAReader * self,int new_speed)628 CDDAReader_set_speed_image(cdio_CDDAReader *self, int new_speed)
629 {
630 /*not an actual CD device, so do nothing*/
631 }
632
633 static void
CDDAReader_set_speed_device(cdio_CDDAReader * self,int new_speed)634 CDDAReader_set_speed_device(cdio_CDDAReader *self, int new_speed)
635 {
636 cdio_cddap_speed_set(self->_.drive.drive, new_speed);
637 }
638
639 static void
cddareader_callback(long int i,paranoia_cb_mode_t mode)640 cddareader_callback(long int i, paranoia_cb_mode_t mode)
641 {
642 if (log_state) {
643 switch (mode) {
644 case PARANOIA_CB_READ:
645 log_state->read++;
646 break;
647 case PARANOIA_CB_VERIFY:
648 log_state->verify++;
649 break;
650 case PARANOIA_CB_FIXUP_EDGE:
651 log_state->fixup_edge++;
652 break;
653 case PARANOIA_CB_FIXUP_ATOM:
654 log_state->fixup_atom++;
655 break;
656 case PARANOIA_CB_SCRATCH:
657 log_state->scratch++;
658 break;
659 case PARANOIA_CB_REPAIR:
660 log_state->repair++;
661 break;
662 case PARANOIA_CB_SKIP:
663 log_state->skip++;
664 break;
665 case PARANOIA_CB_DRIFT:
666 log_state->drift++;
667 break;
668 case PARANOIA_CB_BACKOFF:
669 log_state->backoff++;
670 break;
671 case PARANOIA_CB_OVERLAP:
672 log_state->overlap++;
673 break;
674 case PARANOIA_CB_FIXUP_DROPPED:
675 log_state->fixup_dropped++;
676 break;
677 case PARANOIA_CB_FIXUP_DUPED:
678 log_state->fixup_duped++;
679 break;
680 case PARANOIA_CB_READERR:
681 log_state->readerr++;
682 break;
683 default:
684 break;
685 }
686 }
687 }
688
689 static void
cddareader_reset_log(struct cdio_log * log)690 cddareader_reset_log(struct cdio_log *log)
691 {
692 log->read = 0;
693 log->verify = 0;
694 log->fixup_edge = 0;
695 log->fixup_atom = 0;
696 log->scratch = 0;
697 log->repair = 0;
698 log->skip = 0;
699 log->drift = 0;
700 log->backoff = 0;
701 log->overlap = 0;
702 log->fixup_dropped = 0;
703 log->fixup_duped = 0;
704 log->readerr = 0;
705 }
706
707 static int
cddareader_set_log_item(PyObject * dict,const char * key,int value)708 cddareader_set_log_item(PyObject *dict, const char *key, int value)
709 {
710 PyObject *value_obj = Py_BuildValue("i", value);
711 if (value_obj) {
712 const int result = PyDict_SetItemString(dict, key, value_obj);
713 Py_DECREF(value_obj);
714 if (result == 0) {
715 return 0;
716 } else {
717 return 1;
718 }
719 } else {
720 return 1;
721 }
722 }
723
724 static PyObject*
CDDAReader_log(cdio_CDDAReader * self,PyObject * args)725 CDDAReader_log(cdio_CDDAReader *self, PyObject *args)
726 {
727 const struct cdio_log *log = &(self->log);
728 PyObject *log_obj = PyDict_New();
729 if (log_obj) {
730 if (cddareader_set_log_item(log_obj, "read", log->read))
731 goto error;
732 if (cddareader_set_log_item(log_obj, "verify", log->verify))
733 goto error;
734 if (cddareader_set_log_item(log_obj, "fixup_edge", log->fixup_edge))
735 goto error;
736 if (cddareader_set_log_item(log_obj, "fixup_atom", log->fixup_atom))
737 goto error;
738 if (cddareader_set_log_item(log_obj, "scratch", log->scratch))
739 goto error;
740 if (cddareader_set_log_item(log_obj, "repair", log->repair))
741 goto error;
742 if (cddareader_set_log_item(log_obj, "skip", log->skip))
743 goto error;
744 if (cddareader_set_log_item(log_obj, "drift", log->drift))
745 goto error;
746 if (cddareader_set_log_item(log_obj, "backoff", log->backoff))
747 goto error;
748 if (cddareader_set_log_item(log_obj, "overlap", log->overlap))
749 goto error;
750 if (cddareader_set_log_item(log_obj, "fixup_dropped",
751 log->fixup_dropped))
752 goto error;
753 if (cddareader_set_log_item(log_obj, "fixup_duped", log->fixup_duped))
754 goto error;
755 if (cddareader_set_log_item(log_obj, "readerr", log->readerr))
756 goto error;
757
758 return log_obj;
759 error:
760 Py_DECREF(log_obj);
761 return NULL;
762 } else {
763 return NULL;
764 }
765 }
766
767 static PyObject*
CDDAReader_reset_log(cdio_CDDAReader * self,PyObject * args)768 CDDAReader_reset_log(cdio_CDDAReader *self, PyObject *args)
769 {
770 cddareader_reset_log(&(self->log));
771 Py_INCREF(Py_None);
772 return Py_None;
773 }
774