Add a signed integer ceiling divide function
This commit is contained in:
parent
be643d66b1
commit
08c6fc10c1
5 changed files with 31 additions and 18 deletions
|
@ -38,15 +38,22 @@
|
|||
// Works with both \ and / directory delimeters.
|
||||
std::string get_basename(const std::string& filename);
|
||||
|
||||
// Unsigned integer division with ceiling
|
||||
// There is no risk of signed types being used here because the template is unsigned
|
||||
// Unsigned-only integer division with ceiling
|
||||
template<typename T1, class = typename std::enable_if<std::is_unsigned<T1>::value>::type,
|
||||
typename T2, class = typename std::enable_if<std::is_unsigned<T2>::value>::type>
|
||||
inline const T1 ceil_divide(const T1 x, const T2 y) noexcept {
|
||||
inline const T1 ceil_udivide(const T1 x, const T2 y) noexcept {
|
||||
return (x != 0) ? 1 + ((x - 1) / y) : 0;
|
||||
// https://stackoverflow.com/a/2745086
|
||||
}
|
||||
|
||||
// Signed-only integer division with ceiling
|
||||
template<typename T1, class = typename std::enable_if<std::is_signed<T1>::value>::type,
|
||||
typename T2, class = typename std::enable_if<std::is_signed<T2>::value>::type>
|
||||
inline const T1 ceil_sdivide(const T1 x, const T2 y) noexcept {
|
||||
return x / y + (((x < 0) ^ (y > 0)) && (x % y));
|
||||
// https://stackoverflow.com/a/33790603
|
||||
}
|
||||
|
||||
// Include a message in assert, similar to static_assert:
|
||||
#define assertm(exp, msg) assert(((void)msg, exp))
|
||||
// Use (void) to silent unused warnings.
|
||||
|
|
|
@ -142,7 +142,7 @@ uint32_t CDROM_Interface_Image::BinaryFile::decode(int16_t *buffer,
|
|||
const uint32_t bytes_read = static_cast<uint32_t>(file->gcount());
|
||||
|
||||
// Return the number of decoded Redbook frames
|
||||
return ceil_divide(bytes_read, BYTES_PER_REDBOOK_PCM_FRAME);
|
||||
return ceil_udivide(bytes_read, BYTES_PER_REDBOOK_PCM_FRAME);
|
||||
}
|
||||
|
||||
CDROM_Interface_Image::AudioFile::AudioFile(const char *filename, bool &error)
|
||||
|
@ -201,8 +201,8 @@ bool CDROM_Interface_Image::AudioFile::seek(const uint32_t requested_pos)
|
|||
|
||||
// Convert the position from a byte offset to time offset, in milliseconds.
|
||||
const uint32_t ms_per_s = 1000;
|
||||
const uint32_t pos_in_frames = ceil_divide(requested_pos, BYTES_PER_RAW_REDBOOK_FRAME);
|
||||
const uint32_t pos_in_ms = ceil_divide(pos_in_frames * ms_per_s, REDBOOK_FRAMES_PER_SECOND);
|
||||
const uint32_t pos_in_frames = ceil_udivide(requested_pos, BYTES_PER_RAW_REDBOOK_FRAME);
|
||||
const uint32_t pos_in_ms = ceil_udivide(pos_in_frames * ms_per_s, REDBOOK_FRAMES_PER_SECOND);
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
|
@ -281,7 +281,7 @@ bool CDROM_Interface_Image::AudioFile::read(uint8_t *buffer,
|
|||
// Setup characteristics about our track and the request
|
||||
const uint8_t channels = getChannels();
|
||||
const uint8_t bytes_per_frame = channels * REDBOOK_BPS;
|
||||
const uint32_t requested_frames = ceil_divide(requested_bytes, BYTES_PER_REDBOOK_PCM_FRAME);
|
||||
const uint32_t requested_frames = ceil_udivide(requested_bytes, BYTES_PER_REDBOOK_PCM_FRAME);
|
||||
|
||||
uint32_t decoded_bytes = 0;
|
||||
uint32_t decoded_frames = 0;
|
||||
|
@ -537,7 +537,7 @@ bool CDROM_Interface_Image::GetAudioSub(unsigned char& attr,
|
|||
const auto track_file = player.trackFile.lock();
|
||||
if (track_file) {
|
||||
const uint32_t sample_rate = track_file->getRate();
|
||||
const uint32_t played_frames = ceil_divide(player.playedTrackFrames
|
||||
const uint32_t played_frames = ceil_udivide(player.playedTrackFrames
|
||||
* REDBOOK_FRAMES_PER_SECOND, sample_rate);
|
||||
absolute_sector = player.startSector + played_frames;
|
||||
track_iter current_track = GetTrack(absolute_sector);
|
||||
|
@ -689,7 +689,7 @@ bool CDROM_Interface_Image::PlayAudioSector(const uint32_t start, uint32_t len)
|
|||
* 64-bit.
|
||||
*/
|
||||
player.playedTrackFrames = 0;
|
||||
player.totalTrackFrames = ceil_divide(track_rate * player.totalRedbookFrames,
|
||||
player.totalTrackFrames = ceil_udivide(track_rate * player.totalRedbookFrames,
|
||||
REDBOOK_FRAMES_PER_SECOND);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -818,7 +818,7 @@ bool CDROM_Interface_Image::ReadSectors(PhysPt buffer,
|
|||
"%s after %u sectors (%u bytes)",
|
||||
num, raw ? "raw" : "cooked", sector,
|
||||
success ? "Succeeded" : "Failed",
|
||||
ceil_divide(bytes_read, sectorSize), bytes_read);
|
||||
ceil_udivide(bytes_read, sectorSize), bytes_read);
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ static int32_t MP3_open(Sound_Sample* const sample, const char* const ext)
|
|||
|
||||
// total_time needs milliseconds
|
||||
internal->total_time = (num_frames != 0) ?
|
||||
static_cast<int32_t>(ceil_divide(num_frames * 1000u, sample->actual.rate))
|
||||
static_cast<int32_t>(ceil_udivide(num_frames * 1000u, sample->actual.rate))
|
||||
: -1;
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ 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 uint64_t sample_rate = sample->actual.rate;
|
||||
const drmp3_uint64 pcm_frame = ceil_divide(sample_rate * ms, 1000u);
|
||||
const drmp3_uint64 pcm_frame = ceil_udivide(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 */
|
||||
|
|
|
@ -204,7 +204,7 @@ Uint64 generate_new_seek_points(const char* filename,
|
|||
// 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>
|
||||
(ceil_divide(mp3_frame_count, FRAMES_PER_SEEK_POINT));
|
||||
(ceil_udivide(mp3_frame_count, FRAMES_PER_SEEK_POINT));
|
||||
|
||||
seek_points_vector.resize(num_seek_points);
|
||||
result = drmp3_calculate_seek_points(p_dr,
|
||||
|
|
|
@ -257,14 +257,20 @@ static int32_t opus_open(Sound_Sample * sample, const char * ext)
|
|||
const OpusHead* oh = op_head(of, -1);
|
||||
output_opus_info(of, oh);
|
||||
|
||||
// Populate track properties
|
||||
sample->actual.rate = OPUS_SAMPLE_RATE;
|
||||
sample->actual.channels = static_cast<Uint8>(oh->channel_count);
|
||||
sample->flags = op_seekable(of) ? SOUND_SAMPLEFLAG_CANSEEK: 0;
|
||||
sample->actual.format = AUDIO_S16SYS;
|
||||
int64_t pcm_result = op_pcm_total(of, -1); // If positive, holds total PCM samples
|
||||
internal->total_time = pcm_result == OP_EINVAL ? -1 : // total milliseconds in the stream
|
||||
static_cast<int32_t>
|
||||
(ceil_divide(static_cast<uint64_t>(pcm_result), OPUS_SAMPLE_RATE_PER_MS));
|
||||
|
||||
// Populate the track's duration in milliseconds (or -1 if bad)
|
||||
const auto pcm_result = static_cast<int32_t>(op_pcm_total(of, -1));
|
||||
if (pcm_result == OP_EINVAL)
|
||||
internal->total_time = -1;
|
||||
else {
|
||||
constexpr auto frames_per_ms = static_cast<int32_t>(OPUS_SAMPLE_RATE_PER_MS);
|
||||
internal->total_time = ceil_sdivide(pcm_result, frames_per_ms);
|
||||
}
|
||||
return rcode;
|
||||
} /* opus_open */
|
||||
|
||||
|
@ -310,7 +316,7 @@ static uint32_t opus_read(Sound_Sample * sample, void * buffer, uint32_t request
|
|||
}
|
||||
|
||||
// Finally, we return the number of frames decoded
|
||||
const uint32_t decoded_frames = ceil_divide(total_decoded_samples, channels);
|
||||
const uint32_t decoded_frames = ceil_udivide(total_decoded_samples, channels);
|
||||
return decoded_frames;
|
||||
} /* opus_read */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue