Ejemplo n.º 1
0
static PyObject *
midi_parse_track (unsigned char **track, unsigned char *track_end)
{
    unsigned int time = 0;
    unsigned long track_len, track_size;
    PyObject *pytrack = 0;

    debug_print ("%s", "\n");

    track_size = track_end - *track;

    debug_print ("%s", "\n");
    if (memcmp (*track, "MTrk", 4))
        return midi_error (__FUNCTION__,  ": MTrk expected");

    *track += 4;

    track_len = get_number (track, *track + 4, 4);


    debug_print ("track_len: %u\n", track_len);
    debug_print ("track_size: %u\n", track_size);
    debug_print ("track begin: %p\n", track);
    debug_print ("track end: %p\n", track + track_len);

    if (track_len > track_size)
        return midi_error (__FUNCTION__,  ": track size corrupt");

    pytrack = PyList_New (0);

    if (*track + track_len < track_end)
        track_end = *track + track_len;

    {
        PyObject *pytime = PyInt_FromLong (0L);
        unsigned char running_status = 0;

        while (*track < track_end)
        {
            long dt = get_variable_length_number(track, track_end);
            PyObject *pyev = 0;

            time += dt;
            if (dt)
                pytime = PyInt_FromLong (time);

            pyev = read_event (track, track_end, pytime,
                               &running_status);
            if (pyev)
                PyList_Append (pytrack, pyev);
        }
    }

    *track = track_end;
    return pytrack;
}
Ejemplo n.º 2
0
int WinMMDrv_MIDI_StartPlayback(void (*service)(void))
{
    MMRESULT rv;

    WinMMDrv_MIDI_HaltPlayback();

    midiThreadService = service;

    midiThreadQuitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!midiThreadQuitEvent) {
        ErrorCode = WinMMErr_MIDICreateEvent;
        return WinMMErr_Error;
    }

    if (!midiStreamRunning) {
        rv = midiStreamRestart(midiStream);
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "MIDI_StartPlayback midiStreamRestart");
            WinMMDrv_MIDI_HaltPlayback();
            ErrorCode = WinMMErr_MIDIStreamRestart;
            return WinMMErr_Error;
        }

        midiStreamRunning = TRUE;
    }

    midiThread = CreateThread(NULL, 0, midiDataThread, 0, 0, 0);
    if (!midiThread) {
        WinMMDrv_MIDI_HaltPlayback();
        ErrorCode = WinMMErr_MIDIPlayThread;
        return WinMMErr_Error;
    }

    return WinMMErr_Ok;
}
Ejemplo n.º 3
0
void WinMMDrv_MIDI_Shutdown(void)
{
    MMRESULT rv;

    if (!midiInstalled) {
        return;
    }

    WinMMDrv_MIDI_HaltPlayback();

    if (midiStream) {
        rv = midiStreamClose(midiStream);
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "WinMM MIDI_Shutdown midiStreamClose");
        }
    }

    if (midiMutex) {
        CloseHandle(midiMutex);
    }

    midiStream = 0;
    midiMutex = 0;

    midiInstalled = FALSE;
}
Ejemplo n.º 4
0
static void midi_dispose_buffer(MidiBuffer * node, const char * caller)
{
    MMRESULT rv;
    
    if (node->prepared) {
        rv = midiOutUnprepareHeader( (HMIDIOUT) midiStream, &node->hdr, sizeof(MIDIHDR) );
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "WinMM %s/midi_dispose_buffer midiOutUnprepareHeader", caller);
        }
        node->prepared = FALSE;
    }

    if (midiThread) {
        // remove the node from the activeMidiBuffers list
        LL_Remove( node, next, prev );
    
        // when playing, we keep the buffers
        LL_Add( (MidiBuffer*) &spareMidiBuffers, node, next, prev );
        //fprintf(stderr, "WinMM %s/midi_dispose_buffer recycling buffer %p\n", caller, node);
    } else {
        // when not, we throw them away
        free(node);
        //fprintf(stderr, "WinMM %s/midi_dispose_buffer freeing buffer %p\n", caller, node);
    }
}
Ejemplo n.º 5
0
void WinMMDrv_MIDI_HaltPlayback(void)
{
    MMRESULT rv;
    
    if (midiThread) {
        SetEvent(midiThreadQuitEvent);

        WaitForSingleObject(midiThread, INFINITE);
        fprintf(stderr, "WinMM MIDI_HaltPlayback synched\n");

        CloseHandle(midiThread);
    }

    if (midiThreadQuitEvent) {
        CloseHandle(midiThreadQuitEvent);
    }
    
    if (midiStreamRunning) {
        fprintf(stderr, "stopping stream\n");
        rv = midiStreamStop(midiStream);
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "WinMM MIDI_HaltPlayback midiStreamStop");
        }
        fprintf(stderr, "stream stopped\n");
    
        midiStreamRunning = FALSE;
    }

    midi_free_buffers();
    
    midiThread = 0;
    midiThreadQuitEvent = 0;
}
Ejemplo n.º 6
0
void WinMMDrv_MIDI_SetTempo(int tempo, int division)
{
    MMRESULT rv;
    MIDIPROPTEMPO propTempo;
    MIDIPROPTIMEDIV propTimediv;
    BOOL running = midiStreamRunning;

    //fprintf(stderr, "MIDI_SetTempo %d/%d\n", tempo, division);

    propTempo.cbStruct = sizeof(MIDIPROPTEMPO);
    propTempo.dwTempo = 60000000l / tempo;
    propTimediv.cbStruct = sizeof(MIDIPROPTIMEDIV);
    propTimediv.dwTimeDiv = division;

    if (midiLastDivision != division) {
        // changing the division means halting the stream
        WinMMDrv_MIDI_HaltPlayback();

        rv = midiStreamProperty(midiStream, (LPBYTE) &propTimediv, MIDIPROP_SET | MIDIPROP_TIMEDIV);
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "WinMM MIDI_SetTempo midiStreamProperty timediv");
        }
    }

    rv = midiStreamProperty(midiStream, (LPBYTE) &propTempo, MIDIPROP_SET | MIDIPROP_TEMPO);
    if (rv != MMSYSERR_NOERROR) {
        midi_error(rv, "WinMM MIDI_SetTempo midiStreamProperty tempo");
    }

    if (midiLastDivision != division) {
        if (running && WinMMDrv_MIDI_StartPlayback(midiThreadService) != WinMMErr_Ok) {
            return;
        }

        midiLastDivision = division;
    }

    midiThreadQueueTicks = (int) ceil( ( ( (double) tempo * (double) division ) / 60.0 ) /
            (double) THREAD_QUEUE_INTERVAL );
    if (midiThreadQueueTicks <= 0) {
        midiThreadQueueTicks = 1;
    }
}
Ejemplo n.º 7
0
static PyObject *
midi_parse (unsigned char **midi,unsigned  char *midi_end)
{
    PyObject *pymidi = 0;
    unsigned long header_len;
    unsigned format, tracks;
    int division;
    int i;

    debug_print ("%s", "\n");

    /* Header */
    header_len = get_number (midi, *midi + 4, 4);

    if (header_len < 6)
        return midi_error (__FUNCTION__,  ": header too short");

    format = get_number (midi, *midi + 2, 2);
    tracks = get_number (midi, *midi + 2, 2);

    if (tracks > 32)
        return midi_error (__FUNCTION__,  ": too many tracks");

    division = get_number (midi, *midi + 2, 2) * 4;


    if (division < 0)
        /* return midi_error (cannot handle non-metrical time"); */
        ;
    *midi += header_len - 6;

    pymidi = PyList_New (0);

    /* Tracks */
    for (i = 0; i < tracks; i++)
        PyList_Append (pymidi, midi_parse_track (midi, midi_end));

    pymidi = Py_BuildValue ("(OO)", Py_BuildValue ("(ii)", format, division),
                            pymidi);
    return pymidi;
}
Ejemplo n.º 8
0
static DWORD midi_get_tick(void)
{
    MMRESULT rv;
    MMTIME mmtime;

    mmtime.wType = TIME_TICKS;

    rv = midiStreamPosition(midiStream, &mmtime, sizeof(MMTIME));
    if (rv != MMSYSERR_NOERROR) {
        midi_error(rv, "WinMM midi_get_tick midiStreamPosition");
        return 0;
    }

    return mmtime.u.ticks;
}
Ejemplo n.º 9
0
static PyObject *
pymidi_parse_track (PyObject *self, PyObject *args)
{
    unsigned char *track, *track_end;
    unsigned long track_size;

    debug_print ("%s", "\n");
    if (!PyArg_ParseTuple (args, "s#", &track, &track_size))
        return 0;

    if (track_size < 0)
        return midi_error (__FUNCTION__,   ": negative track size");

    track_end = track + track_size;

    return midi_parse_track (&track, track_end);
}
Ejemplo n.º 10
0
static PyObject *
pymidi_parse (PyObject *self, PyObject *args)
{
    unsigned char *midi, *midi_end;
    unsigned long midi_size;

    debug_print ("%s", "\n");
    if (!PyArg_ParseTuple (args, "s#", &midi, &midi_size))
        return 0;

    if (memcmp (midi, "MThd", 4))
        return midi_error (__FUNCTION__,  ": MThd expected");

    midi += 4;

    midi_end = midi + midi_size;

    return midi_parse (&midi, midi_end);
}
Ejemplo n.º 11
0
int WinMMDrv_MIDI_Init(midifuncs * funcs)
{
    MMRESULT rv;

    if (midiInstalled) {
        WinMMDrv_MIDI_Shutdown();
    }

    memset(funcs, 0, sizeof(midifuncs));

    LL_Reset( (MidiBuffer*) &activeMidiBuffers, next, prev );
    LL_Reset( (MidiBuffer*) &spareMidiBuffers, next, prev );

    midiMutex = CreateMutex(0, FALSE, 0);
    if (!midiMutex) {
        ErrorCode = WinMMErr_MIDICreateMutex;
        return WinMMErr_Error;
    }

    rv = midiStreamOpen(&midiStream, &midiDeviceID, 1, (DWORD_PTR) 0, (DWORD_PTR) 0, CALLBACK_NULL);
    if (rv != MMSYSERR_NOERROR) {
        CloseHandle(midiMutex);
        midiMutex = 0;

        midi_error(rv, "WinMM MIDI_Init midiStreamOpen");
        ErrorCode = WinMMErr_MIDIStreamOpen;
        return WinMMErr_Error;
    }
    
    funcs->NoteOff = Func_NoteOff;
    funcs->NoteOn  = Func_NoteOn;
    funcs->PolyAftertouch = Func_PolyAftertouch;
    funcs->ControlChange = Func_ControlChange;
    funcs->ProgramChange = Func_ProgramChange;
    funcs->ChannelAftertouch = Func_ChannelAftertouch;
    funcs->PitchBend = Func_PitchBend;
    funcs->SysEx = Func_SysEx;

    midiInstalled = TRUE;
    
    return WinMMErr_Ok;
}
Ejemplo n.º 12
0
static void midi_flush_current_buffer(void)
{
    MMRESULT rv;
    MIDIEVENT * evt;
    BOOL needsPrepare = FALSE;

    if (!currentMidiBuffer) {
        return;
    }

    evt = (MIDIEVENT *) currentMidiBuffer->hdr.lpData;

    if (!midiThread) {
        // immediate messages don't use a MIDIEVENT header so strip it off and
        // make some adjustments

        currentMidiBuffer->hdr.dwBufferLength = currentMidiBuffer->hdr.dwBytesRecorded - 12;
        currentMidiBuffer->hdr.dwBytesRecorded = 0;
        currentMidiBuffer->hdr.lpData = (LPSTR) &evt->dwParms[0];
        
        if (currentMidiBuffer->hdr.dwBufferLength > 0) {
            needsPrepare = TRUE;
        }
    } else {
        needsPrepare = TRUE;
    }
    
    if (needsPrepare) {
        // playing a file, or sending a sysex when not playing means
        // we need to prepare the buffer
        rv = midiOutPrepareHeader( (HMIDIOUT) midiStream, &currentMidiBuffer->hdr, sizeof(MIDIHDR) );
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "WinMM midi_flush_current_buffer midiOutPrepareHeader");
            return;
        }

        currentMidiBuffer->prepared = TRUE;
    }

    if (midiThread) {
        // midi file playing, so send events to the stream

        LL_Add( (MidiBuffer*) &activeMidiBuffers, currentMidiBuffer, next, prev );

        rv = midiStreamOut(midiStream, &currentMidiBuffer->hdr, sizeof(MIDIHDR));
        if (rv != MMSYSERR_NOERROR) {
            midi_error(rv, "WinMM midi_flush_current_buffer midiStreamOut");
            midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer");
            return;
        }

        //fprintf(stderr, "WinMM midi_flush_current_buffer queued buffer %p\n", currentMidiBuffer);
    } else {
        // midi file not playing, so send immediately
        
        if (currentMidiBuffer->hdr.dwBufferLength > 0) {
            rv = midiOutLongMsg( (HMIDIOUT) midiStream, &currentMidiBuffer->hdr, sizeof(MIDIHDR) );
            if (rv == MMSYSERR_NOERROR) {
                // busy-wait for Windows to be done with it
                while (!(currentMidiBuffer->hdr.dwFlags & MHDR_DONE)) ;
                
                //fprintf(stderr, "WinMM midi_flush_current_buffer sent immediate long\n");
            } else {
                midi_error(rv, "WinMM midi_flush_current_buffer midiOutLongMsg");
            }
        } else {
            rv = midiOutShortMsg( (HMIDIOUT) midiStream, evt->dwEvent );
            if (rv == MMSYSERR_NOERROR) {
                //fprintf(stderr, "WinMM midi_flush_current_buffer sent immediate short\n");
            } else {
                midi_error(rv, "WinMM midi_flush_current_buffer midiOutShortMsg");
            }
        }

        midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer");
    }
    
    currentMidiBuffer = 0;
}