Skip to content

Commit 0ed7a3a

Browse files
committed
chdman: Add Dreamcast cue output support
1 parent 3f96e5c commit 0ed7a3a

File tree

1 file changed

+85
-35
lines changed

1 file changed

+85
-35
lines changed

src/tools/chdman.cpp

Lines changed: 85 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2569,6 +2569,13 @@ static void do_extract_cd(parameters_map &params)
25692569

25702570
// GDIs will always output as split bin
25712571
bool is_splitbin = mode == MODE_GDI || params.find(OPTION_OUTPUT_SPLIT) != params.end();
2572+
if (!is_splitbin && cdrom->is_gdrom() && mode == MODE_CUEBIN)
2573+
{
2574+
// GD-ROM cue/bin is in Redump format which should always be split by tracks
2575+
util::stream_format(std::cout, "Warning: --%s is required for this specific combination of input disc type and output format, enabling automatically\n", OPTION_OUTPUT_SPLIT);
2576+
is_splitbin = true;
2577+
}
2578+
25722579
if (is_splitbin)
25732580
{
25742581
if (mode == MODE_GDI)
@@ -2612,11 +2619,6 @@ static void do_extract_cd(parameters_map &params)
26122619
std::string trackbin_name;
26132620
try
26142621
{
2615-
if (cdrom->is_gdrom() && (mode == MODE_CUEBIN))
2616-
{
2617-
util::stream_format(std::cout, "Warning: extracting GD-ROM CHDs as bin/cue is not fully supported and will result in an unusable CD-ROM cue file.\n");
2618-
}
2619-
26202622
// process output file
26212623
std::error_condition filerr = util::core_file::open(*output_file_str->second, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, output_toc_file);
26222624
if (filerr)
@@ -2736,6 +2738,55 @@ static void do_extract_cd(parameters_map &params)
27362738
output_toc_file->printf("CD_ROM\n\n\n");
27372739
}
27382740

2741+
if (cdrom->is_gdrom() && mode == MODE_CUEBIN)
2742+
{
2743+
// modify TOC to match Redump cue/bin format as best as possible
2744+
cdrom_file::toc *trackinfo = (cdrom_file::toc*)&toc;
2745+
2746+
// TOSEC GDI-based CHDs have the padframes field set to non-0 where the pregaps for the next track would be
2747+
const bool has_physical_pregap = trackinfo->tracks[0].padframes == 0;
2748+
2749+
for (int tracknum = 1; tracknum < toc.numtrks; tracknum++)
2750+
{
2751+
// pgdatasize should never be set in GD-ROMs currently, so if it is set then assume the TOC has proper pregap values
2752+
if (trackinfo->tracks[tracknum].pgdatasize != 0)
2753+
break;
2754+
2755+
// don't adjust the first track of the single-density and high-density areas
2756+
if (toc.tracks[tracknum].physframeofs == 45000)
2757+
continue;
2758+
2759+
if (!has_physical_pregap)
2760+
{
2761+
// NOTE: This will generate a cue with PREGAP commands instead of INDEX 00 because the pregap data isn't baked into the bins
2762+
trackinfo->tracks[tracknum].pregap += trackinfo->tracks[tracknum-1].padframes;
2763+
2764+
if (tracknum + 1 >= toc.numtrks && toc.tracks[tracknum].trktype != cdrom_file::CD_TRACK_AUDIO)
2765+
{
2766+
// TODO: These 75 frames are actually included at the end of the previous track so should be written
2767+
// It's currently not possible to format it as expected without hacky code because the 150 pregap for the last track
2768+
// is sandwiched between these 75 frames and the actual track data.
2769+
// The 75 frames seems to normally be 0s so this should be ok for now until a use case is found.
2770+
trackinfo->tracks[tracknum-1].frames -= 75;
2771+
trackinfo->tracks[tracknum].pregap += 75;
2772+
}
2773+
}
2774+
else
2775+
{
2776+
int curextra = 150; // 00:02:00
2777+
if (tracknum + 1 >= toc.numtrks && toc.tracks[tracknum+1].trktype != cdrom_file::CD_TRACK_AUDIO)
2778+
curextra += 75; // 00:01:00, special case when last track is data
2779+
2780+
trackinfo->tracks[tracknum-1].padframes = curextra;
2781+
2782+
trackinfo->tracks[tracknum].pregap += curextra;
2783+
trackinfo->tracks[tracknum].splitframes = curextra;
2784+
trackinfo->tracks[tracknum].pgdatasize = trackinfo->tracks[tracknum].datasize;
2785+
trackinfo->tracks[tracknum].pgtype = trackinfo->tracks[tracknum].trktype;
2786+
}
2787+
}
2788+
}
2789+
27392790
// iterate over tracks and copy all data
27402791
uint64_t totaloutputoffs = 0;
27412792
uint64_t outputoffs = 0;
@@ -2766,6 +2817,14 @@ static void do_extract_cd(parameters_map &params)
27662817
output_bin_filenames.push_back(trackbin_name);
27672818
}
27682819

2820+
if (cdrom->is_gdrom() && mode == MODE_CUEBIN)
2821+
{
2822+
if (tracknum == 0)
2823+
output_toc_file->printf("REM SINGLE-DENSITY AREA\n");
2824+
else if (toc.tracks[tracknum].physframeofs == 45000)
2825+
output_toc_file->printf("REM HIGH-DENSITY AREA\n");
2826+
}
2827+
27692828
// output the metadata about the track to the TOC file
27702829
const cdrom_file::track_info &trackinfo = toc.tracks[tracknum];
27712830
output_track_metadata(mode, *output_toc_file, tracknum, trackinfo, std::string(core_filename_extract_base(trackbin_name)), discoffs, outputoffs);
@@ -2785,31 +2844,44 @@ static void do_extract_cd(parameters_map &params)
27852844

27862845
// now read and output the actual data
27872846
uint32_t bufferoffs = 0;
2788-
uint32_t actualframes = trackinfo.frames - trackinfo.padframes;
2847+
uint32_t actualframes = trackinfo.frames - trackinfo.padframes + trackinfo.splitframes;
27892848
for (uint32_t frame = 0; frame < actualframes; frame++)
27902849
{
27912850
progress(false, "Extracting, %.1f%% complete... \r", 100.0 * double(totaloutputoffs + outputoffs) / double(total_bytes));
27922851

2852+
int trk, frameofs;
2853+
if (tracknum > 0 && frame < trackinfo.splitframes)
2854+
{
2855+
// pull data from previous track, the reverse of how splitframes is used when making the GD-ROM CHDs
2856+
trk = tracknum - 1;
2857+
frameofs = toc.tracks[trk].frames - trackinfo.splitframes + frame;
2858+
}
2859+
else
2860+
{
2861+
trk = tracknum;
2862+
frameofs = frame - trackinfo.splitframes;
2863+
}
2864+
27932865
// read the data
2794-
cdrom->read_data(cdrom->get_track_start_phys(tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype, true);
2866+
cdrom->read_data(cdrom->get_track_start_phys(trk) + frameofs, &buffer[bufferoffs], toc.tracks[trk].trktype, true);
27952867

27962868
// for CDRWin and GDI audio tracks must be reversed
27972869
// in the case of GDI and CHD version < 5 we assuming source CHD image is GDROM so audio tracks is already reversed
2798-
if (((mode == MODE_GDI && input_chd.version() > 4) || (mode == MODE_CUEBIN)) && (trackinfo.trktype == cdrom_file::CD_TRACK_AUDIO))
2799-
for (int swapindex = 0; swapindex < trackinfo.datasize; swapindex += 2)
2870+
if (((mode == MODE_GDI && input_chd.version() > 4) || (mode == MODE_CUEBIN)) && (toc.tracks[trk].trktype == cdrom_file::CD_TRACK_AUDIO))
2871+
for (int swapindex = 0; swapindex < toc.tracks[trk].datasize; swapindex += 2)
28002872
{
28012873
uint8_t swaptemp = buffer[bufferoffs + swapindex];
28022874
buffer[bufferoffs + swapindex] = buffer[bufferoffs + swapindex + 1];
28032875
buffer[bufferoffs + swapindex + 1] = swaptemp;
28042876
}
2805-
bufferoffs += trackinfo.datasize;
2877+
bufferoffs += toc.tracks[trk].datasize;
28062878
discoffs++;
28072879

28082880
// read the subcode data
2809-
if (trackinfo.subtype != cdrom_file::CD_SUB_NONE && (mode == MODE_NORMAL))
2881+
if (toc.tracks[trk].subtype != cdrom_file::CD_SUB_NONE && (mode == MODE_NORMAL))
28102882
{
2811-
cdrom->read_subcode(cdrom->get_track_start_phys(tracknum) + frame, &buffer[bufferoffs], true);
2812-
bufferoffs += trackinfo.subsize;
2883+
cdrom->read_subcode(cdrom->get_track_start_phys(trk) + frameofs, &buffer[bufferoffs], true);
2884+
bufferoffs += toc.tracks[trk].subsize;
28132885
}
28142886

28152887
// write it out if we need to
@@ -2824,28 +2896,6 @@ static void do_extract_cd(parameters_map &params)
28242896
}
28252897
}
28262898

2827-
if (cdrom->is_gdrom() && mode == MODE_CUEBIN && trackinfo.padframes > 0)
2828-
{
2829-
uint32_t padframes = trackinfo.padframes;
2830-
2831-
// don't write the pad frames between the end of the single density area and start of the high density area
2832-
if (tracknum+1 < toc.numtrks && toc.tracks[tracknum+1].physframeofs == 45000)
2833-
padframes = 0;
2834-
2835-
bufferoffs = 0;
2836-
std::fill(buffer.begin(), buffer.end(), 0);
2837-
2838-
while (bufferoffs < padframes)
2839-
{
2840-
auto const [writerr, byteswritten] = write(*output_bin_file, &buffer[0], output_frame_size);
2841-
if (writerr)
2842-
report_error(1, "Error writing pad data to file (%s): %s\n", *output_file_str->second, "Write error");
2843-
bufferoffs++;
2844-
}
2845-
2846-
outputoffs += output_frame_size * padframes;
2847-
}
2848-
28492899
discoffs += trackinfo.padframes;
28502900
}
28512901

0 commit comments

Comments
 (0)