Skip to content

Commit

Permalink
feat(DmSegment): add a getter for the length of a segment in seconds
Browse files Browse the repository at this point in the history
  • Loading branch information
lmichaelis committed May 9, 2024
1 parent e57b130 commit 49f885f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
11 changes: 11 additions & 0 deletions include/dmusic.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,17 @@ DMAPI DmGuid const* DmSegment_getGuid(DmSegment const* slf);
/// \return A read-only pointer to the segment's name in UTF-8.
DMAPI char const* DmSegment_getName(DmSegment const* slf);

/// \brief Get the length of the given segment in seconds.
///
/// The number of PCM samples required to render `n` seconds of the segment can be calculated like this:
/// \f$x_{samples} = n \cdot x_{rate} \cdot n_{channels}\f$
/// where \f$x_{rate}\f$ is the sample rate to use (usually 44100 Hz) and \f$n_{channels}\f$ is the number
/// of PCM output channels (1 for mono and 2 for stereo PCM).
///
/// \param slf[in] The segment to get the length of
/// \return The number of seconds one repeat of the segment takes.
DMAPI double DmSegment_getLength(DmSegment const* slf);

/// \}

/// \defgroup DmLoaderGroup Loader
Expand Down
9 changes: 7 additions & 2 deletions src/Common.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,16 @@ uint32_t Dm_getMeasureLength(DmTimeSignature sig) {
return v;
}

double Dm_getTicksPerSample(DmTimeSignature time_signature, double beats_per_minute, uint32_t sample_rate) {
double Dm_getTicksPerSecond(DmTimeSignature time_signature, double beats_per_minute) {
uint32_t pulses_per_beat = Dm_getBeatLength(time_signature); // unit: music-time per beat
double beats_per_second = beats_per_minute / DmInt_SECONDS_PER_MINUTE; // unit: 1 per second
double pulses_per_second = pulses_per_beat * beats_per_second; // unit: music-time per second
double pulses_per_sample = pulses_per_second / sample_rate; // unit: music-time per sample
return pulses_per_second;
}

double Dm_getTicksPerSample(DmTimeSignature time_signature, double beats_per_minute, uint32_t sample_rate) {
double pulses_per_second = Dm_getTicksPerSecond(time_signature, beats_per_minute); // unit: music-time per second
double pulses_per_sample = pulses_per_second / sample_rate; // unit: music-time per sample
return pulses_per_sample;
}

Expand Down
30 changes: 30 additions & 0 deletions src/Segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,33 @@ char const* DmSegment_getName(DmSegment const* slf) {

return slf->info.unam;
}

double DmSegment_getLength(DmSegment const* slf) {
if (slf == NULL) {
return 0;
}

// NOTE: This assumes that the tempo messages are ordered from earliest to latest
DmTimeSignature signature = {4, 4, 4};
uint32_t offset = 0;
double tempo = 100.;
double duration = 0;

for (unsigned i = 0; i < slf->messages.length; ++i) {
DmMessage* msg = &slf->messages.data[i];
if (msg->type != DmMessage_TEMPO) {
continue;
}

uint32_t ticks = msg->time - offset;
tempo = msg->tempo.tempo;

duration += ticks / Dm_getTicksPerSecond(signature, tempo);
offset = msg->time;
}

uint32_t ticks = slf->length - offset;
duration += ticks / Dm_getTicksPerSecond(signature, tempo);

return duration;
}
1 change: 1 addition & 0 deletions src/_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ DMINT void DmTimeSignature_parse(DmTimeSignature* slf, DmRiff* rif);

DMINT uint32_t Dm_getBeatLength(DmTimeSignature sig);
DMINT uint32_t Dm_getMeasureLength(DmTimeSignature sig);
DMINT double Dm_getTicksPerSecond(DmTimeSignature time_signature, double beats_per_minute);
DMINT double Dm_getTicksPerSample(DmTimeSignature time_signature, double beats_per_minute, uint32_t sample_rate);
DMINT uint32_t Dm_getTimeOffset(uint32_t grid_start, int32_t time_offset, DmTimeSignature sig);
DMINT uint32_t Dm_getSampleCountForDuration(uint32_t duration,
Expand Down

0 comments on commit 49f885f

Please sign in to comment.