Perform some minor house-keeping in the mp3 and seek handler
- Cleanup some types where precision is lost. - Explicitly cast between types (fixes all effc++ warnings) - Simplify lossy and cast-heavy floating-point coversions with ceil_divide
This commit is contained in:
parent
fc9711c932
commit
9828f2d912
3 changed files with 54 additions and 40 deletions
|
@ -24,8 +24,9 @@
|
|||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <SDL.h> // provides: SDL_malloc, SDL_realloc, SDL_free, SDL_memcpy, and SDL_memset
|
||||
#include <support.h>
|
||||
|
||||
#define DR_MP3_IMPLEMENTATION
|
||||
#define DR_MP3_NO_STDIO 1
|
||||
#define DRMP3_FREE(p) SDL_free((p))
|
||||
|
@ -108,31 +109,30 @@ static Uint32 MP3_read(Sound_Sample* const sample, void* buffer, Uint32 desired_
|
|||
static_cast<drmp3_int16*>(buffer)));
|
||||
} /* MP3_read */
|
||||
|
||||
static Sint32 MP3_open(Sound_Sample* const sample, const char* const ext)
|
||||
static int32_t MP3_open(Sound_Sample* const sample, const char* const ext)
|
||||
{
|
||||
(void) ext; // deliberately unused
|
||||
Sound_SampleInternal* const internal = static_cast<Sound_SampleInternal*>(sample->opaque);
|
||||
Sint32 result(0); // assume failure until proven otherwise
|
||||
bool result = false; // assume failure until proven otherwise
|
||||
mp3_t* p_mp3 = (mp3_t*) SDL_calloc(1, sizeof (mp3_t));
|
||||
if (p_mp3 != nullptr) {
|
||||
if (p_mp3) {
|
||||
p_mp3->p_dr = (drmp3*) SDL_calloc(1, sizeof (drmp3));
|
||||
if (p_mp3->p_dr != nullptr) {
|
||||
result = drmp3_init(p_mp3->p_dr, mp3_read, mp3_seek, sample, nullptr, nullptr);
|
||||
if (result == DRMP3_TRUE) {
|
||||
if (p_mp3->p_dr) {
|
||||
if (drmp3_init(p_mp3->p_dr, mp3_read, mp3_seek, sample, nullptr, nullptr) == DRMP3_TRUE) {
|
||||
SNDDBG(("MP3: Accepting data stream.\n"));
|
||||
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
|
||||
sample->actual.channels = p_mp3->p_dr->channels;
|
||||
sample->actual.channels = static_cast<uint8_t>(p_mp3->p_dr->channels);
|
||||
sample->actual.rate = p_mp3->p_dr->sampleRate;
|
||||
sample->actual.format = AUDIO_S16SYS; // returns native byte-order based on architecture
|
||||
const Uint64 num_frames = populate_seek_points(internal->rw, p_mp3, MP3_FAST_SEEK_FILENAME); // status will be 0 or pcm_frame_count
|
||||
if (num_frames != 0) {
|
||||
const unsigned int rate = p_mp3->p_dr->sampleRate;
|
||||
internal->total_time = ( static_cast<Sint32>(num_frames) / rate) * 1000;
|
||||
internal->total_time += (num_frames % rate) * 1000 / rate;
|
||||
result = 1;
|
||||
} else {
|
||||
internal->total_time = -1;
|
||||
}
|
||||
sample->actual.format = AUDIO_S16SYS; // native byte-order based on architecture
|
||||
|
||||
// frame count is agnostic of sample size and number of channels
|
||||
const uint64_t num_frames =
|
||||
populate_seek_points(internal->rw, p_mp3, MP3_FAST_SEEK_FILENAME, result);
|
||||
|
||||
// total_time needs milliseconds
|
||||
internal->total_time = (num_frames != 0) ?
|
||||
static_cast<int32_t>(ceil_divide(num_frames * 1000u, sample->actual.rate))
|
||||
: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,11 +141,12 @@ static Sint32 MP3_open(Sound_Sample* const sample, const char* const ext)
|
|||
internal->decoder_private = p_mp3;
|
||||
|
||||
// if anything went wrong then tear down our private structure
|
||||
if (result == 0) {
|
||||
if (!result) {
|
||||
SNDDBG(("MP3: Failed to open the data stream.\n"));
|
||||
MP3_close(sample);
|
||||
}
|
||||
|
||||
return result;
|
||||
return static_cast<int32_t>(result);
|
||||
} /* MP3_open */
|
||||
|
||||
static Sint32 MP3_rewind(Sound_Sample* const sample)
|
||||
|
@ -159,9 +160,9 @@ static Sint32 MP3_seek(Sound_Sample* const sample, const Uint32 ms)
|
|||
{
|
||||
Sound_SampleInternal* const internal = static_cast<Sound_SampleInternal*>(sample->opaque);
|
||||
mp3_t* p_mp3 = static_cast<mp3_t*>(internal->decoder_private);
|
||||
const float frames_per_ms = sample->actual.rate / 1000.0f;
|
||||
const drmp3_uint64 frame_offset = static_cast<drmp3_uint64>(frames_per_ms) * ms;
|
||||
const Sint32 result = drmp3_seek_to_pcm_frame(p_mp3->p_dr, frame_offset);
|
||||
const uint64_t sample_rate = sample->actual.rate;
|
||||
const drmp3_uint64 pcm_frame = ceil_divide(sample_rate * ms, 1000u);
|
||||
const drmp3_bool32 result = drmp3_seek_to_pcm_frame(p_mp3->p_dr, pcm_frame);
|
||||
return (result == DRMP3_TRUE);
|
||||
} /* MP3_seek */
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#include <map>
|
||||
|
||||
// Local headers
|
||||
#include "support.h"
|
||||
#include "xxhash.h"
|
||||
// #include "../../../include/logging.h"
|
||||
#include "mp3_seek_table.h"
|
||||
|
@ -99,13 +100,13 @@ using std::ofstream;
|
|||
// time point. The trade-off is as follows:
|
||||
// - a large number means slower in-game seeking but a smaller fast-seek file.
|
||||
// - a smaller numbers (below 10) results in fast seeks on slow hardware.
|
||||
#define FRAMES_PER_SEEK_POINT 7
|
||||
#define FRAMES_PER_SEEK_POINT 7u
|
||||
|
||||
// Returns the size of a file in bytes (if valid), otherwise 0
|
||||
size_t get_file_size(const char* filename) {
|
||||
uint64_t get_file_size(const char* filename) {
|
||||
struct stat stat_buf;
|
||||
int rc = stat(filename, &stat_buf);
|
||||
return rc == 0 ? stat_buf.st_size : -1;
|
||||
return rc == 0 ? static_cast<uint64_t>(stat_buf.st_size) : 0u;
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,7 +148,7 @@ Uint64 calculate_stream_hash(struct SDL_RWops* const context) {
|
|||
// have the same trailing 32KB of content. The different seeds will produce
|
||||
// unique hashes.
|
||||
XXH64_state_t* const state = XXH64_createState();
|
||||
const Uint64 seed = stream_size;
|
||||
const uint64_t seed = static_cast<uint64_t>(stream_size);
|
||||
XXH64_reset(state, seed);
|
||||
|
||||
while (total_bytes_read < static_cast<size_t>(tail_size)) {
|
||||
|
@ -186,9 +187,9 @@ Uint64 generate_new_seek_points(const char* filename,
|
|||
drmp3_uint64 pcm_frame_count(0);
|
||||
|
||||
// Get the number of compressed MP3 frames and the number of uncompressed PCM frames.
|
||||
drmp3_bool8 result = drmp3_get_mp3_and_pcm_frame_count(p_dr,
|
||||
&mp3_frame_count,
|
||||
&pcm_frame_count);
|
||||
drmp3_bool32 result = drmp3_get_mp3_and_pcm_frame_count(p_dr,
|
||||
&mp3_frame_count,
|
||||
&pcm_frame_count);
|
||||
|
||||
if ( result != DRMP3_TRUE
|
||||
|| mp3_frame_count < FRAMES_PER_SEEK_POINT
|
||||
|
@ -202,11 +203,13 @@ Uint64 generate_new_seek_points(const char* filename,
|
|||
// the decoded PCM times.
|
||||
// We also take into account the desired number of "FRAMES_PER_SEEK_POINT",
|
||||
// which is defined above.
|
||||
drmp3_uint32 num_seek_points = static_cast<drmp3_uint32>(mp3_frame_count)/FRAMES_PER_SEEK_POINT + 1;
|
||||
drmp3_uint32 num_seek_points = static_cast<drmp3_uint32>
|
||||
(ceil_divide(mp3_frame_count, FRAMES_PER_SEEK_POINT));
|
||||
|
||||
seek_points_vector.resize(num_seek_points);
|
||||
result = drmp3_calculate_seek_points(p_dr,
|
||||
&num_seek_points,
|
||||
reinterpret_cast<drmp3_seek_point*>(seek_points_vector.data()));
|
||||
&num_seek_points,
|
||||
reinterpret_cast<drmp3_seek_point*>(seek_points_vector.data()));
|
||||
|
||||
if (result != DRMP3_TRUE || num_seek_points == 0) {
|
||||
// LOG_MSG("MP3: failed to calculate sufficient seek points for stream");
|
||||
|
@ -300,7 +303,13 @@ Uint64 load_existing_seek_points(const char* filename,
|
|||
// attempting to read it from the fast-seek file and (if it can't be read for any reason), it
|
||||
// calculates new data. It makes use of the above two functions.
|
||||
//
|
||||
Uint64 populate_seek_points(struct SDL_RWops* const context, mp3_t* p_mp3, const char* seektable_filename) {
|
||||
uint64_t populate_seek_points(struct SDL_RWops* const context,
|
||||
mp3_t* p_mp3,
|
||||
const char* seektable_filename,
|
||||
bool &result) {
|
||||
|
||||
// assume failure until proven otherwise
|
||||
result = false;
|
||||
|
||||
// Calculate the stream's xxHash value.
|
||||
Uint64 stream_hash = calculate_stream_hash(context);
|
||||
|
@ -334,12 +343,13 @@ Uint64 populate_seek_points(struct SDL_RWops* const context, mp3_t* p_mp3, const
|
|||
|
||||
// Finally, regardless of which scenario succeeded above, we now have our seek points!
|
||||
// We bind our seek points to the dr_mp3 object which will be used for fast seeking.
|
||||
drmp3_bool8 result = drmp3_bind_seek_table(p_mp3->p_dr,
|
||||
p_mp3->seek_points_vector.size(),
|
||||
reinterpret_cast<drmp3_seek_point*>(p_mp3->seek_points_vector.data()));
|
||||
if (result != DRMP3_TRUE) {
|
||||
// LOG_MSG("MP3: could not bind the seek points to the dr_mp3 object");
|
||||
if(drmp3_bind_seek_table(p_mp3->p_dr,
|
||||
static_cast<uint32_t>(p_mp3->seek_points_vector.size()),
|
||||
reinterpret_cast<drmp3_seek_point*>(p_mp3->seek_points_vector.data()))
|
||||
!= DRMP3_TRUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = true;
|
||||
return pcm_frame_count;
|
||||
}
|
||||
|
|
|
@ -54,4 +54,7 @@ struct mp3_t {
|
|||
std::vector<drmp3_seek_point_serial> seek_points_vector;
|
||||
};
|
||||
|
||||
Uint64 populate_seek_points(struct SDL_RWops* const context, mp3_t* p_mp3, const char* seektable_filename);
|
||||
uint64_t populate_seek_points(struct SDL_RWops* const context,
|
||||
mp3_t* p_mp3,
|
||||
const char* seektable_filename,
|
||||
bool &result);
|
||||
|
|
Loading…
Add table
Reference in a new issue