Commit 31589551 authored by Max Kellermann's avatar Max Kellermann

TagHandler: pass SongTime to duration()

parent d9d97bd1
...@@ -102,7 +102,7 @@ adplug_scan_file(Path path_fs, ...@@ -102,7 +102,7 @@ adplug_scan_file(Path path_fs,
return false; return false;
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
player->songlength() / 1000); SongTime::FromMS(player->songlength()));
if (handler->tag != nullptr) { if (handler->tag != nullptr) {
adplug_scan_tag(TAG_TITLE, player->gettitle(), adplug_scan_tag(TAG_TITLE, player->gettitle(),
......
...@@ -244,19 +244,19 @@ audiofile_stream_decode(Decoder &decoder, InputStream &is) ...@@ -244,19 +244,19 @@ audiofile_stream_decode(Decoder &decoder, InputStream &is)
} }
gcc_pure gcc_pure
static int static SignedSongTime
audiofile_get_duration(InputStream &is) audiofile_get_duration(InputStream &is)
{ {
if (!is.IsSeekable() || !is.KnownSize()) if (!is.IsSeekable() || !is.KnownSize())
return -1; return SignedSongTime::Negative();
AudioFileInputStream afis{nullptr, is}; AudioFileInputStream afis{nullptr, is};
AFvirtualfile *vf = setup_virtual_fops(afis); AFvirtualfile *vf = setup_virtual_fops(afis);
AFfilehandle fh = afOpenVirtualFile(vf, "r", nullptr); AFfilehandle fh = afOpenVirtualFile(vf, "r", nullptr);
if (fh == AF_NULL_FILEHANDLE) if (fh == AF_NULL_FILEHANDLE)
return -1; return SignedSongTime::Negative();
int duration = audiofile_get_duration(fh).RoundS(); const auto duration = audiofile_get_duration(fh);
afCloseFile(fh); afCloseFile(fh);
return duration; return duration;
} }
...@@ -265,11 +265,11 @@ static bool ...@@ -265,11 +265,11 @@ static bool
audiofile_scan_stream(InputStream &is, audiofile_scan_stream(InputStream &is,
const struct tag_handler *handler, void *handler_ctx) const struct tag_handler *handler, void *handler_ctx)
{ {
int total_time = audiofile_get_duration(is); const auto duration = audiofile_get_duration(is);
if (total_time < 0) if (duration.IsNegative())
return false; return false;
tag_handler_invoke_duration(handler, handler_ctx, total_time); tag_handler_invoke_duration(handler, handler_ctx, SongTime(duration));
return true; return true;
} }
......
...@@ -474,8 +474,9 @@ dsdiff_scan_stream(InputStream &is, ...@@ -474,8 +474,9 @@ dsdiff_scan_stream(InputStream &is,
return false; return false;
/* calculate song time and add as tag */ /* calculate song time and add as tag */
unsigned songtime = ((metadata.chunk_size / metadata.channels) * 8) / uint64_t n_frames = metadata.chunk_size / audio_format.channels;
metadata.sample_rate; auto songtime = SongTime::FromScale<uint64_t>(n_frames,
audio_format.sample_rate);
tag_handler_invoke_duration(handler, handler_ctx, songtime); tag_handler_invoke_duration(handler, handler_ctx, songtime);
/* Read additional metadata and created tags if available */ /* Read additional metadata and created tags if available */
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include <string.h> #include <string.h>
static constexpr unsigned DSF_BLOCK_SIZE = 4096; static constexpr unsigned DSF_BLOCK_SIZE = 4096;
static constexpr unsigned DSF_BLOCK_BITS = DSF_BLOCK_SIZE * 8;
struct DsfMetaData { struct DsfMetaData {
unsigned sample_rate, channels; unsigned sample_rate, channels;
...@@ -348,8 +347,9 @@ dsf_scan_stream(InputStream &is, ...@@ -348,8 +347,9 @@ dsf_scan_stream(InputStream &is,
return false; return false;
/* calculate song time and add as tag */ /* calculate song time and add as tag */
unsigned songtime = (metadata.n_blocks * DSF_BLOCK_BITS) / const auto n_blocks = metadata.n_blocks;
metadata.sample_rate; auto songtime = SongTime::FromScale<uint64_t>(n_blocks * DSF_BLOCK_SIZE,
audio_format.sample_rate);
tag_handler_invoke_duration(handler, handler_ctx, songtime); tag_handler_invoke_duration(handler, handler_ctx, songtime);
#ifdef HAVE_ID3TAG #ifdef HAVE_ID3TAG
......
...@@ -438,11 +438,9 @@ faad_scan_stream(InputStream &is, ...@@ -438,11 +438,9 @@ faad_scan_stream(InputStream &is,
if (!result.first) if (!result.first)
return false; return false;
unsigned duration = result.second.IsNegative() if (!result.second.IsNegative())
? 0 tag_handler_invoke_duration(handler, handler_ctx,
: result.second.RoundS(); SongTime(result.second));
tag_handler_invoke_duration(handler, handler_ctx, duration);
return true; return true;
} }
......
...@@ -609,9 +609,12 @@ ffmpeg_scan_stream(InputStream &is, ...@@ -609,9 +609,12 @@ ffmpeg_scan_stream(InputStream &is,
return false; return false;
} }
if (f->duration != (int64_t)AV_NOPTS_VALUE) if (f->duration != (int64_t)AV_NOPTS_VALUE) {
tag_handler_invoke_duration(handler, handler_ctx, const auto duration =
f->duration / AV_TIME_BASE); SongTime::FromScale<uint64_t>(f->duration,
AV_TIME_BASE);
tag_handler_invoke_duration(handler, handler_ctx, duration);
}
ffmpeg_scan_dictionary(f->metadata, handler, handler_ctx); ffmpeg_scan_dictionary(f->metadata, handler, handler_ctx);
int idx = ffmpeg_find_audio_stream(f); int idx = ffmpeg_find_audio_stream(f);
......
...@@ -179,6 +179,16 @@ flac_scan_comments(const FLAC__StreamMetadata_VorbisComment *comment, ...@@ -179,6 +179,16 @@ flac_scan_comments(const FLAC__StreamMetadata_VorbisComment *comment,
handler, handler_ctx); handler, handler_ctx);
} }
gcc_pure
static inline SongTime
flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info)
{
assert(stream_info->sample_rate > 0);
return SongTime::FromScale<uint64_t>(stream_info->total_samples,
stream_info->sample_rate);
}
void void
flac_scan_metadata(const FLAC__StreamMetadata *block, flac_scan_metadata(const FLAC__StreamMetadata *block,
const struct tag_handler *handler, void *handler_ctx) const struct tag_handler *handler, void *handler_ctx)
......
...@@ -114,15 +114,6 @@ public: ...@@ -114,15 +114,6 @@ public:
struct Tag; struct Tag;
struct ReplayGainInfo; struct ReplayGainInfo;
static inline unsigned
flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info)
{
assert(stream_info->sample_rate > 0);
return (stream_info->total_samples + stream_info->sample_rate - 1) /
stream_info->sample_rate;
}
bool bool
flac_parse_replay_gain(ReplayGainInfo &rgi, flac_parse_replay_gain(ReplayGainInfo &rgi,
const FLAC__StreamMetadata *block); const FLAC__StreamMetadata *block);
......
...@@ -238,7 +238,7 @@ gme_scan_file(Path path_fs, ...@@ -238,7 +238,7 @@ gme_scan_file(Path path_fs,
if (ti->length > 0) if (ti->length > 0)
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
ti->length / 100); SongTime::FromMS(ti->length));
if (ti->song != nullptr) { if (ti->song != nullptr) {
if (gme_track_count(emu) > 1) { if (gme_track_count(emu) > 1) {
......
...@@ -1094,11 +1094,9 @@ mad_decoder_scan_stream(InputStream &is, ...@@ -1094,11 +1094,9 @@ mad_decoder_scan_stream(InputStream &is,
if (!result.first) if (!result.first)
return false; return false;
unsigned duration = result.second.IsNegative() if (!result.second.IsNegative())
? 0 tag_handler_invoke_duration(handler, handler_ctx,
: result.second.RoundS(); SongTime(result.second));
tag_handler_invoke_duration(handler, handler_ctx, duration);
return true; return true;
} }
......
...@@ -184,7 +184,7 @@ modplug_scan_stream(InputStream &is, ...@@ -184,7 +184,7 @@ modplug_scan_stream(InputStream &is,
return false; return false;
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
ModPlug_GetLength(f) / 1000); SongTime::FromMS(ModPlug_GetLength(f)));
const char *title = ModPlug_GetName(f); const char *title = ModPlug_GetName(f);
if (title != nullptr) if (title != nullptr)
......
...@@ -256,8 +256,10 @@ mp4_scan_file(Path path_fs, ...@@ -256,8 +256,10 @@ mp4_scan_file(Path path_fs,
return false; return false;
} }
const MP4Duration dur = MP4GetTrackDuration(handle, id) / const MP4Timestamp scale = MP4GetTrackTimeScale(handle, id);
MP4GetTrackTimeScale(handle, id); const SongTime dur =
SongTime::FromScale<uint64_t>(MP4GetTrackDuration(handle, id),
scale);
tag_handler_invoke_duration(handler, handler_ctx, dur); tag_handler_invoke_duration(handler, handler_ctx, dur);
const MP4Tags* tags = MP4TagsAlloc(); const MP4Tags* tags = MP4TagsAlloc();
......
...@@ -228,7 +228,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is) ...@@ -228,7 +228,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
mpc_demux_exit(demux); mpc_demux_exit(demux);
} }
static float static SignedSongTime
mpcdec_get_file_duration(InputStream &is) mpcdec_get_file_duration(InputStream &is)
{ {
mpc_decoder_data data(is, nullptr); mpc_decoder_data data(is, nullptr);
...@@ -243,25 +243,24 @@ mpcdec_get_file_duration(InputStream &is) ...@@ -243,25 +243,24 @@ mpcdec_get_file_duration(InputStream &is)
mpc_demux *demux = mpc_demux_init(&reader); mpc_demux *demux = mpc_demux_init(&reader);
if (demux == nullptr) if (demux == nullptr)
return -1; return SignedSongTime::Negative();
mpc_streaminfo info; mpc_streaminfo info;
mpc_demux_get_info(demux, &info); mpc_demux_get_info(demux, &info);
mpc_demux_exit(demux); mpc_demux_exit(demux);
return mpc_streaminfo_get_length(&info); return SongTime::FromS(mpc_streaminfo_get_length(&info));
} }
static bool static bool
mpcdec_scan_stream(InputStream &is, mpcdec_scan_stream(InputStream &is,
const struct tag_handler *handler, void *handler_ctx) const struct tag_handler *handler, void *handler_ctx)
{ {
float total_time = mpcdec_get_file_duration(is); const auto duration = mpcdec_get_file_duration(is);
if (duration.IsNegative())
if (total_time < 0)
return false; return false;
tag_handler_invoke_duration(handler, handler_ctx, total_time); tag_handler_invoke_duration(handler, handler_ctx, SongTime(duration));
return true; return true;
} }
......
...@@ -233,8 +233,11 @@ mpd_mpg123_scan_file(Path path_fs, ...@@ -233,8 +233,11 @@ mpd_mpg123_scan_file(Path path_fs,
mpg123_delete(handle); mpg123_delete(handle);
tag_handler_invoke_duration(handler, handler_ctx, const auto duration =
num_samples / audio_format.sample_rate); SongTime::FromScale<uint64_t>(num_samples,
audio_format.sample_rate);
tag_handler_invoke_duration(handler, handler_ctx, duration);
return true; return true;
} }
......
...@@ -441,9 +441,12 @@ mpd_opus_scan_stream(InputStream &is, ...@@ -441,9 +441,12 @@ mpd_opus_scan_stream(InputStream &is,
} }
} }
if (packet.e_o_s || OggSeekFindEOS(oy, os, packet, is)) if (packet.e_o_s || OggSeekFindEOS(oy, os, packet, is)) {
tag_handler_invoke_duration(handler, handler_ctx, const auto duration =
packet.granulepos / opus_sample_rate); SongTime::FromScale<uint64_t>(packet.granulepos,
opus_sample_rate);
tag_handler_invoke_duration(handler, handler_ctx, duration);
}
ogg_stream_clear(&os); ogg_stream_clear(&os);
......
...@@ -388,7 +388,7 @@ sidplay_scan_file(Path path_fs, ...@@ -388,7 +388,7 @@ sidplay_scan_file(Path path_fs,
const auto duration = get_song_length(path_fs); const auto duration = get_song_length(path_fs);
if (!duration.IsNegative()) if (!duration.IsNegative())
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
duration.RoundS()); SongTime(duration));
return true; return true;
} }
......
...@@ -246,8 +246,9 @@ sndfile_scan_stream(InputStream &is, ...@@ -246,8 +246,9 @@ sndfile_scan_stream(InputStream &is,
return false; return false;
} }
tag_handler_invoke_duration(handler, handler_ctx, const auto duration =
info.frames / info.samplerate); SongTime::FromScale<uint64_t>(info.frames, info.samplerate);
tag_handler_invoke_duration(handler, handler_ctx, duration);
for (auto i : sndfile_tags) for (auto i : sndfile_tags)
sndfile_handle_tag(sf, i.str, i.tag, handler, handler_ctx); sndfile_handle_tag(sf, i.str, i.tag, handler, handler_ctx);
......
...@@ -347,8 +347,10 @@ vorbis_scan_stream(InputStream &is, ...@@ -347,8 +347,10 @@ vorbis_scan_stream(InputStream &is,
if (!vorbis_is_open(&vis, &vf)) if (!vorbis_is_open(&vis, &vf))
return false; return false;
const auto total = ov_time_total(&vf, -1);
if (total >= 0)
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
(int)(ov_time_total(&vf, -1) + 0.5)); SongTime::FromS(total));
vorbis_comments_scan(ov_comment(&vf, -1)->user_comments, vorbis_comments_scan(ov_comment(&vf, -1)->user_comments,
handler, handler_ctx); handler, handler_ctx);
......
...@@ -283,9 +283,10 @@ wavpack_scan_file(Path path_fs, ...@@ -283,9 +283,10 @@ wavpack_scan_file(Path path_fs,
return false; return false;
} }
tag_handler_invoke_duration(handler, handler_ctx, const auto duration =
WavpackGetNumSamples(wpc) / SongTime::FromScale<uint64_t>(WavpackGetNumSamples(wpc),
WavpackGetSampleRate(wpc)); WavpackGetSampleRate(wpc));
tag_handler_invoke_duration(handler, handler_ctx, duration);
/* the WavPack format implies APEv2 tags, which means we can /* the WavPack format implies APEv2 tags, which means we can
reuse the mapping from tag_ape.c */ reuse the mapping from tag_ape.c */
......
...@@ -135,7 +135,9 @@ wildmidi_scan_file(Path path_fs, ...@@ -135,7 +135,9 @@ wildmidi_scan_file(Path path_fs,
return false; return false;
} }
int duration = info->approx_total_samples / WILDMIDI_SAMPLE_RATE; const auto duration =
SongTime::FromScale<uint64_t>(info->approx_total_samples,
WILDMIDI_SAMPLE_RATE);
tag_handler_invoke_duration(handler, handler_ctx, duration); tag_handler_invoke_duration(handler, handler_ctx, duration);
WildMidi_Close(wm); WildMidi_Close(wm);
......
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
static void static void
add_tag_duration(unsigned seconds, void *ctx) add_tag_duration(SongTime duration, void *ctx)
{ {
TagBuilder &tag = *(TagBuilder *)ctx; TagBuilder &tag = *(TagBuilder *)ctx;
tag.SetDuration(SignedSongTime::FromS(seconds)); tag.SetDuration(duration);
} }
static void static void
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "check.h" #include "check.h"
#include "TagType.h" #include "TagType.h"
#include "Chrono.hxx"
#include <assert.h> #include <assert.h>
...@@ -30,11 +31,11 @@ ...@@ -30,11 +31,11 @@
*/ */
struct tag_handler { struct tag_handler {
/** /**
* Declare the duration of a song, in seconds. Do not call * Declare the duration of a song. Do not call
* this when the duration could not be determined, because * this when the duration could not be determined, because
* there is no magic value for "unknown duration". * there is no magic value for "unknown duration".
*/ */
void (*duration)(unsigned seconds, void *ctx); void (*duration)(SongTime duration, void *ctx);
/** /**
* A tag has been read. * A tag has been read.
...@@ -53,12 +54,12 @@ struct tag_handler { ...@@ -53,12 +54,12 @@ struct tag_handler {
static inline void static inline void
tag_handler_invoke_duration(const struct tag_handler *handler, void *ctx, tag_handler_invoke_duration(const struct tag_handler *handler, void *ctx,
unsigned seconds) SongTime duration)
{ {
assert(handler != nullptr); assert(handler != nullptr);
if (handler->duration != nullptr) if (handler->duration != nullptr)
handler->duration(seconds, ctx); handler->duration(duration, ctx);
} }
static inline void static inline void
......
...@@ -48,9 +48,9 @@ ...@@ -48,9 +48,9 @@
static bool empty = true; static bool empty = true;
static void static void
print_duration(unsigned seconds, gcc_unused void *ctx) print_duration(SongTime duration, gcc_unused void *ctx)
{ {
printf("duration=%d\n", seconds); printf("duration=%f\n", duration.ToDoubleS());
} }
static void static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment