static int check_disc_space(sacd_reader_t *sacd_reader, scarletbook_handle_t *handle, int ripping_flags) { uint64_t needed_sectors = 0; if (ripping_flags & RIP_ISO) { needed_sectors = sacd_get_total_sectors(sacd_reader); } else if (has_two_channel(handle) && ripping_flags & RIP_2CH) { needed_sectors = get_two_channel(handle)->track_end - get_two_channel(handle)->track_start; } else if (has_both_channels(handle) && ripping_flags & RIP_MCH) { needed_sectors = get_multi_channel(handle)->track_end - get_multi_channel(handle)->track_start; } if (needed_sectors > output_device_sectors) { msgType dialog_type; char *message = (char *) malloc(512); LOG(lm_main, LOG_ERROR, ("no enough disc space on %s (%llu), needs: %llu", output_device, output_device_sectors, needed_sectors)); snprintf(message, 512, "Ripping aborted.\nYou do not have enough disc space on [%s (%.2fGB available)].", output_device, output_device_space); dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON); dialog_action = 0; msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL); while (!user_requested_exit() && !dialog_action) { sysUtilCheckCallback(); flip(); } msgDialogAbort(); free(message); return 0; } return 1; }
int main(int argc, char* argv[]) { char *albumdir = 0, *musicfilename, *file_path = 0; int i, area_idx; sacd_reader_t *sacd_reader; #ifdef PTW32_STATIC_LIB pthread_win32_process_attach_np(); pthread_win32_thread_attach_np(); #endif init(); if (parse_options(argc, argv)) { setlocale(LC_ALL, ""); if (fwide(stdout, 1) < 0) { fprintf(stderr, "ERROR: Output not set to wide.\n"); } // default to 2 channel if (opts.two_channel == 0 && opts.multi_channel == 0) { opts.two_channel = 1; } sacd_reader = sacd_open(opts.input_device); if (sacd_reader) { handle = scarletbook_open(sacd_reader, 0); if (handle) { if (opts.print) { scarletbook_print(handle); } if (opts.output_dsf || opts.output_iso || opts.output_dsdiff || opts.output_dsdiff_em || opts.export_cue_sheet) { output = scarletbook_output_create(handle, handle_status_update_track_callback, handle_status_update_progress_callback, safe_fwprintf); // select the channel area area_idx = ((has_multi_channel(handle) && opts.multi_channel) || !has_two_channel(handle)) ? handle->mulch_area_idx : handle->twoch_area_idx; albumdir = (strlen(opts.output_file) > 0 ? strdup(opts.output_file) : get_album_dir(handle)); if (opts.output_iso) { uint32_t total_sectors = sacd_get_total_sectors(sacd_reader); #ifdef SECTOR_LIMIT #define FAT32_SECTOR_LIMIT 2090000 uint32_t sector_size = FAT32_SECTOR_LIMIT; uint32_t sector_offset = 0; if (total_sectors > FAT32_SECTOR_LIMIT) { musicfilename = (char *) malloc(512); file_path = make_filename(0, 0, albumdir, "iso"); for (i = 1; total_sectors != 0; i++) { sector_size = min(total_sectors, FAT32_SECTOR_LIMIT); snprintf(musicfilename, 512, "%s.%03d", file_path, i); scarletbook_output_enqueue_raw_sectors(output, sector_offset, sector_size, musicfilename, "iso"); sector_offset += sector_size; total_sectors -= sector_size; } free(musicfilename); } else #endif { get_unique_filename(&albumdir, "iso"); file_path = make_filename(0, 0, albumdir, "iso"); scarletbook_output_enqueue_raw_sectors(output, 0, total_sectors, file_path, "iso"); } } else if (opts.output_dsdiff_em) { get_unique_filename(&albumdir, "dff"); file_path = make_filename(0, 0, albumdir, "dff"); scarletbook_output_enqueue_track(output, area_idx, 0, file_path, "dsdiff_edit_master", (opts.convert_dst ? 1 : handle->area[area_idx].area_toc->frame_format != FRAME_FORMAT_DST)); } else if (opts.output_dsf || opts.output_dsdiff) { // create the output folder get_unique_dir(0, &albumdir); recursive_mkdir(albumdir, 0774); // fill the queue with items to rip for (i = 0; i < handle->area[area_idx].area_toc->track_count; i++) { if (opts.select_tracks && opts.selected_tracks[i] == 0) continue; musicfilename = get_music_filename(handle, area_idx, i, opts.output_file); if (opts.output_dsf) { file_path = make_filename(0, albumdir, musicfilename, "dsf"); scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsf", 1 /* always decode to DSD */); } else if (opts.output_dsdiff) { file_path = make_filename(0, albumdir, musicfilename, "dff"); scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsdiff", (opts.convert_dst ? 1 : handle->area[area_idx].area_toc->frame_format != FRAME_FORMAT_DST)); } free(musicfilename); free(file_path); file_path = 0; } } if (opts.export_cue_sheet) { char *cue_file_path = make_filename(0, 0, albumdir, "cue"); #ifdef _WIN32 wchar_t *wide_filename = (wchar_t *) charset_convert(cue_file_path, strlen(cue_file_path), "UTF-8", sizeof(wchar_t) == 2 ? "UCS-2-INTERNAL" : "UCS-4-INTERNAL"); #else wchar_t *wide_filename = (wchar_t *) charset_convert(cue_file_path, strlen(cue_file_path), "UTF-8", "WCHAR_T"); #endif fwprintf(stdout, L"Exporting CUE sheet [%ls]\n", wide_filename); if (!file_path) file_path = make_filename(0, 0, albumdir, "dff"); write_cue_sheet(handle, file_path, area_idx, cue_file_path); free(cue_file_path); free(wide_filename); } free(file_path); started_processing = time(0); scarletbook_output_start(output); scarletbook_output_destroy(output); fprintf(stdout, "\rWe are done.. \n"); } scarletbook_close(handle); free(albumdir); } } sacd_close(sacd_reader); #ifndef _WIN32 freopen(0, "w", stdout); #endif if (fwide(stdout, -1) >= 0) { fprintf(stderr, "ERROR: Output not set to byte oriented.\n"); } } free_lock(g_fwprintf_lock); destroy_logging(); #ifdef PTW32_STATIC_LIB pthread_win32_process_detach_np(); pthread_win32_thread_detach_np(); #endif printf("\n"); return 0; }
int start_ripping_gui(int ripping_flags) { char *albumdir, *musicfilename, *file_path = 0; sacd_reader_t *sacd_reader; scarletbook_handle_t *handle; scarletbook_output_t *output; msgType dialog_type; int area_idx, i, ret; uint32_t prev_upper_progress = 0; uint32_t prev_lower_progress = 0; uint32_t delta; int prev_current_track = 0; uint32_t prev_stats_total_sectors_processed = 0; uint32_t prev_stats_current_file_sectors_processed = 0; uint64_t tb_start, tb_freq; uint64_t tmp_total_ripping_sectors = 0; char progress_message[64]; sysAtomicSet(&stats_total_sectors, 0); sysAtomicSet(&stats_total_sectors_processed, 0); sysAtomicSet(&stats_current_file_total_sectors, 0); sysAtomicSet(&stats_current_file_sectors_processed, 0); sysAtomicSet(&stats_current_track, 0); sysAtomicSet(&stats_total_tracks, 0); sacd_reader = sacd_open("/dev_bdvd"); if (sacd_reader) { handle = scarletbook_open(sacd_reader, 0); if (check_disc_space(sacd_reader, handle, ripping_flags)) { ret = sacd_authenticate(sacd_reader); if (ret != 0) { LOG(lm_main, LOG_ERROR, ("authentication failed: %x", ret)); } // select the channel area area_idx = ((has_multi_channel(handle) && ripping_flags & RIP_MCH) || !has_two_channel(handle)) ? handle->mulch_area_idx : handle->twoch_area_idx; albumdir = get_album_dir(handle); output = scarletbook_output_create(handle, handle_status_update_track_callback, handle_status_update_progress_callback, safe_fwprintf); if (ripping_flags & RIP_ISO) { #define FAT32_SECTOR_LIMIT 2090000 uint32_t total_sectors = sacd_get_total_sectors(sacd_reader); uint32_t sector_size = FAT32_SECTOR_LIMIT; uint32_t sector_offset = 0; if (total_sectors > FAT32_SECTOR_LIMIT) { musicfilename = (char *) malloc(512); file_path = make_filename(output_device, 0, albumdir, "iso"); for (i = 1; total_sectors != 0; i++) { sector_size = min(total_sectors, FAT32_SECTOR_LIMIT); snprintf(musicfilename, 512, "%s.%03d", file_path, i); scarletbook_output_enqueue_raw_sectors(output, sector_offset, sector_size, musicfilename, "iso"); sector_offset += sector_size; total_sectors -= sector_size; } free(file_path); free(musicfilename); } else { file_path = make_filename(output_device, 0, albumdir, "iso"); scarletbook_output_enqueue_raw_sectors(output, 0, total_sectors, file_path, "iso"); free(file_path); } tmp_total_ripping_sectors = sacd_get_total_sectors(sacd_reader); } else { // do not overwrite previous dump get_unique_dir(output_device, &albumdir); // fill the queue with items to rip for (i = 0; i < handle->area[area_idx].area_toc->track_count; i++) { musicfilename = get_music_filename(handle, area_idx, i, 0); if (ripping_flags & RIP_DSF) { file_path = make_filename(output_device, albumdir, musicfilename, "dsf"); scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsf", 1 /* always decode to DSD */); } else if (ripping_flags & RIP_DSDIFF) { file_path = make_filename(output_device, albumdir, musicfilename, "dff"); scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsdiff", ((ripping_flags & RIP_2CH_DST || ripping_flags & RIP_MCH_DST) ? 0 : 1)); } tmp_total_ripping_sectors += handle->area[area_idx].area_tracklist_offset->track_length_lsn[i]; free(musicfilename); free(file_path); } file_path = make_filename(output_device, albumdir, 0, 0); LOG(lm_main, LOG_NOTICE, ("setting output folder to: %s", file_path)); recursive_mkdir(file_path, 0777); free(file_path); } scarletbook_output_start(output); tb_freq = sysGetTimebaseFrequency(); tb_start = __gettime(); { char *message = (char *) malloc(512); file_path = make_filename(output_device, albumdir, 0, 0); snprintf(message, 512, "Title: %s\nOutput: %s\nFormat: %s\nSize: %.2fGB\nArea: %s\nEncoding: %s", substr(albumdir, 0, 100), file_path, (ripping_flags & RIP_DSDIFF ? "DSDIFF" : (ripping_flags & RIP_DSF ? "DSF" : "ISO")), ((double) ((tmp_total_ripping_sectors * SACD_LSN_SIZE) / 1073741824.00)), (ripping_flags & RIP_2CH ? "2ch" : "mch"), (ripping_flags & RIP_2CH_DST || ripping_flags & RIP_MCH_DST ? "DST" : (ripping_flags & RIP_ISO ? "DECRYPTED" : "DSD")) ); free(file_path); dialog_action = 0; dialog_type = MSG_DIALOG_MUTE_ON | MSG_DIALOG_DOUBLE_PROGRESSBAR; msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL); while (!user_requested_exit() && dialog_action == 0 && scarletbook_output_is_busy(output)) { uint32_t tmp_stats_total_sectors_processed = sysAtomicRead(&stats_total_sectors_processed); uint32_t tmp_stats_total_sectors = sysAtomicRead(&stats_total_sectors); uint32_t tmp_stats_current_file_sectors_processed = sysAtomicRead(&stats_current_file_sectors_processed); uint32_t tmp_stats_current_file_total_sectors = sysAtomicRead(&stats_current_file_total_sectors); int tmp_current_track = sysAtomicRead(&stats_current_track); if (tmp_current_track != 0 && tmp_current_track != prev_current_track) { memset(progress_message, 0, 64); musicfilename = get_music_filename(handle, area_idx, tmp_current_track - 1, 0); // HACK: substr is not thread safe, but it's only used in this thread.. snprintf(progress_message, 63, "Track (%d/%d): [%s...]", tmp_current_track, sysAtomicRead(&stats_total_tracks), substr(musicfilename, 0, 40)); free(musicfilename); msgDialogProgressBarReset(MSG_PROGRESSBAR_INDEX0); msgDialogProgressBarSetMsg(MSG_PROGRESSBAR_INDEX1, progress_message); prev_upper_progress = 0; prev_stats_current_file_sectors_processed = 0; prev_current_track = tmp_current_track; } if (tmp_stats_total_sectors != 0 && prev_stats_total_sectors_processed != tmp_stats_total_sectors_processed) { delta = (tmp_stats_current_file_sectors_processed + (tmp_stats_current_file_sectors_processed - prev_stats_current_file_sectors_processed)) * 100 / tmp_stats_current_file_total_sectors - prev_upper_progress; prev_upper_progress += delta; msgDialogProgressBarInc(MSG_PROGRESSBAR_INDEX0, delta); delta = (tmp_stats_total_sectors_processed + (tmp_stats_total_sectors_processed - prev_stats_total_sectors_processed)) * 100 / tmp_stats_total_sectors - prev_lower_progress; prev_lower_progress += delta; msgDialogProgressBarInc(MSG_PROGRESSBAR_INDEX1, delta); snprintf(progress_message, 64, "Ripping %.1fMB/%.1fMB at %.2fMB/sec", ((float)(tmp_stats_current_file_sectors_processed * SACD_LSN_SIZE) / 1048576.00), ((float)(tmp_stats_current_file_total_sectors * SACD_LSN_SIZE) / 1048576.00), (float)((float) tmp_stats_total_sectors_processed * SACD_LSN_SIZE / 1048576.00) / (float)((__gettime() - tb_start) / (float)(tb_freq))); msgDialogProgressBarSetMsg(MSG_PROGRESSBAR_INDEX0, progress_message); prev_stats_total_sectors_processed = tmp_stats_total_sectors_processed; prev_stats_current_file_sectors_processed = tmp_stats_current_file_sectors_processed; } sysUtilCheckCallback(); flip(); } msgDialogAbort(); free(message); } free(albumdir); scarletbook_output_destroy(output); } scarletbook_close(handle); } sacd_close(sacd_reader); if (user_requested_exit()) { return 0; } else if (1) { dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON); msgDialogOpen2(dialog_type, "ripping process completed.", dialog_handler, NULL, NULL); dialog_action = 0; while (!dialog_action && !user_requested_exit()) { sysUtilCheckCallback(); flip(); } msgDialogAbort(); } return 0; }
static void client_thread(void *userdata) { p_socket client = (p_socket) userdata; ServerRequest request; ServerResponse response; uint8_t zero = 0; uint8_t *output_buf = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); pb_istream_t input = pb_istream_from_socket(client); pb_ostream_t output; sacd_reader_t *sacd_reader = 0; scarletbook_handle_t *handle = 0; int non_encrypted_disc = 0; int checked_for_non_encrypted_disc = 0; uint32_t encrypted_start_1 = 0; uint32_t encrypted_start_2 = 0; uint32_t encrypted_end_1 = 0; uint32_t encrypted_end_2 = 0; uint32_t block_size = 0; uint32_t end_lsn = 0; client_connected = 1; response.data.bytes = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE); for (;;) { if (!pb_decode(&input, ServerRequest_fields, &request)) { break; } response.has_data = false; response.data.size = 0; response.result = -1; switch(request.type) { case ServerRequest_Type_DISC_READ: { response.type = ServerResponse_Type_DISC_READ; if (handle && sacd_reader) { int encrypted = 0; end_lsn = request.sector_offset + request.sector_count; // check what block ranges are encrypted.. if (request.sector_offset < encrypted_start_1) { block_size = min(encrypted_start_1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); encrypted = 0; } else if (request.sector_offset >= encrypted_start_1 && request.sector_offset <= encrypted_end_1) { block_size = min(encrypted_end_1 + 1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); encrypted = 1; } else if (request.sector_offset > encrypted_end_1 && request.sector_offset < encrypted_start_2) { block_size = min(encrypted_start_2 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); encrypted = 0; } else if (request.sector_offset >= encrypted_start_2 && request.sector_offset <= encrypted_end_2) { block_size = min(encrypted_end_2 + 1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); encrypted = 1; } block_size = min(end_lsn - request.sector_offset, block_size); response.result = sacd_read_block_raw(sacd_reader, request.sector_offset, block_size, response.data.bytes); response.has_data = response.result > 0; response.data.size = response.result * SACD_LSN_SIZE; // the ATAPI call which returns the flag if the disc is encrypted or not is unknown at this point. // user reports tell me that the only non-encrypted discs out there are DSD 3 14/16 discs. // this is a quick hack/fix for these discs. if (encrypted && checked_for_non_encrypted_disc == 0) { switch (handle->area[0].area_toc->frame_format) { case FRAME_FORMAT_DSD_3_IN_14: case FRAME_FORMAT_DSD_3_IN_16: non_encrypted_disc = *(uint64_t *)(response.data.bytes + 16) == 0; break; } checked_for_non_encrypted_disc = 1; } // encrypted blocks need to be decrypted first if (encrypted && non_encrypted_disc == 0) { sacd_decrypt(sacd_reader, response.data.bytes, block_size); } } } break; case ServerRequest_Type_DISC_OPEN: response.type = ServerResponse_Type_DISC_OPENED; sacd_reader = sacd_open("/dev_bdvd"); if (sacd_reader) { handle = scarletbook_open(sacd_reader, 0); checked_for_non_encrypted_disc = 0; non_encrypted_disc = 0; if (handle) { // set the encryption range if (handle->area[0].area_toc != 0) { encrypted_start_1 = handle->area[0].area_toc->track_start; encrypted_end_1 = handle->area[0].area_toc->track_end; } if (handle->area[1].area_toc != 0) { encrypted_start_2 = handle->area[1].area_toc->track_start; encrypted_end_2 = handle->area[1].area_toc->track_end; } response.result = sacd_authenticate(sacd_reader); } } break; case ServerRequest_Type_DISC_CLOSE: { response.type = ServerResponse_Type_DISC_CLOSED; if (handle) { scarletbook_close(handle); handle = 0; } if (sacd_reader) { sacd_close(sacd_reader); sacd_reader = 0; } response.result = 0; } break; case ServerRequest_Type_DISC_SIZE: response.type = ServerResponse_Type_DISC_SIZE; if (sacd_reader) { response.result = sacd_get_total_sectors(sacd_reader); } break; } // reset output stream output = pb_ostream_from_buffer(output_buf, MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); if (!pb_encode(&output, ServerResponse_fields, &response)) { break; } /* We signal the end of a request with a 0 tag. */ pb_write(&output, &zero, 1); // write the output buffer to the opened socket { bool ret; size_t written; ret = (socket_send(client, (char *) output_buf, output.bytes_written, &written, 0, 0) == IO_DONE && written == output.bytes_written); if (!ret) break; } if (request.type == ServerRequest_Type_DISC_CLOSE) { break; } } if (handle) scarletbook_close(handle); if (sacd_reader) sacd_close(sacd_reader); free(response.data.bytes); free(output_buf); closesocket((int) *client); client_connected = 0; sysThreadExit(0); }