I'm creating an USB OPL3 hardware player which could be used to play VGM files now and could be used for music production or use as a sound card for DOSBox in the future. Prototype works pretty fine except for one problem: VGM playback speed is slightly faster compared to recordings on this site.
What I'm doing now is processing the VGM file on computer, sending the commands to the OPL3, calculate all the time spent on sending that data(Tdata) before a sleep command, and at a sleep command(Tsleep) I sleep for (Tsleep - Tdata). When listening directly it doesn't seems to be causing much problem, rhythm and tempo seems to be correct, but comparing the recorded file to a previously recorded one on this site shows it's actually a little bit fast. Is there anything wrong with my processing or there're other issues involved?
Thanks in advance for any generous help!
Video:
https://youtu.be/MI8EEHc744Y
VGM file format timing issue
Technical discussion about the VGM format, and all the software you need to handle VGM files.
Moderator: Staff
- vampirefrog Offline
- Webmaster
- Posts: 1506
- Joined: 2014-01-28, 5:51:54
most likely it's the former. be aware of rounding / precision errors. I think generally it might be a good idea to accumulate delays and process the writes in batches (for example every X millisecond, where you can use a hardware timer set to that exact period).ClassicOldSong wrote:Is there anything wrong with my processing or there're other issues involved?
FM chips are slow so don't be alarmed if you end up taking more than one VGM tick to process all the writes.
- ClassicOldSong Offline
- Posts: 8
- Joined: 2021-03-31, 8:46:19
In this configuration playback speed should be completely controlled by CPU. This prototype uses GPIO for command transferring, since commands were sent directly by CPU, the CPU clock itself is the audio interface clock.perhaps due to clock drift between the audio interface clock and the system clock
That's exactly what I'm doing, except for that I took the time for commanding away from sleeps, otherwise it could be too slow or inconsistent.I think generally it might be a good idea to accumulate delays and process the writes in batches
- ValleyBell Offline
- Posts: 4787
- Joined: 2011-12-01, 20:20:07
- Location: Germany
In general, VGM timing assumed that the action of "sending a command" takes 0 time.
Only "wait" commands cause the time to advance. You need to be aware of that concept.
Thus, when sending a command takes some real time, you need to subtract that time from the next delay.
When I write timing code, I usually have a timestamp for "time of the next command", which is increased whenever there is a "wait" command.
And when I'm sleeping, I always wait until that timestamp is reached. (If the real time is already past it, then of course there is no wait.)
Only "wait" commands cause the time to advance. You need to be aware of that concept.
Thus, when sending a command takes some real time, you need to subtract that time from the next delay.
When I write timing code, I usually have a timestamp for "time of the next command", which is increased whenever there is a "wait" command.
And when I'm sleeping, I always wait until that timestamp is reached. (If the real time is already past it, then of course there is no wait.)
- ClassicOldSong Offline
- Posts: 8
- Joined: 2021-03-31, 8:46:19
Interesting, it seems that we are doing the very same. But I'm still getting slightly faster. Probably it's the rounding issue. I saved 1/44100 in double and multiply it each time a wait command comes in. Probably should divide it each time instead of multiply it.When I write timing code, I usually have a timestamp for "time of the next command", which is increased whenever there is a "wait" command.
Last edited by ClassicOldSong on 2021-04-04, 22:52:08, edited 1 time in total.
- ClassicOldSong Offline
- Posts: 8
- Joined: 2021-03-31, 8:46:19
Not at my computer rn so tried on my phone:
Which outputs
Multiplying doesn't seem to be the main cause of this problem.
Code: Select all
#include <iostream>
#include <cstdint>
using namespace std;
int main()
{
double aaa = 1.0 / 44100;
uint32_t bbb = aaa * 0xffffffff;
uint32_t ccc = 0xffffffff / 44100;
cout<<bbb<<"\n";
cout<<ccc;
return 0;
}
Code: Select all
97391
97391
- ClassicOldSong Offline
- Posts: 8
- Joined: 2021-03-31, 8:46:19
I've calculated all wait command time and the total running time of the player, and there's no much difference, and even a little bit slower. So I don't think there's problem with my timing method, probably the recording here is just not time accurate.
Code: Select all
total time delay commands in usecs: 97424690
total play time in usecs: 98046745
- ClassicOldSong Offline
- Posts: 8
- Joined: 2021-03-31, 8:46:19