Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Ticks for: libsndfile, FmMidi, Wildmidi (kinda) #2118

Merged
merged 4 commits into from Jun 16, 2020

Conversation

Ghabry
Copy link
Member

@Ghabry Ghabry commented Apr 7, 2020

libsndfile and our bad wave decoder for slow platforms (FASTWAV) have no way to query the position. I added sample counting to get the position. This is hard to get right when "Seek" is used, so I kept this as a FIXME.

In FmMidi I added the current tick count to the midi message. The value matches the harmony value with some margin of error (is a bit higher/lower, harmony somehow keeps the value constant). No idea yet how to make it match better.

WildMidi: This is problematic. Will probably create a PR to there library someday to export the values through there API. They only offer the samplerate (How many samples were created based on the Midi file, so this is indirectly calculated through tempo + division).
When the Midi has no tempo changes just knowing the current tempo is enough to get a quite good value but for a perfect value we need all tempo informations (thats why the midi library has to calculate it).
There is no API to get the current tempo. Assume a fixed tempo (default tempo of WildMidi) and parse the division manually from the Midi header. This makes the error small enough to fix #2106 (the tick reaches the required value before the track ends), fix #1733 and fix #2241.

The Ticks are not implemented for Midis that state that there timing is FPS based. WildMidi rejects such files and because we are not aware of any bug reports this format is very unpopular I guess.

Test for MIDI. Autorun event. Outputs the delta since the last Midi Tick call

@> Play BGM: 'Battle1', 100, 100, 50
@> Control Variables: [0001:Variable 0001] = MIDI Play Location (Tick)
@> Control Variables: [0003:Variable 0003] = Variable [0001]
@> Control Variables: [0001:Variable 0001] -= Variable [0002]
@> Text: \V[1]\|\^
@> Control Variables: [0002:Variable 0002] = Variable [0003]

src/midisequencer.h Outdated Show resolved Hide resolved
@Ghabry Ghabry added this to the 0.6.3 milestone Apr 10, 2020
@Ghabry
Copy link
Member Author

Ghabry commented Apr 14, 2020

This kinda fixes "チンブラ戦隊ブライアン" but this uses Midi for timing in intro music so it needs perfect ticks (and is a perfect test candidate!).

Copy link
Member

@carstene1ns carstene1ns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better than what we have now.

src/decoder_wav.cpp Outdated Show resolved Hide resolved
@fdelapena fdelapena added the MIDI label Jun 9, 2020
@Ghabry
Copy link
Member Author

Ghabry commented Jun 9, 2020

oh there is progress on the PR :). I will check the float vs int comment and then this is ready for now.

…to get Division or tempo changes.

Assume a default tempo and manually extract the Division from the header.
@Ghabry
Copy link
Member Author

Ghabry commented Jun 13, 2020

I reworked the midi ticks part of FmMidi. I added a function to query the divisions. Midi ticks calculation however is now from the outside. Is more accurate this way because before we had message resolution, now we have millisecond resolution.
The error margin is ~4% compared to harmony (the value is slightly lower for some reason)

I want to do the following in a later PR, is too involved for this one:
Create a GenericMidiDecoder which is responsible for initializing the "sub decoder" (FmMidi, WildMidi, Fluidsynth/Lite) and the GenericMidiDecoder will run a FmMidi sequencer that keeps track of the current position to calculate the ticks. This way we get the same ticks everywhere and this is a cheap operation. Is just parsing, not sampling.
FmMidi and Fluid could even use the same sequencer this way, this allows switching Midi audio on-the-fly.
(WildMidi does not provide suitable functions to hook in our sequencer)

@Ghabry Ghabry force-pushed the audio-wip branch 2 times, most recently from 09cb0fe to 2bfbdb8 Compare June 13, 2020 14:32
src/decoder_fmmidi.cpp Outdated Show resolved Hide resolved
@Ghabry
Copy link
Member Author

Ghabry commented Jun 13, 2020

Better way: I remember the last tempo change position and use this to calculate the ticks when they are requested via GetTicks(). This avoids useless tick calculations and has much less error (result is around the same, ~3-5% error compared to RPG_RT)

@carstene1ns carstene1ns merged commit 6bef151 into EasyRPG:master Jun 16, 2020
@Ghabry Ghabry deleted the audio-wip branch February 22, 2022 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
4 participants