Exemple #1
0
void
KeyItem::DrawMods(BView *view, BRect r, int32 mod)
{
	float w = -(r.Width()+2);

	if (mod & B_SHIFT_KEY) {
		DrawKey(view, r, "S");
		r.OffsetBy(w,0);
	}

	if (mod & B_CONTROL_KEY) {
		DrawKey(view, r, "C");
		r.OffsetBy(w,0);
	}

	if (mod & B_OPTION_KEY) {
		DrawKey(view, r, "O");
		r.OffsetBy(w,0);
	}

	if ((mod & B_COMMAND_KEY)) {
		DrawKey(view, r, "A");
		r.OffsetBy(w,0);
	}
}
Exemple #2
0
VOID ProcessKey (HDC hdc, UINT message, LPARAM 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
}
Exemple #3
0
void
KeyItem::DrawItem(BView *view, BRect rect, bool all)
{
	BFont font;
	view->GetFont(&font);

	if (m_id == -1) {				// Draw the Outline
		if (IsSelected())
			view->SetLowColor(150,190,230);
		else
			view->SetLowColor(255,255,255);

		view->FillRect(rect, B_SOLID_LOW);
		view->SetHighColor(0,0,0);
		view->SetFont(be_bold_font);
		view->DrawString( Label(), BPoint( rect.left +5, rect.top +font.Size() ));
		view->SetFont(&font);
		return;
	}

	const char *key;

	StringItem::DrawItem(view, rect, all);

	view->SetHighColor(240,240,240);
	view->StrokeLine( BPoint(rect.left, rect.bottom), BPoint(rect.right, rect.bottom));
	view->SetHighColor(0,0,0);

	float x = rect.left + rect.Width()/2 +(font.Size()+4)*3;	// max 3 combinations

	DrawMods(view, BRect( x - font.Size() - 6, rect.top+1, x -4, rect.bottom-1), m_mod);

	if (m_key >' ' && m_key < 'a') {
		view->DrawChar( m_key, BPoint( x, rect.top +font.Size() ));
	} else if (m_key) {
		key = _KeyLabel(m_key);
		DrawKey(view, BRect(x-2, rect.top+1, x+font.StringWidth(key)+2, rect.bottom-1), key);
	}

	x = rect.right - 32;

	DrawMods(view, BRect( x - font.Size() - 6, rect.top+1, x -4, rect.bottom-1), m_mod2);

	if (m_key2 >' ' && m_key2 < 'a') {
		view->DrawChar( m_key2, BPoint( x, rect.top +font.Size() ));
	} else if (m_key2) {
		key = _KeyLabel(m_key2);
		DrawKey(view, BRect(x-2, rect.top+1, x+font.StringWidth(key)+2, rect.bottom-1), key);
	}
}
Exemple #4
0
float KeyControl::DrawMods(BRect r, int32 mod)
{
	float w = (r.Width()+2);
	if ((mod & B_COMMAND_KEY)){
		DrawKey(r, "A");
		r.OffsetBy(w,0);
	}
	if (mod & B_OPTION_KEY){
		DrawKey(r, "O");
		r.OffsetBy(w,0);
	}
	if (mod & B_CONTROL_KEY){
		DrawKey(r, "C");
		r.OffsetBy(w,0);
	}
	if (mod & B_SHIFT_KEY){
		DrawKey(r, "S");
		r.OffsetBy(w,0);
	}
	return r.left+4;
}
Exemple #5
0
void OCPiano::Paint()
{
    //Scene.clear();
    ClearTransparent();
    for (int i=1;i<128;i++)
    {
        if (!IsBlackKey(i)) DrawKey(i,Pitches.contains(i) || (i==CurrentPitch));
    }
    for (int i=1;i<128;i++)
    {
        if (IsBlackKey(i)) DrawKey(i,Pitches.contains(i) || (i==CurrentPitch));
    }

    SetPenBrush(Qt::black,Qt::darkGray);
    QPainterPath p(QPoint(PitchToPos(60)+2,WhiteKeyHeight+5));
    p.lineTo(PitchToPos(60)+2+((WhiteKeyWidth-4)/2),WhiteKeyHeight);
    p.lineTo(PitchToPos(60)+WhiteKeyWidth-2,WhiteKeyHeight+5);
    Path(p);

    //Scene.addPath(p,QPen(Qt::black),QBrush(Qt::darkGray));
    //this->viewport()->update();
    update();
}
Exemple #6
0
void
KeyControl::Draw(BRect r)
{
	BFont font;
	GetFont(&font);
	font_height fh;
	font.GetHeight(&fh);
	float y = Bounds().bottom - (float)ceil(fh.descent);

	const char* key;

	SetHighColor(0,0,0);
	DrawString( Label(), BPoint(2.0, y));

	r = Bounds();
	r.left = Divider();

	if (IsFocus())
		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
	else
		SetHighColor(0,0,0);

	StrokeRect(r);
	r.InsetBy(1,1);
	SetHighColor( 255,255,255 );
	FillRect(r);
	SetHighColor(0,0,0);
	r.InsetBy(1,1);

	float x = DrawMods(
		BRect(r.left, r.top+1, r.left+font.Size()+6, r.bottom-1), fMod);

	if (fKey >' ' && fKey < 'a')
		DrawChar( fKey, BPoint( x, r.bottom - (float)ceil(fh.descent)));
	else if (fKey) {
		key = _KeyLabel(fKey);
		DrawKey(BRect(x-2, r.top+1, x+font.StringWidth(key)+2, r.bottom-1), key);
	}
}
Exemple #7
0
void Options::Draw()
{
	SetDrawBlendMode(DX_BLENDMODE_ALPHA, 120); //透過
	DrawBox(0, 0, 640, 480, black, TRUE); //明るい背景を暗くする
	if (!keyconfigflag)
	{
		DrawBox(0, 25, 100, 55, yellow, TRUE);
		SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0); //元に戻す
		DrawExtendString(20, 30, 1.5, 1.5, "Option", black);
		DrawBox(0, choosenow * 25 + 65, 640, (choosenow + 1) * 25 + 65, yellow, TRUE);
		for (int i = 0; i < option_max; i++)
		{
			DrawFormatString(200 - GetDrawFormatStringWidth("%s", option_list[i]), i * 25 + 70, (choosenow == i ? black : white), "%s", option_list[i]);
		}
		DrawString(400, (option_max - 2) * 25 + 70, "設定", (choosenow == option_max - 2 ? black : white));
	}
	else
	{
		DrawBox(0, 25, 200, 55, yellow, TRUE);
		SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0); //元に戻す
		DrawExtendString(20, 30, 1.5, 1.5, "KeyConfig", black);
		DrawString(222, 35, "キーボード", white);
		DrawString(422, 35, "ゲームパッド", white);


		DrawBox(0, choosenow_keyconfig * 20 + 58, 640, (choosenow_keyconfig + 1) * 20 + 58, (keyconfingflag?black:yellow), TRUE);
		for (int i = 0; i < key_name_max - 1; i++)
		{
			DrawFormatString(160, i * 20 + 60, (choosenow_keyconfig == i ? black : white),"%s",key_name_list[i]);
			DrawKey(260, i * 20 + 60, key_deside_temp[i]);
		}
		DrawString(60, (key_name_max - 1) * 20 + 60, "設定を反映して戻る", (choosenow_keyconfig == 8 ? black : white));
	}
	SetDrawBlendMode(DX_BLENDMODE_ALPHA, 144); //透過
	DrawBox(0, 0, 640, 20, blue, TRUE); //説明欄
	SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0); //元に戻す

	DrawFormatString(22, 2, white, "%s", option_explanation[choosenow], TRUE); //説明しよう
}
Exemple #8
0
void KeyControl::Draw(BRect r)
{
	BFont font;
	GetFont(&font);
	font_height fh;
	font.GetHeight(&fh);
	float y = Bounds().bottom - ceil(fh.descent);

	const char *key;

	SetHighColor(0,0,0);
	DrawString( Label(), BPoint(2.0, y));

	r = Bounds();
	r.left = Divider();
	if (IsFocus())
		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
	else
		SetHighColor(0,0,0);

	StrokeRect(r);
	r.InsetBy(1,1);
	SetHighColor( 255,255,255 );
	FillRect(r);
	SetHighColor(0,0,0);
	r.InsetBy(1,1);

	float x = DrawMods(BRect( r.left, r.top+1, r.left +font.Size()+6, r.bottom-1), m_mod);
	if (m_key >' ' && m_key < 'a'){
		DrawChar( m_key, BPoint( x, r.bottom - ceil(fh.descent)));
	}else if (m_key){
		switch(m_key){
		case ' ':	key = "   ";	break;
		case 1:		key = "Home";	break;
		case 4:		key = "End";	break;
		case 5:		key = "Ins";	break;
		case 8:		key = "BS ";	break;
		case 9:		key = "Tab";	break;
		case 10:	key = "Return";	break;
		case 11:	key = "PgUp";	break;
		case 12:	key = "PgDown";	break;
		case 14:	key = "F1";		break;
		case 15:	key = "F2";		break;
		case 16:	key = "F3";		break;
		case 17:	key = "F4";		break;
		case 18:	key = "F5";		break;
		case 19:	key = "F6";		break;
		case 20:	key = "F7";		break;
		case 21:	key = "F8";		break;
		case 22:	key = "F9";		break;
		case 23:	key = "F10";	break;
		case 24:	key = "F11";	break;
		case 25:	key = "F12";	break;
		case 27:	key = "Esc";	break;
		case 28:	key = "Left";	break;
		case 29:	key = "Right";	break;
		case 30:	key = "Up";		break;
		case 31:	key = "Down";	break;
		case 127:	key = "Del";	break;
		default:	key = "???";	break;
		}

		DrawKey(BRect(x-2, r.top+1, x+font.StringWidth(key)+2, r.bottom-1), key);
	}
}
Exemple #9
0
void KeyItem::DrawItem(BView *view, BRect rect, bool all)
{
	BFont font;
	view->GetFont(&font);

	if (m_id == -1){				// Draw the Outline
		rgb_color bgColor;

		if (IsSelected())
			bgColor = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR);
		else
			bgColor = ui_color(B_LIST_BACKGROUND_COLOR);

		view->SetHighColor(bgColor);
		view->SetLowColor(bgColor);
		view->FillRect(rect, B_SOLID_LOW);

		if (IsSelected())
			view->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
		else
			view->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));

		view->SetFont(be_bold_font);
		view->DrawString( Text(), BPoint( rect.left +5, rect.top +font.Size() +3 ));
		view->SetFont(&font);
		return;
	}

	const char *key;

	BStringItem::DrawItem(view, rect, all);

	view->SetHighColor(240,240,240);
	view->StrokeLine( BPoint(rect.left, rect.bottom), BPoint(rect.right, rect.bottom));
	if (IsSelected()) {
		view->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
		view->SetLowColor(ui_color(B_LIST_SELECTED_BACKGROUND_COLOR));
	}
	else {
		view->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
		view->SetLowColor(ui_color(B_LIST_BACKGROUND_COLOR));
	}

	float x = rect.left + rect.Width()/2 +(font.Size()+4)*3;	// max 3 combinations
	DrawMods(view, BRect( x - font.Size() - 6, rect.top+1, x -4, rect.bottom-1), m_mod);
	if (m_key >' ' && m_key < 'a'){
		view->DrawChar( m_key, BPoint( x, rect.top +font.Size() ));
	}else if (m_key){
		switch(m_key){
		case ' ':	key = "   ";	break;
		case 1:		key = "Home";	break;
		case 4:		key = "End";	break;
		case 5:		key = "Ins";	break;
		case 8:		key = "BS ";	break;
		case 9:		key = "Tab";	break;
		case 10:	key = "Return";	break;
		case 11:	key = "PgUp";	break;
		case 12:	key = "PgDown";	break;
		case 14:	key = "F1";		break;
		case 15:	key = "F2";		break;
		case 16:	key = "F3";		break;
		case 17:	key = "F4";		break;
		case 18:	key = "F5";		break;
		case 19:	key = "F6";		break;
		case 20:	key = "F7";		break;
		case 21:	key = "F8";		break;
		case 22:	key = "F9";		break;
		case 23:	key = "F10";	break;
		case 24:	key = "F11";	break;
		case 25:	key = "F12";	break;
		case 27:	key = "Esc";	break;
		case 28:	key = "Left";	break;
		case 29:	key = "Right";	break;
		case 30:	key = "Up";		break;
		case 31:	key = "Down";	break;
		case 127:	key = "Del";	break;
		default:	key = "???";	break;
		}

		DrawKey(view, BRect(x-2, rect.top+1, x+font.StringWidth(key)+2, rect.bottom-1), key);
	}

	x = rect.right - 32;
	DrawMods(view, BRect( x - font.Size() - 6, rect.top+1, x -4, rect.bottom-1), m_mod2);

	if (m_key2 >' ' && m_key2 < 'a'){
		view->DrawChar( m_key2, BPoint( x, rect.top +font.Size() ));
	}else if (m_key2){
		switch(m_key2){
		case ' ':	key = " ";		break;
		case 1:		key = "Home";	break;
		case 4:		key = "End";	break;
		case 5:		key = "Ins";	break;
		case 8:		key = "BS ";	break;
		case 9:		key = "Tab";	break;
		case 10:	key = "Return";	break;
		case 11:	key = "PgUp";	break;
		case 12:	key = "PgDown";	break;
		case 14:	key = "F1";		break;
		case 15:	key = "F2";		break;
		case 16:	key = "F3";		break;
		case 17:	key = "F4";		break;
		case 18:	key = "F5";		break;
		case 19:	key = "F6";		break;
		case 20:	key = "F7";		break;
		case 21:	key = "F8";		break;
		case 22:	key = "F9";		break;
		case 23:	key = "F10";	break;
		case 24:	key = "F11";	break;
		case 25:	key = "F12";	break;
		case 27:	key = "Esc";	break;
		case 28:	key = "Left";	break;
		case 29:	key = "Right";	break;
		case 30:	key = "Up";		break;
		case 31:	key = "Down";	break;
		case 127:	key = "Del";	break;
		default:	key = "???";	break;
		}

		DrawKey(view, BRect(x-2, rect.top+1, x+font.StringWidth(key)+2, rect.bottom-1), key);
	}
}
Exemple #10
0
/*virtual*/ void CWndTuner::OnPaint() {
  static int nLastNote = -1;
  static int nLastCents = -999;

  CRect rcClient(m_rcClient);
  rcClient.top += 74;
  // BIOS::LCD::Bar(rcClient, RGB565(FFFFFF));
  if (!m_bWave) {
    BIOS::LCD::Bar(m_rcClient, RGB565(FFFFFF));
    BIOS::LCD::Bar(m_rcClient.left, m_rcClient.bottom - 16, m_rcClient.right,
                   m_rcClient.bottom, RGB565(b0b0b0));
    CBitmap bmp;
    bmp.Load(bitmapTuner);
    bmp.Blit(70, 32);

    DrawPiano();
    DrawScale();

    CRect rcScale(200, 120, 340, 132);
    BIOS::LCD::Print(rcScale.CenterX() - 5 * 4, rcScale.bottom + 2,
                     RGB565(000000), RGBTRANS, "cents");
    BIOS::LCD::Print(240, BIOS::LCD::LcdHeight - 41, RGB565(ff0000), RGBTRANS,
                     "Spectrum");
  }

  float fBestFreq = GetFundamental();
  if (fBestFreq == 0) {
    BIOS::LCD::Bar(m_rcClient.left, m_rcClient.bottom - 16, m_rcClient.right,
                   m_rcClient.bottom, RGB565(b0b0b0));
    BIOS::LCD::Print(4, BIOS::LCD::LcdHeight - 16, RGB565(000000),
                     RGB565(b0b0b0), "No signal detected");

    if (nLastNote >= 0) {
      DrawKey(nLastNote, false);
      nLastNote = -1;
    }
    if (nLastCents != -999) {
      DrawCents(nLastCents, false);
      nLastCents = -999;
    }
    return;
  }

  float fNote =
      log(fBestFreq / 440.0f) / log(2.0f) * 12.0f + 9 + 12 * 4;  // 440Hz -> A4

  int nBaseNote = (int)floor(fNote + 0.5f);  // +50 cents
  int nOctave = nBaseNote / 12;
  int nNote = nBaseNote % 12;
  int nCents = (int)((fNote - nBaseNote) * 100.0f);

  if (nNote < 0) {
    BIOS::LCD::Bar(m_rcClient.left, m_rcClient.bottom - 16, m_rcClient.right,
                   m_rcClient.bottom, RGB565(b0b0b0));
    BIOS::LCD::Print(4, BIOS::LCD::LcdHeight - 16, RGB565(000000),
                     RGB565(b0b0b0), "Invalid signal");

    if (nLastNote >= 0) {
      DrawKey(nLastNote, false);
      nLastNote = -1;
    }
    if (nLastCents != -999) {
      DrawCents(nLastCents, false);
      nLastCents = -999;
    }
    return;
  }

  const char *notes[] = {"C-", "C#", "D-", "D#", "E-", "F-",
                         "F#", "G-", "G#", "A-", "A#", "B-"};
  BIOS::LCD::Printf(4, BIOS::LCD::LcdHeight - 16, RGB565(000000),
                    RGB565(b0b0b0), "%1f Hz -> Note: %s%d %c%d cents   ",
                    fBestFreq, notes[nNote], nOctave, nCents >= 0 ? '+' : '-',
                    ABS(nCents));

  if (nLastNote > -1) DrawKey(nLastNote, false);
  nLastNote = nNote;
  DrawKey(nNote, true);

  if (nLastCents != -999) DrawCents(nLastCents, false);
  nLastCents = nCents;
  DrawCents(nLastCents, true);
}
int GUIKeyboard::Render(void)
{
	if (!isConditionTrue())
	{
		mRendered = false;
		return 0;
	}

	Layout& lay = layouts[currentLayout - 1];

	bool drawKeys = false;
	if (lay.keyboardImg && lay.keyboardImg->GetResource())
		// keyboard is image based
		gr_blit(lay.keyboardImg->GetResource(), 0, 0, mRenderW, mRenderH, mRenderX, mRenderY);
	else {
		// keyboard is software drawn
		// fill background
		gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, mBackgroundColor.alpha);
		gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);
		drawKeys = true;
	}

	// draw keys
	int y1 = 0;
	for (int row = 0; row < MAX_KEYBOARD_ROWS; ++row) {
		int rowY = mRenderY + y1;
		int rowH = lay.row_end_y[row] - y1;
		y1 = lay.row_end_y[row];
		int x1 = 0;
		for (int col = 0; col < MAX_KEYBOARD_KEYS; ++col) {
			Key& key = lay.keys[row][col];
			int keyY = rowY;
			int keyH = rowH;
			int keyX = mRenderX + x1;
			int keyW = key.end_x - x1;
			x1 = key.end_x;

			// Draw key for software drawn keyboard
			if (drawKeys)
				DrawKey(key, keyX, keyY, keyW, keyH);

			// Draw highlight for capslock
			if (hasCapsHighlight && lay.is_caps && CapsLockOn && (int)key.key == KEYBOARD_LAYOUT && key.layout == lay.revert_layout) {
				gr_color(mCapsHighlightColor.red, mCapsHighlightColor.green, mCapsHighlightColor.blue, mCapsHighlightColor.alpha);
				gr_fill(keyX, keyY, keyW, keyH);
			}

			// Highlight current key
			if (hasHighlight && &key == currentKey && highlightRenderCount != 0) {
				gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha);
				gr_fill(keyX, keyY, keyW, keyH);
			}
		}
	}

	if (!hasHighlight || highlightRenderCount == 0)
		mRendered = true;
	else if (highlightRenderCount > 0)
		highlightRenderCount--;
	return 0;
}
Exemple #12
0
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static BOOL bOpened = FALSE ;
     HDC         hdc ;
     HMENU       hMenu ;
     int         i, iNumDevs, iPitchBend, cxClient, cyClient ;
     MIDIOUTCAPS moc ;
     PAINTSTRUCT ps ;
     SIZE        size ;
     TCHAR       szBuffer [16] ;
     
     switch (message)
     {
     case WM_CREATE:
               // Get size of capital letters in system font
          
          hdc = GetDC (hwnd) ;
          
          GetTextExtentPoint (hdc, TEXT ("M"), 1, &size) ;
          cxCaps = size.cx ;
          cyChar = size.cy ;
          
          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, TEXT ("No MIDI output devices!"),
                                 szAppName, MB_OK | MB_ICONSTOP) ;
               return -1 ;
          }
          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 (LOWORD (wParam) == IDM_OPEN && !bOpened)
          {
               if (midiOutOpen (&hMidiOut, iDevice, 0, 0, 0))
               {
                    MessageBeep (MB_ICONEXCLAMATION) ;
                    MessageBox (hwnd, TEXT ("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 (LOWORD (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 (LOWORD (wParam) >= IDM_DEVICE - 1 && 
                   LOWORD (wParam) <  IDM_CHANNEL)
          {
               CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_UNCHECKED) ;
               iDevice = LOWORD (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 (LOWORD (wParam) >= IDM_CHANNEL && 
                   LOWORD (wParam) <  IDM_VOICE)
          {
               CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_UNCHECKED);
               iChannel = LOWORD (wParam) - IDM_CHANNEL ;
               CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_CHECKED) ;
               
               if (bOpened)
                    MidiSetPatch (hMidiOut, iChannel, iVoice) ;
          }
          
               // Change MIDI "Voice" menu command
          
          else if (LOWORD (wParam) >= IDM_VOICE)
          {
               CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_UNCHECKED) ;
               iVoice = LOWORD (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 (LOWORD (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 = HIWORD (wParam) ;  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 (LOWORD (wParam))
          {
          case SB_THUMBTRACK:    iPitchBend = 16383 - HIWORD (wParam) ;  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, TEXT ("Channel %i"), iChannel + 1) ;
     
          TextOut (hdc, cxCaps, 1 * cyChar, 
                        bOpened ? TEXT ("Open") : TEXT ("Closed"),
                        bOpened ? 4 : 6) ;
          TextOut (hdc, cxCaps, 2 * cyChar, moc.szPname,
                        lstrlen (moc.szPname)) ;
          TextOut (hdc, cxCaps, 3 * cyChar, szBuffer, lstrlen (szBuffer)) ;
          TextOut (hdc, cxCaps, 4 * cyChar,
                        fam[iVoice / 8].inst[iVoice % 8].szInst,
               lstrlen (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) ;
}