M
M
mpvcluuuuub2021-11-24 16:24:22
MIDI
mpvcluuuuub, 2021-11-24 16:24:22

How to fix big delay between MIDI notes?

I wrote a program for playing melodies that are stored in a text file, when playing between sounds, for some reason there is some kind of delay of about one half a second, although I didn’t seem to indicate it anywhere.

#pragma comment(lib, "Winmm.lib")
 
#include <cmath>
#include <vector>
#include <map>
#include <fstream>
#include <iostream>
#include <windows.h>
#include <mmsystem.h>
 
 
using namespace std;
#define SNDQUE 10000
 
typedef struct _soundtype
{
    double Freq;
    int Dura;
    int Vol;
    int Voice;
    double Tempo;
    int sndTid;
} soundtype, * LPSOUNDTYPE;
 
static soundtype SndPmtr[SNDQUE + 1];
static int gTenter;
static int gTwait;
static int gTexit;
static int gTarray;
static BOOL gTsig;
static HANDLE gSThread = NULL;
 
map<char, double> matchingNotesToFrequency{
{'C', 32.703}, {'D', 36.708}, {'E', 41.203}, // До, Ре, Ми
{'F', 43.654}, {'G', 48.999}, {'A', 55.}, // Фа, Соль, Ля
{'H', 61.735} }; // Си
 
struct MyNote {
    double frequency;
    int duration;
    int octave;
};
 
double Round(double, int);
double Abs(double);
vector<MyNote> readNotes(string notespath);
int Sound(float, int = 0, int = 127, int = 0, float = 1);
// changed this from int PlaySnd(void) to:
DWORD WINAPI PlaySnd(LPVOID);
 
int main()
{
    // Tugboat whistle sound 95 hertz, 2000ms, 127 = loud, 111 = Shanai
    // experiment with your own sounds, it's fun ...
    //Sound(95, 2000, 127, 111); // 2 second blast
    //Sound(1, 1000, 0, 111); // 1 second of silence
    //Sound(95, 2000, 127, 111); // 2 second blast
    //Sound(1, 1000, 0, 111); // 1 second of silence
    //Sound(95, 2000, 127, 111); // 2 second blast
 
    vector<MyNote> notes = readNotes("melody.txt");
    for (int i = 0; i < notes.size(); i++) {
        Sound(notes[i].frequency * notes[i].octave * 10, notes[i].duration, 127, 0);
    }
        // wait till que is empty
    while (Sound(0) != 0)
    {
    Sleep(10);
    }
 
        return 0;
}
 
double Round(double n, int d)
{
    return (floor((n)*pow(10.0, (d)) + 0.5) / pow(10.0, (d)));
}
 
 
double Abs(double a)
{
    if (a < 0) return -a;
    return a;
}
 
vector<MyNote> readNotes(string notespath)
{
    
    vector<MyNote> notes;
 
    ifstream reader(notespath);
 
    if (reader.is_open()) 
    {
        while (!reader.eof()) {
 
            char noteSymbol;
            int octave, duration;
            MyNote temp;
            
            reader >> noteSymbol;
            reader >> octave;
            reader >> duration;
 
            temp.frequency = matchingNotesToFrequency[noteSymbol];
            temp.octave = octave;
            temp.duration = duration;
 
            notes.push_back(temp);
 
        }
    }
    else
    {
        cout << "File not open";
    }
 
    return notes;
 
}
 
int Sound(float Freq, int Dura, int Vol, int Voice, float Tempo)
{
    DWORD dwThreadId;
    
    if (Freq == 0 && Dura < 1) return gTenter - gTexit;
    // silence
    if (Freq == 0) Vol = 0;
    if (Dura < 5) Dura = 5;
    gTenter++;
    gTsig = FALSE;
    if (gTenter >= SNDQUE)
    {
        gTarray = gTenter % SNDQUE + 1;
    }
    else
    {
        gTarray = gTenter;
    }
    SndPmtr[gTarray].Freq = Freq;
    SndPmtr[gTarray].Dura = Dura;
    SndPmtr[gTarray].Tempo = Tempo;
    SndPmtr[gTarray].Vol = Vol;
    SndPmtr[gTarray].Voice = Voice;
    SndPmtr[gTarray].sndTid = gTenter;
    if (gSThread == NULL && (Freq == Abs(Freq) || Freq == 0))
    {
    // "PlaySnd" needs casting (void *)
        gSThread = CreateThread(NULL, 0, PlaySnd, (void*)"PlaySnd", 0, &dwThreadId);
        Sleep(1);
        return 0;
    }
    if (Freq != Abs(Freq))
    {
        if (Freq == -1)
        {
            Freq = 0;
            SndPmtr[gTarray].Vol = 0;
        }
        SndPmtr[gTarray].Freq = Abs(Freq);
        gTsig = TRUE;
        while (gSThread != NULL)
        {
            Sleep(10);
        }
        gTexit = gTenter - 1;
        gTwait = gTenter - 1;
        gTsig = FALSE;
        return PlaySnd(0); // needs some kind of argument
    }
    return 0;
}
 
DWORD WINAPI PlaySnd(LPVOID)
{
    soundtype LocSndPar;
    int lTarray;
    
    while (gTenter > gTexit && gTsig == FALSE)
    {
        gTwait++;
        if (gTwait >= SNDQUE)
            lTarray = gTwait % SNDQUE + 1;
        else
            lTarray = gTwait;
        LocSndPar = SndPmtr[lTarray];
        int Note = 0;
        int Phrase = 0;
        HMIDIOUT hMidi;
        midiOutOpen(&hMidi, (UINT)-1, 0, 0, CALLBACK_NULL);
        midiOutShortMsg(hMidi, (256 * LocSndPar.Voice) + 192);
        // convert frequency to midi note
        Note = (int)Round((log(LocSndPar.Freq) - log(440.0)) / log(2.0) * 12 + 69, 0);
        Phrase = (LocSndPar.Vol * 256 + Note) * 256 + 144;
        midiOutShortMsg(hMidi, Phrase);
        Sleep((int)(LocSndPar.Dura * (1 / LocSndPar.Tempo + 0.0001)));
        Phrase = (LocSndPar.Vol * 256 + Note) * 256 + 128;
        midiOutShortMsg(hMidi, Phrase);
        midiOutClose(hMidi);
        gTexit++;
    }
    CloseHandle(gSThread);
    gSThread = NULL;
    return 0;
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
maaGames, 2021-11-24
@maaGames

Sleep((int)(LocSndPar.Dura * (1 / LocSndPar.Tempo + 0.0001)));
And all the other Sleep delays, maybe they have a problem.
(void*)"PlaySnd" can be omitted, you don't use an argument in PLaySnd. You can pass nullptr.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question