Category : Files from Magazines
Archive   : VOL11N08.ZIP
Filename : KBMIDI.C

 
Output of file : KBMIDI.C contained in archive : VOL11N08.ZIP
/*---------------------------------------------------------
KBMIDI.C -- Keyboard MIDI Player for Multimedia Windows
(c) Charles Petzold, 1992
---------------------------------------------------------*/


#include
extern "C" {
#include
}
#include
typedef unsigned int UINT ;

#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))

// Defines for Menu IDs
// --------------------

#define IDM_OPEN 0x100
#define IDM_CLOSE 0x101
#define IDM_DEVICE 0x200
#define IDM_CHANNEL 0x300
#define IDM_VOICE 0x400

// Forward declaration of WndProc
// ------------------------------

long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG);

// Global variables
// ----------------

char szAppName [] = "KBMidi" ;
HMIDIOUT hMidiOut ;
int iDevice = MIDIMAPPER, iChannel = 0, iVoice = 0, iVelocity = 64 ;
int cxCaps, cyChar, xOffset, yOffset ;

// Structures for family and instrument names
// ------------------------------------------

typedef struct
{
char * szInst ;
int iVoice ;
}
INSTRUMENT ;

typedef struct
{
char * szFam ;
INSTRUMENT inst [8] ;
}
FAMILY ;

FAMILY fam [16] = { "Piano",

"Acoustic Grand Piano", 0,
"Bright Acoustic Piano", 1,
"Electric Grand Piano", 2,
"Honky-tonk Piano", 3,
"Rhodes Piano", 4,
"Chorused Piano", 5,
"Harpsichord", 6,
"Clavinet", 7,

"Chromatic Percussion",

"Celesta", 8,
"Glockenspiel", 9,
"Music box", 10,
"Vibraphone", 11,
"Marimba", 12,
"Xylophone", 13,
"Tubular Bells", 14,
"Dulcimer", 15,

"Organ",

"Hammond Organ", 16,
"Percussive Organ", 17,
"Rock Organ", 18,
"Church Organ", 19,
"Reed Organ", 20,
"Accordian", 21,
"Harmonica", 22,
"Tango Accordian", 23,

"Guitar",

"Acoustic Guitar (nylon)", 24,
"Acoustic Guitar (steel)", 25,
"Electric Guitar (jazz)", 26,
"Electric Guitar (clean)", 27,
"Electric Guitar (muted)", 28,
"Overdriven Guitar", 29,
"Distortion Guitar", 30,
"Guitar Harmonics", 31,

"Bass",

"Acoustic Bass", 32,
"Electric Bass (finger)", 33,
"Electric Bass (pick)", 34,
"Fretless Bass", 35,
"Slap Bass 1", 36,
"Slap Bass 2", 37,
"Synth Bass 1", 38,
"Synth Bass 2", 39,

"Strings",

"Violin", 40,
"Viola", 41,
"Cello", 42,
"Contrabass", 43,
"Tremolo Strings", 44,
"Pizzicato Strings", 45,
"Orchestral Harp", 46,
"Timpani", 47,

"Ensemble",

"String Ensemble 1", 48,
"String Ensemble 2", 49,
"Synth Strings 1", 50,
"Synth Strings 2", 51,
"Choir Aahs", 52,
"Voice Oohs", 53,
"Synth Voice", 54,
"Orchestra Hit", 55,

"Brass",

"Trumpet", 56,
"Trombone", 57,
"Tuba", 58,
"Muted Trumpet", 59,
"French Horn", 60,
"Brass Section", 61,
"Synth Brass 1", 62,
"Synth Brass 2", 63,

"Reed",

"Soprano Sax", 64,
"Alto Sax", 65,
"Tenor Sax", 66,
"Baritone Sax", 67,
"Oboe", 68,
"English Horn", 69,
"Bassoon", 70,
"Clarinet", 71,

"Pipe",

"Piccolo", 72,
"Flute", 73,
"Recorder", 74,
"Pan Flute", 75,
"Bottle Blow", 76,
"Shakuhachi", 77,
"Whistle", 78,
"Ocarina", 79,

"Synth Lead",

"Lead 1 (square)", 80,
"Lead 2 (sawtooth)", 81,
"Lead 3 (caliope lead)", 82,
"Lead 4 (chiff lead)", 83,
"Lead 5 (charang)", 84,
"Lead 6 (voice)", 85,
"Lead 7 (fifths)", 86,
"Lead 8 (brass + lead)", 87,

"Synth Pad",

"Pad 1 (new age)", 88,
"Pad 2 (warm)", 89,
"Pad 3 (polysynth)", 90,
"Pad 4 (choir)", 91,
"Pad 5 (bowed)", 92,
"Pad 6 (metallic)", 93,
"Pad 7 (halo)", 94,
"Pad 8 (sweep)", 95,

"Synth Effects",

"FX 1 (rain)", 96,
"FX 2 (soundtrack)", 97,
"FX 3 (crystal)", 98,
"FX 4 (atmosphere)", 99,
"FX 5 (brightness)", 100,
"FX 6 (goblins)", 101,
"FX 7 (echoes)", 102,
"FX 8 (sci-fi)", 103,

"Ethnic",

"Sitar", 104,
"Banjo", 105,
"Shamisen", 106,
"Koto", 107,
"Kalimba", 108,
"Bagpipe", 109,
"Fiddle", 110,
"Shanai", 111,

"Percussive",

"Tinkle Bell", 112,
"Agogo", 113,
"Steel Drums", 114,
"Woodblock", 115,
"Taiko Drum", 116,
"Melodic Tom", 117,
"Synth Drum", 118,
"Reverse Cymbal", 119,

"Sound Effects",

"Guitar Fret Noise", 120,
"Breath Noise", 121,
"Seashore", 122,
"Bird Tweet", 123,
"Telephone Ring", 124,
"Helicopter", 125,
"Applause", 126,
"Gunshot", 127 } ;

// Data for translating scan codes to octaves and notes
// ----------------------------------------------------

#define NUMSCANS (sizeof key / sizeof key[0])

struct
{
int iOctave ;
int iNote ;
int yPos ;
int xPos ;
char * szKey ;
}
key [] =
{
// Scan Char Oct Note
// ---- ---- --- ----
-1, -1, -1, -1, NULL, // 0 None
-1, -1, -1, -1, NULL, // 1 Esc
-1, -1, 0, 0, "", // 2 1
5, 1, 0, 2, "C#", // 3 2 5 C#
5, 3, 0, 4, "D#", // 4 3 5 D#
-1, -1, 0, 6, "", // 5 4
5, 6, 0, 8, "F#", // 6 5 5 F#
5, 8, 0, 10, "G#", // 7 6 5 G#
5, 10, 0, 12, "A#", // 8 7 5 A#
-1, -1, 0, 14, "", // 9 8
6, 1, 0, 16, "C#", // 10 9 6 C#
6, 3, 0, 18, "D#", // 11 0 6 D#
-1, -1, 0, 20, "", // 12 -
6, 6, 0, 22, "F#", // 13 = 6 F#
-1, -1, -1, -1, NULL, // 14 Back

-1, -1, -1, -1, NULL, // 15 Tab
5, 0, 1, 1, "C", // 16 q 5 C
5, 2, 1, 3, "D", // 17 w 5 D
5, 4, 1, 5, "E", // 18 e 5 E
5, 5, 1, 7, "F", // 19 r 5 F
5, 7, 1, 9, "G", // 20 t 5 G
5, 9, 1, 11, "A", // 21 y 5 A
5, 11, 1, 13, "B", // 22 u 5 B
6, 0, 1, 15, "C", // 23 i 6 C
6, 2, 1, 17, "D", // 24 o 6 D
6, 4, 1, 19, "E", // 25 p 6 E
6, 5, 1, 21, "F", // 26 [ 6 F
6, 7, 1, 23, "G", // 27 ] 6 G
-1, -1, -1, -1, NULL, // 28 Ent

-1, -1, -1, -1, NULL, // 29 Ctrl
3, 8, 2, 2, "G#", // 30 a 3 G#
3, 10, 2, 4, "A#", // 31 s 3 A#
-1, -1, 2, 6, "", // 32 d
4, 1, 2, 8, "C#", // 33 f 4 C#
4, 3, 2, 10, "D#", // 34 g 4 D#
-1, -1, 2, 12, "", // 35 h
4, 6, 2, 14, "F#", // 36 j 4 F#
4, 8, 2, 16, "G#", // 37 k 4 G#
4, 10, 2, 18, "A#", // 38 l 4 A#
-1, -1, 2, 20, "", // 39 ;
5, 1, 2, 22, "C#", // 40 ' 5 C#
-1, -1, -1, -1, NULL, // 41 `

-1, -1, -1, -1, NULL, // 42 Shift
-1, -1, -1, -1, NULL, // 43 \ (not line continuation)
3, 9, 3, 3, "A", // 44 z 3 A
3, 11, 3, 5, "B", // 45 x 3 B
4, 0, 3, 7, "C", // 46 c 4 C
4, 2, 3, 9, "D", // 47 v 4 D
4, 4, 3, 11, "E", // 48 b 4 E
4, 5, 3, 13, "F", // 49 n 4 F
4, 7, 3, 15, "G", // 50 m 4 G
4, 9, 3, 17, "A", // 51 , 4 A
4, 11, 3, 19, "B", // 52 . 4 B
5, 0, 3, 21, "C" // 53 / 5 C
} ;

// Standard WinMain
// ----------------

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd ;
WNDCLASS wndclass ;

if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;

RegisterClass (&wndclass) ;
}

hwnd = CreateWindow (szAppName, "Keyboard MIDI Player",
WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd);

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

// Create the program's menu (called from WndProc, WM_CREATE)
// ----------------------------------------------------------

HMENU CreateTheMenu (int iNumDevs)
{
char szBuffer [32] ;
HMENU hMenu, hMenuPopup, hMenuSubPopup ;
int i, iFam, iIns ;
MIDIOUTCAPS moc ;

hMenu = CreateMenu () ;

// Create "On/Off" popup menu

hMenuPopup = CreateMenu () ;

AppendMenu (hMenuPopup, MF_STRING , IDM_OPEN, "&Open") ;
AppendMenu (hMenuPopup, MF_STRING | MF_CHECKED, IDM_CLOSE, "&Closed") ;

AppendMenu (hMenu, MF_STRING | MF_POPUP, hMenuPopup, "&Status") ;

// Create "Device" popup menu

hMenuPopup = CreateMenu () ;

// Put MIDI Mapper on menu if it's installed

if (!midiOutGetDevCaps (MIDIMAPPER, &moc, sizeof (moc)))
AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + MIDIMAPPER,
moc.szPname) ;
else
iDevice = 0 ;

// Add the rest of the MIDI devices

for (i = 0 ; i < iNumDevs ; i++)
{
midiOutGetDevCaps (i, &moc, sizeof (moc)) ;
AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + i, moc.szPname) ;
}

CheckMenuItem (hMenuPopup, 0, MF_BYPOSITION | MF_CHECKED) ;
AppendMenu (hMenu, MF_STRING | MF_POPUP, hMenuPopup, "&Device") ;

// Create "Channel" popup menu

hMenuPopup = CreateMenu () ;

for (i = 0 ; i < 16 ; i++)
{
wsprintf (szBuffer, "%d", i + 1) ;
AppendMenu (hMenuPopup,
MF_STRING | (i ? MF_UNCHECKED : MF_CHECKED),
IDM_CHANNEL + i, szBuffer) ;
}

AppendMenu (hMenu, MF_STRING | MF_POPUP, hMenuPopup, "&Channel") ;

// Create "Voice" popup menu

hMenuPopup = CreateMenu () ;

for (iFam = 0 ; iFam < 16 ; iFam++)
{
hMenuSubPopup = CreateMenu () ;

for (iIns = 0 ; iIns < 8 ; iIns++)
{
wsprintf (szBuffer, "&%d.\t%s", iIns + 1,
(LPSTR) fam[iFam].inst[iIns].szInst) ;
AppendMenu (hMenuSubPopup,
MF_STRING | (fam[iFam].inst[iIns].iVoice ?
MF_UNCHECKED : MF_CHECKED),
fam[iFam].inst[iIns].iVoice + IDM_VOICE,
szBuffer) ;
}

wsprintf (szBuffer, "&%c.\t%s", 'A' + iFam,
(LPSTR) fam[iFam].szFam) ;
AppendMenu (hMenuPopup, MF_STRING | MF_POPUP, hMenuSubPopup,
szBuffer) ;
}

AppendMenu (hMenu, MF_STRING | MF_POPUP, hMenuPopup, "&Voice") ;

return hMenu ;
}

// Routines for simplifying MIDI output
// ------------------------------------

DWORD MidiOutMessage (HMIDIOUT hMidi, int iStatus, int iChannel,
int iData1, int iData2)
{
DWORD dwMessage ;

dwMessage = iStatus | iChannel | (iData1 << 8) | ((long) iData2 << 16) ;

return midiOutShortMsg (hMidi, dwMessage) ;
}

DWORD MidiNoteOff (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel)
{
return MidiOutMessage (hMidi, 0x080, iChannel, 12 * iOct + iNote, iVel) ;
}

DWORD MidiNoteOn (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel)
{
return MidiOutMessage (hMidi, 0x090, iChannel, 12 * iOct + iNote, iVel) ;
}

DWORD MidiSetPatch (HMIDIOUT hMidi, int iChannel, int iVoice)
{
return MidiOutMessage (hMidi, 0x0C0, iChannel, iVoice, 0) ;
}

DWORD MidiPitchBend (HMIDIOUT hMidi, int iChannel, int iBend)
{
return MidiOutMessage (hMidi, 0x0E0, iChannel, iBend & 0x7F, iBend >> 7) ;
}

// Draw a single key on window
// ---------------------------

VOID DrawKey (HDC hdc, int iScanCode, BOOL fInvert)
{
RECT rc ;

rc.left = 3 * cxCaps * key[iScanCode].xPos / 2 + xOffset ;
rc.top = 3 * cyChar * key[iScanCode].yPos / 2 + yOffset ;
rc.right = rc.left + 3 * cxCaps ;
rc.bottom = rc.top + 3 * cyChar / 2 ;

SetTextColor (hdc, fInvert ? 0x00FFFFFFul : 0x00000000ul) ;
SetBkColor (hdc, fInvert ? 0x00000000ul : 0x00FFFFFFul) ;

FillRect (hdc, &rc, GetStockObject (fInvert ? BLACK_BRUSH : WHITE_BRUSH)) ;

DrawText (hdc, key[iScanCode].szKey, -1, &rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

FrameRect (hdc, &rc, GetStockObject (BLACK_BRUSH)) ;
}

// Process a Key Up or Key Down message
// ------------------------------------

VOID ProcessKey (HDC hdc, WORD message, LONG lParam)
{
int iScanCode, iOctave, iNote ;

iScanCode = 0x0FF & HIWORD (lParam) ;

if (iScanCode >= NUMSCANS) // No scan codes over 53
return ;

if ((iOctave = key[iScanCode].iOctave) == -1) // Non-music key
return ;

if (GetKeyState (VK_SHIFT) < 0)
iOctave += 0x20000000 & lParam ? 2 : 1 ;

if (GetKeyState (VK_CONTROL) < 0)
iOctave -= 0x20000000 & lParam ? 2 : 1 ;

iNote = key[iScanCode].iNote ;

if (message == WM_KEYUP) // For key up
{
MidiNoteOff (hMidiOut, iChannel, iOctave, iNote, 0) ; // Note off
DrawKey (hdc, iScanCode, FALSE) ;
return ;
}

if (0x40000000 & lParam) // ignore typematics
return ;

MidiNoteOn (hMidiOut, iChannel, iOctave, iNote, iVelocity) ; // Note on
DrawKey (hdc, iScanCode, TRUE) ; // Draw the inverted key
}

// Window Procedure
// ----------------

long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam,
LONG lParam)
{
static BOOL bOpened = FALSE ;
char szBuffer [16] ;
DWORD dwExtent ;
HDC hdc ;
HMENU hMenu ;
MIDIOUTCAPS moc ;
PAINTSTRUCT ps ;
short i, iNumDevs, iPitchBend, cxClient, cyClient ;

switch (message)
{
case WM_CREATE:
// Get size of capital letters in system font

hdc = GetDC (hwnd) ;

dwExtent = GetTextExtent (hdc, "M", 1) ;
cxCaps = LOWORD (dwExtent) ;
cyChar = HIWORD (dwExtent) ;

ReleaseDC (hwnd, hdc) ;

// Initialize "Volume" scroll bar

SetScrollRange (hwnd, SB_HORZ, 1, 127, FALSE) ;
SetScrollPos (hwnd, SB_HORZ, iVelocity, TRUE) ;

// Initialize "Pitch Bend" scroll bar

SetScrollRange (hwnd, SB_VERT, 0, 16383, FALSE) ;
SetScrollPos (hwnd, SB_VERT, 8192, TRUE) ;

// Get number of MIDI output devices and set up menu

if (0 == (iNumDevs = midiOutGetNumDevs ()))
{
MessageBeep (MB_ICONSTOP) ;
MessageBox (hwnd, "No MIDI output devices",
szAppName, MB_OK | MB_ICONSTOP) ;
DestroyWindow (hwnd) ;
}
else
{
SetMenu (hwnd, CreateTheMenu (iNumDevs)) ;
}

return 0 ;

case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;

xOffset = (cxClient - 25 * 3 * cxCaps / 2) / 2 ;
yOffset = (cyClient - 11 * cyChar) / 2 + 5 * cyChar ;
return 0 ;

case WM_COMMAND:
hMenu = GetMenu (hwnd) ;

// "Open" menu command

if (wParam == IDM_OPEN && !bOpened)
{
if (midiOutOpen (&hMidiOut, iDevice, NULL, 0L, 0L))
{
MessageBeep (MB_ICONEXCLAMATION) ;
MessageBox (hwnd, "Cannot open MIDI device",
szAppName, MB_OK | MB_ICONEXCLAMATION) ;
}
else
{
CheckMenuItem (hMenu, IDM_OPEN, MF_CHECKED) ;
CheckMenuItem (hMenu, IDM_CLOSE, MF_UNCHECKED) ;

MidiSetPatch (hMidiOut, iChannel, iVoice) ;
bOpened = TRUE ;
}
}

// "Close" menu command

else if (wParam == IDM_CLOSE && bOpened)
{
CheckMenuItem (hMenu, IDM_OPEN, MF_UNCHECKED) ;
CheckMenuItem (hMenu, IDM_CLOSE, MF_CHECKED) ;

// Turn all keys off and close device

for (i = 0 ; i < 16 ; i++)
MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ;

midiOutClose (hMidiOut) ;
bOpened = FALSE ;
}

// Change MIDI "Device" menu command

else if (wParam >= IDM_DEVICE - 1 && wParam < IDM_CHANNEL)
{
CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_UNCHECKED) ;
iDevice = wParam - IDM_DEVICE ;
CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_CHECKED) ;

// Close and reopen MIDI device

if (bOpened)
{
SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ;
SendMessage (hwnd, WM_COMMAND, IDM_OPEN, 0L) ;
}
}

// Change MIDI "Channel" menu command

else if (wParam >= IDM_CHANNEL && wParam < IDM_VOICE)
{
CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_UNCHECKED);
iChannel = wParam - IDM_CHANNEL ;
CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_CHECKED) ;

if (bOpened)
MidiSetPatch (hMidiOut, iChannel, iVoice) ;
}

// Change MIDI "Voice" menu command

else if (wParam >= IDM_VOICE)
{
CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_UNCHECKED) ;
iVoice = wParam - IDM_VOICE ;
CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_CHECKED) ;

if (bOpened)
MidiSetPatch (hMidiOut, iChannel, iVoice) ;
}

InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;

// Process a Key Up or Key Down message

case WM_KEYUP:
case WM_KEYDOWN:
hdc = GetDC (hwnd) ;

if (bOpened)
ProcessKey (hdc, message, lParam) ;

ReleaseDC (hwnd, hdc) ;
return 0 ;

// For Escape, turn off all notes and repaint

case WM_CHAR:
if (bOpened && wParam == 27)
{
for (i = 0 ; i < 16 ; i++)
MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ;

InvalidateRect (hwnd, NULL, TRUE) ;
}
return 0 ;

// Horizontal scroll: Velocity

case WM_HSCROLL:
switch (wParam)
{
case SB_LINEUP: iVelocity -= 1 ; break ;
case SB_LINEDOWN: iVelocity += 1 ; break ;
case SB_PAGEUP: iVelocity -= 8 ; break ;
case SB_PAGEDOWN: iVelocity += 8 ; break ;
case SB_THUMBPOSITION:
iVelocity = LOWORD (lParam) ;
break ;

default:
return 0 ;
}

iVelocity = max (1, min (iVelocity, 127)) ;
SetScrollPos (hwnd, SB_HORZ, iVelocity, TRUE) ;
return 0 ;

// Vertical scroll: Pitch Bend

case WM_VSCROLL:
switch (wParam)
{
case SB_THUMBTRACK:
iPitchBend = 16383 - LOWORD (lParam) ;
break ;

case SB_THUMBPOSITION:
iPitchBend = 8191 ;
break ;

default:
return 0 ;
}

iPitchBend = max (0, min (iPitchBend, 16383)) ;
SetScrollPos (hwnd, SB_VERT, 16383 - iPitchBend, TRUE) ;

if (bOpened)
MidiPitchBend (hMidiOut, iChannel, iPitchBend) ;
return 0 ;

case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;

for (i = 0 ; i < NUMSCANS ; i++)
if (key[i].xPos != -1)
DrawKey (hdc, i, FALSE) ;

midiOutGetDevCaps (iDevice, &moc, sizeof (MIDIOUTCAPS)) ;
wsprintf (szBuffer, "Channel %d", iChannel + 1) ;

TextOut (hdc, cxCaps, 1 * cyChar, bOpened ? "Open" : "Closed",
bOpened ? 4 : 6) ;
TextOut (hdc, cxCaps, 2 * cyChar, moc.szPname,
strlen (moc.szPname)) ;
TextOut (hdc, cxCaps, 3 * cyChar, (LPSTR) szBuffer,
strlen (szBuffer)) ;
TextOut (hdc, cxCaps, 4 * cyChar,
(LPSTR) fam[iVoice / 8].inst[iVoice % 8].szInst,
strlen (fam[iVoice / 8].inst[iVoice % 8].szInst)) ;

EndPaint (hwnd, &ps) ;
return 0 ;

case WM_DESTROY :
SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ;

PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;

}


  3 Responses to “Category : Files from Magazines
Archive   : VOL11N08.ZIP
Filename : KBMIDI.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/