In the previous code, if the game attempted to seek beyond the track
length, or if a "seek & read" would add up to going beyond the
end-of-the-track, the code would pass those requests to the underlying
codecs to handle (and reject with a corresponding error code).
This PR moves those checks up into the CDROM CD-DA code, and will
short-circuit them. Illegal seeks won't be attempted, however the usual
negative return code will still be passed to the game just like before.
Likewise, reads beyond the end will be pruned so they will get as much
audio as possible, without asking the codec for extra.
The commit refines several types to their logical use-cases.
For example, a CDROM will at-most contain 400,000 sectors and be
less than 1B bytes in size. Likewise, both are 'physical'
quantities and this should always be zero-or-greater
(therefore, uint32_t is used).
Fortunately, there are almost no cases where these values are
overloaded to mean something else (ie: negative return codes to
indicate failure).
Besides eliminating many implicit cast warnings, differing-signed
comparison warnings, and overflowable type-cast warnings, the
more correct use of types helps logically bound expectations of the
values they contain, which should improve maintainability.
1. Moves the mutex and mixer channel members to unique pointers
2. Moves the trackFile to a weak pointer
3. Move member initialization to the class definition
This class still retains a raw *cd member, however fixing this
ripples up to the array of [26] CD images, and across more
code that generically deals with mount points; so this work
remains to do.
Unmounting single binary-file CDROM images would result in a
crash as flagged by @dreamer_ in issue #112, who noted that
multiple tracks point to the same TrackFile (track.file field).
During destruction, the pre-C++11 code used a temporary
`TrackFile* last` variable to store the currently deleted
track.file's value and only delete the next track.file if it's
not equal to `last`. The result of this is that only the
first-encountered track.file was deleted and all subsequent
and back-to-back duplicate track.file values were left as-is.
This commit replaces the Track object's 'file' member pointer
with a shared_ptr, which effectively does the same thing by
only deleting the last reference.
The shared_ptr simplifies some error-cases where we previously
had to delete the Track.file allocation, but can now simply
let the Track object go out-of-scope and let the shared_ptr
delete it's managed object (if it has one).
This removes a feature of mounting physical CD-ROMs in DOSBox.
SDL 2.0 removed SDL_cdrom from supported libraries, so to bring this
code back, either the functionality will need to be reimplemented or
SDL_cdrom code modernized for SDL 2.0, and bundled with the repo (the
same way SDL_sound is already bundled).
Also, remove all traces of these interfaces from user manual (README
file) and man page (docs/dosbox.1).
MCI (Media Control Interface) was a primary Windows interface. Code
comments and documentation claimed, that it's only for "NT, 2000, XP"
but the code was enabled for Windows 2000 or later (version > 4.0).
DX (Digital audio eXtraction (?)) could be forced on any Windows with
autodetection working only on Vista and Windows 7 (code was disabled for
Windows 8 or later - probably unintentionally).
DIO used DeviceIoControl interface and Windows-specific ioctl calls.
All 3 interfaces depend on SDL and SDL_cdrom functionality to work.
SDL_cdrom 1.2 implementation uses MCI on Windows to provide the same
functionality.
ASPI was supported by Microsoft only for Windows 95, 98 and, ME.
Adaptec supported this interface going forward for Windows NT, 2000,
and XP (32-bit only).
Cleanup before replacing SDL1.2 with SDL2.
OS/2 support was introduced in DOSBox in March 2006. OS/2 reached EOL
in December 2006.
As of 2019, OS/2 is being continued by proprietary 32-bit only ArcaOS,
although there is no official SDL2 support, despite pledges from SDL2
maintainers.
Issue reported by Dagar and Pr3tty F1y, and confirmed as a bug by ripsaw8080.
Thank you!
This fixes the GoG release of Betrayal at Krondor which (either due to CD mastering
issues or a faulty rip), requests playback of a given track at the tail end
of the prior track.
In debugging and performing this fix, many debug messages were improved as well
as making some small small code adjustments, such as using iterators to point to
individual tracks (track->attribute) instead of using the tracks array
(tracks[track -1].attribute).
Thanks to @ripsaw8080 for insight into CD-DA channel mapping,
@hail-to-the-ryzen for testing and flagging a position-tracking bug,
and @dreamer_ for guidance and code review.
The CD-DA volume and channel mapping loops were moved to generic mixer
calls and no longer require a pre-processing loop:
- Application-controlled CD-DA volume adjustment is now applied using
an existing mixer volume scalar that was previously unused by the
CD-DA code.
- Mapping of CD-DA left and right channels is now applied at the tail
end of the mixer's sample ingest sequence.
The following have been removed:
- The CD-DA callback chunk-wise circular buffer
- The decode buffers in the Opus and MP3 decoders
- The decode buffer and conversion buffers in SDL_Sound
These removals and API changes allow the image player's buffer
to be passed-through ultimately to the audio codec, skipping multiple
intermediate buffers.
Runtime improvements:
- Replaces the existing audio callback routine with an efficient chunked
circular-buffer audio reader
- Replaces assumptions that all audio tracks are 44.1 kHz & stereo.
The mixer is now fed data at the actual compressed track's rate and
channel count
- Eliminates all SDL locks in the audio code in favour of mixer state
control
- Queries the codec for track-length instead of using hundreds of
iterative decimating seeks to determine track length (loading
a 99-track CUE now takes 0.1 user-seconds versus 3+ seconds
previously)
- Seeks are performed within the already-decoded buffer (for all
codecs) instead of discarding and re-running the decode sequence
- SDL_Sound's buffer-size is now set once and never resized, which
eliminates repeated re-malloc'ing in the library
- Only one seek is performed per-playback sequence followed by
sequential decodes, similar to a physical CDROM (The baseline dosbox
performs a seek for every 2352-bytes of uncompressed audio)
- The DOSBox mixer is now only active during playback sequences and
fully dormant otherwise (baseline dosbox instead performs hundreds of
calls/second with empty data)
- When using Opus audio tracks, and if your dosbox.conf [mixer]
rate=48000, then you will (very likely) achieve sample-exact
unadulterated pass-through along your entire audio chain from the
decoder, to DOSBox, to your operating system's software mixer,
to your sound card driver, to your sound card, to your speakers,
or to your digital receiver / USB speakers/headphones / or HDMI
TV/screen. This is because almost all modern hardware DACs use
a native sample rate of 48000
Source-level maintenance improvements:
- It strips all pre-processor #ifdef branching for SDL_Sound from
the code
- Fixes all codec compiler warnings (in the modified files); builds
have been tested with GCC 4 to 10, Clang 6 to 10, and MSVC 14
- Tested on Linux, macOS (Xcode), and Windows (MinGW MSYS 1.0)
operating systems
- Tested on i386, x86_64, ARM, and PowerPC (big-endian) architectures
Macros FRAMES_TO_MSF and MSF_TO_FRAMES come from SDL_cdrom library.
SDL_cdrom was removed from SDL2 and these macros are used also in code
not directly related to SDL_cdrom library, so a replacement is needed.
Turns out output pointer type is different on Windows (int*) than it is on
Linux (unsigned char*); given choice between using void* for parameters and
a template function, I prefer template.