Can’t sync a .midi file to what appears onscreen in my game

I’m currently developing my first game for a course using PixiJS and TypeScript, and I decided to make it a rhythm game. The gameplay is very simple: the user has to press one of six keys when said key falls within a certain area of the screen. However, the backend for the gameplay is a bit more complex, since the songs for the game are supposed to be chosen by the user from a .mid file (which is intended to represent the notes that show up onscreen) and an .ogg file (which is the music that will be played).

Now, I’ve used a library to parse a custom .mid file into a .json, and then from that .json I can get the data to show the notes onscreen as keys for the user to press. The issue, however, is that no matter the formulas I’ve tried or the many iterations my function to parse the json into a playable array I’ve gone through, what appears on screen ALWAYS ends up desynced with the music.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>function processMidiJson(json: any) {
console.log('Processing MIDI JSON:', json);
const jsonArray = convertArraysToObjectArrays(Object.values(json));
let notesArray: [string, number][] = [];
const tempo = json.tracks[0][1].setTempo.microsecondsPerQuarter; // Tempo in microseconds per quarter note
const bpm = 60000 / (tempo / 1000);
const division = json.division; // Division value from MIDI file
const msPerTick = 60000 / (bpm * division)
console.log(msPerTick);
for (let i = 0; i < jsonArray[2][1].length; i++) {
const currentObject = jsonArray[2][1][i];
if (currentObject.noteOn) {
if (jsonArray[2][1][i - 1].noteOn) { // If the previous note is a noteOn, then it is a chord and only the delta of one note is necessary.
notesArray.push([String(currentObject.noteOn.noteNumber - 96), ((currentObject.delta) * msPerTick)]);
} else {
notesArray.push([String(currentObject.noteOn.noteNumber - 96), ((currentObject.delta + jsonArray[2][1][i + 1].delta) * msPerTick)]);
}
}
}
console.log(notesArray);
return notesArray;
}
</code>
<code>function processMidiJson(json: any) { console.log('Processing MIDI JSON:', json); const jsonArray = convertArraysToObjectArrays(Object.values(json)); let notesArray: [string, number][] = []; const tempo = json.tracks[0][1].setTempo.microsecondsPerQuarter; // Tempo in microseconds per quarter note const bpm = 60000 / (tempo / 1000); const division = json.division; // Division value from MIDI file const msPerTick = 60000 / (bpm * division) console.log(msPerTick); for (let i = 0; i < jsonArray[2][1].length; i++) { const currentObject = jsonArray[2][1][i]; if (currentObject.noteOn) { if (jsonArray[2][1][i - 1].noteOn) { // If the previous note is a noteOn, then it is a chord and only the delta of one note is necessary. notesArray.push([String(currentObject.noteOn.noteNumber - 96), ((currentObject.delta) * msPerTick)]); } else { notesArray.push([String(currentObject.noteOn.noteNumber - 96), ((currentObject.delta + jsonArray[2][1][i + 1].delta) * msPerTick)]); } } } console.log(notesArray); return notesArray; } </code>
function processMidiJson(json: any) {
    console.log('Processing MIDI JSON:', json);
    const jsonArray = convertArraysToObjectArrays(Object.values(json));
    let notesArray: [string, number][] = [];
    const tempo = json.tracks[0][1].setTempo.microsecondsPerQuarter; // Tempo in microseconds per quarter note
    const bpm = 60000 / (tempo / 1000);
    const division = json.division; // Division value from MIDI file
    const msPerTick = 60000 / (bpm * division)
    console.log(msPerTick);

    for (let i = 0; i < jsonArray[2][1].length; i++) {
        const currentObject = jsonArray[2][1][i];

        if (currentObject.noteOn) {
            if (jsonArray[2][1][i - 1].noteOn) { // If the previous note is a noteOn, then it is a chord and only the delta of one note is necessary.
                notesArray.push([String(currentObject.noteOn.noteNumber - 96), ((currentObject.delta) * msPerTick)]);
            } else {
                notesArray.push([String(currentObject.noteOn.noteNumber - 96), ((currentObject.delta + jsonArray[2][1][i + 1].delta) * msPerTick)]);
            }
        }
    }

    console.log(notesArray);
    return notesArray;
}

This is my current function. The .mid file I’m using is parsed into this json, and the json is parsed into this array, in which the first value of each array is the note number (which is tied to a key) and the second value the gap between the current and the previous note in milliseconds. Now, I’ve tried doing both currentObject.delta + jsonArray[2][1][i + 1].delta and currentObject.delta + jsonArray[2][1][i - 1].delta, and using the delta value of the current note’s noteOff seems to work better, but in both cases it still gets desynced the further you get into the song.

I’ve kind of run out of ideas at this point, it’s clear that MIDI files can be rather inconsistent, but the values in ms that I get should nevertheless match the music being played (which is, by the way, a 1:1 representation of the midi file since it was created straight from the midi being used). Considering that the testing song I’m using has 120 BPM, the values in the array seem to be correct, such as a 1/8th note lasting 250ms and a dotted quarter note lasting 750ms, nevertheless it gets desynced.

This is the GitHub repository in case anyone wants to test it first-hand.

New contributor

Juani is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật