mididebug

harja 12.07.03 23:29

MIDI-virran käsittelyä Windows-ympäristössä

 Tekstiversio  Arvo: 2 (2 ääntä)  Äänestä: +  -
/* MIDIDebug - pieni MIDI-tiedon debuggaus/muokkausväline
   Windowsin konsoliin. Suhteellisen vanhaa koodia (pari vuotta vanha)
   mutta toimii hyvin lähtötason esimerkkinä MIDI-ohjelmointiin */


#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <ctype.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define VERSION "1.1"

unsigned char inline HBYTE(const UINT n){return ((n>>8)&0xFF);} // Palauttaa ylimmät 8 bittiä
unsigned char inline LBYTE(const UINT n){return (n&0xFF);} // Palauttaa alemmat 8 bittiä

unsigned int inline HWORD(const DWORD n){return ((n>>16)&0xFFFF);} // Palauttaa ylimmät 16 bittiä
unsigned int inline LWORD(const DWORD n){return (n&0xFFFF);} // Palauttaa alimmat 16 bittiä

HMIDIIN hMidiIn;
HMIDIOUT hMidiOut;
bool printDebug=0;

int octave=0,showNotes=0;

char* i2b(int n, int bits) // kokonaisluku biteiksi
{
        static char buffer[17]={0};
        int i=0, x=0;   
        memset(buffer, 0, 16);
        while(i<bits)
        {
                        x=n;
                        x&=0x1;
                        buffer[i++]='0'+x;
                        n>>=1;
        }
        buffer[i]='\0';
        strrev(buffer);
        return buffer;
}

/* Käsittelee sisääntulevan MIDI-datan */
void CALLBACK MidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
{

        /* Midi-viesti on paketoitu parametreihin seuraavalla tavalla:
        Ylempi sana
                Ylempi tavu - Ei käytössä
                Alempi tavu - Sisältää toisen tavun MIDI-datasta (tarvittaessa)
        Alempi sana
                Ylempi tavu - Ensimmäinen tavu MIDI-datasta (tarvittaessa)
                Alempi tavu - Itse MIDI data
        */

        int dwH=HWORD(dwParam1),dwL=LWORD(dwParam1);
        int noteNo=0, Velocity=0, cmd=0, Channel=0, lword=0;
        char param1High[17]={0}, param1Low[17]={0}, midiDataHigh[9]={0}, midiDataLow[9]={0}, midiStatus[9]={0};
        DWORD sendThis=0;

        strcpy(param1High,i2b(dwH, 16));
        strcpy(param1Low,i2b(dwL, 16));
       
        strcpy(midiDataLow, i2b(LBYTE(dwH),8));
        strncpy(midiDataHigh, param1Low, 8);
        strcpy(midiStatus, i2b(LBYTE(dwL),8));
       
        int status=LBYTE(dwL);
        int midiCmd=(status&0xf0)>>4;

        sendThis=dwParam1;     

        if(printDebug)
                printf("MIDI IN: param: %8s %8s status: %8s [0x%x]\n", midiDataHigh, midiDataLow, midiStatus, status);

        switch(midiCmd)
        {
        case 0x8:       case 0x9:
                // Parsitaan data, kuten yllä on kuvattu
                Velocity=LBYTE(dwH);
                noteNo=HBYTE(dwL);
                Channel=(status&0xf)+1;
                sendThis=0;sendThis=Velocity;sendThis<<=16;
                noteNo+=(octave*12);lword=noteNo;lword<<=8;
                lword|=status;sendThis|=lword;
                if(showNotes) printf("Note %s, no: %d, velocity: %d, channel %d\n", ((Velocity==0||status==0x8)?"off":"on"), noteNo, Velocity, Channel);
                break;
        case 0xb:
                printf("Controller Change, controller number %d, new value %d, channel %d\n", HBYTE(dwL), LBYTE(dwH), status&0x0f);
                break;
        case 0xc:
                printf("Program Change, new patch number %d\n", HBYTE(dwL));
                break;
        case 0xe:
                printf("Bender Change\n");
                break;
        }
       
        midiOutShortMsg(hMidiOut, sendThis);
}

void CALLBACK MidiOutProc(HMIDIOUT hMidiOut, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
        printf("MIDI OUT: Sending message: %d, parameters %ld and %ld\n", wMsg, dwParam1, dwParam2);
}

void showMidiDevices(void)
{
        int numInDevices=0,numOutDevices=0,i=0,res=0;
       
        LPMIDIINCAPS MidiInCaps=new MIDIINCAPS;
        LPMIDIOUTCAPS MidiOutCaps=new MIDIOUTCAPS;

        numInDevices=midiInGetNumDevs();
        numOutDevices=midiOutGetNumDevs();
        if(numInDevices<=0 || numOutDevices<=0)
        {
                printf("No available MIDI devices!\n");
                exit(EXIT_FAILURE);
        }
        printf("\nMIDI In Devices on your system:\n");
        printf("-------------------------------\n");
        for(i=0;i<numInDevices;i++)
        {

                if((res=midiInGetDevCaps(i, MidiInCaps, sizeof(MIDIINCAPS)))!=0)
                {
                        printf("Error: midiInGetDeviceCaps(): Errno=%d\n",res);
                        exit(EXIT_FAILURE);
                }
                printf("MIDI device '%s':\n",MidiInCaps->szPname);
                printf("\tVersion: %d.%d\n", HBYTE(MidiInCaps->vDriverVersion), LBYTE(MidiInCaps->vDriverVersion));
                printf("\twMid: %d ", MidiInCaps->wMid);
                printf("wPid: %d\n\n", MidiInCaps->wPid);
        }
       
        printf("Midi Out Devices on your system:\n");
        printf("--------------------------------\n");
        for(i=0;i<numOutDevices;i++)
        {

                if((res=midiOutGetDevCaps(i, MidiOutCaps, sizeof(MIDIOUTCAPS)))!=0)
                {
                        printf("Error: midiOutGetDeviceCaps(): Errno=%d\n",res);
                        exit(EXIT_FAILURE);
                }
                printf("MIDI device %d, '%s':\n",i,MidiOutCaps->szPname);
                printf("\tVersion: %d.%d\n", HBYTE(MidiOutCaps->vDriverVersion), LBYTE(MidiOutCaps->vDriverVersion));
                printf("\twMid: %d ", MidiOutCaps->wMid);
                printf("wPid: %d\n", MidiOutCaps->wPid);
                printf("\tVoices: %d ", MidiOutCaps->wVoices);
                printf("Notes: %d\n", MidiOutCaps->wNotes);
                printf("\tTechnology: ");
                switch(MidiOutCaps->wTechnology)
                {
                case MOD_FMSYNTH: printf("FM Synth\n"); break;
                case MOD_MAPPER: printf("MIDI Mapper\n"); break;
                case MOD_MIDIPORT: printf("MIDI Port\n"); break;
                case MOD_SQSYNTH: printf("Square wave Syntesizer\n"); break;
                case MOD_SYNTH: printf("Synthesizer\n"); break;
                default: printf("Unknown\n");
                }              
        }

        delete MidiInCaps;
        delete MidiOutCaps;
}

/* Kysytään käyttäjältä mitä laitteita halutaan käyttää */
void selectMidiDevices()
{       
        int numInDevices=0,numOutDevices=0,i=0, selin=-1,selout=-1,res=0;
        DWORD volume=0;
        LPMIDIINCAPS MidiInCaps=new MIDIINCAPS;
        LPMIDIOUTCAPS MidiOutCaps=new MIDIOUTCAPS;

        numInDevices=midiInGetNumDevs();
        numOutDevices=midiOutGetNumDevs();

        if(numInDevices>1) while(selin<0){printf("\nSelect Input Interface: "); scanf("%d", &selin);}
        else selin=0;

        if(numOutDevices>1) while(selout<0){printf("\nSelect Output Interface: "); scanf("%d", &selout);}
        else selout=0;

        if(midiInGetDevCaps(selin, MidiInCaps, sizeof(MIDIINCAPS))!=0){printf("Error (%d)!\n", selin); exit(EXIT_FAILURE);}
        printf("Opening midi in device %d, '%s'...\n", selin, MidiInCaps->szPname);     
        if((res=midiInOpen(&hMidiIn, selin, (unsigned long)&MidiInProc, NULL, CALLBACK_FUNCTION)))
        {
                char buffer[255];
                midiInGetErrorText(res,buffer,255);
                printf("Error opening midi in '%s'\n %s!\n", MidiInCaps->szPname, buffer);
                exit(EXIT_FAILURE);
        }
        midiInStart(hMidiIn);
        printf("Midi Input port opened... listening.\n");

        if(midiOutGetDevCaps(selout, MidiOutCaps, sizeof(MIDIOUTCAPS))!=0){printf("Error (%d)!\n", selout); exit(EXIT_FAILURE);}
        printf("Opening midi out device %d, '%s'...\n", selout, MidiOutCaps->szPname);
        if((res=midiOutOpen(&hMidiOut, selout, (ULONG)&MidiOutProc, NULL, CALLBACK_FUNCTION)))
        {
                char buffer[255];
                midiInGetErrorText(res,buffer,255);
                printf("Error opening midi out '%s'\n %s!\n", MidiOutCaps->szPname, buffer);
                exit(EXIT_FAILURE);
        }
        midiOutGetVolume(hMidiOut,&volume);
        printf("Midi Out port opened, volume L=%d%% R=%d%%...\n",(int)(((float)HWORD(volume)/(float)0xFFFF)*100.0),(int)(((float)LWORD(volume)/(float)0xFFFF)*100.0));

        delete MidiOutCaps;
        delete MidiInCaps;
}

void shutDown(void)
{
        midiInStop(hMidiIn);
        midiInClose(hMidiIn);
        midiOutClose(hMidiOut);
}

/* Ohjelmaan päälooppi */
void mainLoop()
{
        int numInDevices=0,numOutDevices=0,i=0, selin=-1,selout=-1,res=0;
        DWORD volume=0;
        char ch=0;

        while(ch!=27)
        {
                ch=_getch();

                if(ch=='p')
                {
                        int newpatch=-1;
                        DWORD dwParam=0;
                        while(newpatch<0)
                        {
                                fflush(stdin);
                                printf("new patch number: ");
                                scanf("%d",&newpatch);
                        }
                        dwParam=newpatch;
                        dwParam<<=8;
                        dwParam|=192;
                        int err=midiOutShortMsg(hMidiOut, dwParam);

                }
                else if(ch=='v')
                {
                        int volume=-1;
                        DWORD dwVolume=0;
                        while(volume<0)
                        {
                                fflush(stdin);
                                printf("new volume (in percentage): ");
                                scanf("%d",&volume);
                        }
                        volume=(int)(((float)volume/100.0)*(float)0xFFFF);
                        printf("Volume=%d\n", volume);
                        dwVolume=volume;
                        dwVolume<<=16;
                        dwVolume|=volume;
                        midiOutSetVolume(hMidiOut, dwVolume);
                        printf("Volume set to: L=%d%% R=%d%%\n", (int)(((float)HWORD(dwVolume)/(float)0xFFFF)*100.0),(int)(((float)LWORD(dwVolume)/(float)0xFFFF)*100.0));
                }
                else if(ch=='m')
                {
                        printDebug=!printDebug;
                        printf("Debugging %s\n", printDebug?"enabled":"disabled");
                }
                else if(ch=='h')
                {
                        printf("KEYBOARD HELP\n");
                        printf("-------------\n");
                        printf("p                     Change the patch\n");
                        printf("v                     Change the volume\n");
                        printf("+                     Add an octave to the original note\n");
                        printf("-                     Remove an octave from the original note\n");
                        printf("*                     Reset the octave to 0\n");
                        printf("s                     Show/do not show MIDI note on/off commands\n");
                        printf("m                     Print Debug Information\n");
                        printf("d                     Print devices\n");
                        printf("c                     Change devices\n");
                        printf("q or ESC                Exit the program\n");
                }
                else if(ch=='d')
                {
                        showMidiDevices();
                }
                else if(ch=='c')
                {
                        shutDown();
                        selectMidiDevices();
                }
                else if(ch=='s')
                {
                        showNotes=(showNotes==1?0:1);
                        printf("Showing notes %s\n", ((showNotes==1)?"enabled":"disabled"));
                }
                else if(ch=='+') { octave++; printf("Octave + 1 = %d\n", octave); }
                else if(ch=='-') { octave--; printf("Octave - 1 = %d\n", octave); }
                else if(ch=='*') { octave=0; printf("Octave reset to 0\n"); }
                else if(ch=='q') ch=27;
        }
}

int main(void)
{       
        printf(".----------------------------------------------.\n");
        printf("|MIDI Debugger version %3s (c) Mikko Harju 2001|\n",VERSION);
        printf(".______________________________________________|.\n");
        showMidiDevices();
        selectMidiDevices();       
        mainLoop();
        shutDown();
        return 0;       
}