Please try this with #define METHOD1 and also commenting out //#define METHOD1.
Code: Select all | Expand
/*
*
* Piano.prg
* G.N.Rao
*
*/
#include "fiveWin.Ch"
#define METHOD1
#ifdef METHOD1
static aTone := { 130.8, 138.6, 146.8, 155.6, 164.8, 174.6, 185, 196, 207.7, 220, 233.1, 246.9,;
261.7, 277.2, 293.7, 311.1, 329.6,349.2,370, 415.3, 440, 466.2, 493.9, 523.3 }
#else
static aTone := { 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 460, 494, ;
523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, ;
1047,1109,1175,1244,1318,1397,1480,1568,1661,1760,1865,1976, ;
2094,2218,2350,2489,2637,2794,2960,3136,3322,3520,3730,3951, ;
4187 }
#endif
static aWhite, aBlack
// Configuration Parameters
static aDlgMargin := { 20, 20, 20, 20 } // top, left, bottom, right
static nHtWhite := 200
static nWdWhite := 40
static nHtBlack := 120
static nWdBlack := 20
static nDuration := 23
static nKeyPress := 0
static nOctaves := 4
//----------------------------------------------------------------------------//
function Main()
local oDlg, oFont
nOctaves := Min( nOctaves, Int( Len( aTone ) / 12 ) )
PrepareKeys()
DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-10 BOLD
DEFINE DIALOG oDlg FONT oFont SIZE ;
ATail( aWhite )[3][4]+aDlgMargin[ 4 ], aWhite[1][3][3]+aDlgMargin[ 3 ] ;
PIXEL COLOR CLR_BLACK, CLR_HGRAY TITLE "PIANO"
ACTIVATE DIALOG oDlg CENTERED ;
ON PAINT PaintPiano( hDC, oDlg ) ;
ON CLICK PlayPiano( nRow, nCol, oDlg )
RELEASE FONT oFont
return nil
//----------------------------------------------------------------------------//
static function PaintPiano( hDC, oDlg )
local hBrush, hBrush2
local aKey
hBrush := CreateSolidBrush( CLR_WHITE )
for each aKey in aWhite
if aKey[ 1 ] == nKeyPress
hBrush2 := CreateSolidBrush( RGB(255,255,150) )
FillRect( hDC, aKey[ 3 ], hBrush2 )
DeleteObject( hBrush2 )
else
FillRect( hDC, aKey[ 3 ], hBrush )
endif
PaintLabel( hDC, aKey[ 4 ], aKey[ 3 ], oDlg:oFont, CLR_BLACK )
next
DeleteObject( hBrush )
hBrush := CreateSolidBrush( CLR_BLACK )
for each aKey in aBlack
if aKey[ 1 ] == nKeyPress
hBrush2 := CreateSolidBrush( CLR_GRAY )
FillRect( hDC, aKey[ 3 ], hBrush2 )
DeleteObject( hBrush2 )
else
FillRect( hDC, aKey[ 3 ], hBrush )
endif
PaintLabel( hDC, aKey[ 4 ], aKey[ 3 ], oDlg:oFont, CLR_YELLOW )
next
DeleteObject( hBrush )
return nil
//----------------------------------------------------------------------------//
static function PaintLabel( hDC, cLabel, aRect, oFont, nColor )
local nMode
if Len( cLabel ) == 1 // White Key
aRect := AClone( aRect )
aRect[ 1 ] += nHtBlack
endif
nMode := SetBkMode( hDC, 1 )
SetTextColor( hDC, nColor )
oFont:Activate( hDC )
DrawText( hDC, cLabel ,aRect , 0x25 ) // DT_SINGLELINE + DT_VCENTER + DT_CENTER
oFont:DeActivate( hDC )
SetBkMode( hDC, nMode )
return nil
//----------------------------------------------------------------------------//
static function PlayPiano( nRow, nCol, oDlg )
local n, aKey
for each aKey in { aBlack, aWhite }
if nRow >= aKey[ 1 ][ 3 ][ 1 ] .and. nRow < aKey[ 1 ][ 3 ][ 3 ]
for n := 1 to Len( aKey )
if nCol >= aKey[ n ][ 3 ][ 2 ]
if nCol < aKey[ n ][ 3 ][ 4 ]
nKeyPress := aKey[ n ][ 1 ]
oDlg:Refresh()
SysRefresh()
#ifdef METHOD1
TONE( aKey[ n ][ 2 ], nDuration )
#else
TONE_2( aKey[ n ][ 2 ], "1/2" )
#endif
nKeyPress := 0
oDlg:Refresh()
SysRefresh()
return nil
endif
else
EXIT
endif
next
endif
next
return nil
//----------------------------------------------------------------------------//
static function PrepareKeys()
local nGap := 4
local n, x, nTop, nLeft, nBottom
local nOctave
local aLabel := { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }
aWhite := {}
nTop := aDlgMargin[ 1 ]
nLeft := aDlgMargin[ 2 ]
nBottom := nTop + nHtWhite
x := 0
for nOctave := 1 to nOctaves
for each n in { 1, 3, 5, 6, 8, 10, 12 }
AAdd( aWhite, { x + n, aTone[ x + n ], { nTop, nLeft, nBottom, nLeft + nWdWhite }, aLabel[ n ] } )
nLeft += ( nWdWhite + nGap )
next
x += 12
next
aBlack := {}
nLeft := aDlgMargin[ 2 ] + nWdWhite - Int( nWdBlack / 2 )
nBottom := nTop + nHtBlack
x := 0
for nOctave := 1 to nOctaves
for each n in { 2, 4, 7, 9, 11 }
AAdd( aBlack, { x + n, aTone[ x + n ], { nTop, nLeft, nBottom, nLeft + nWdBlack }, aLabel[ n ] } )
nLeft += ( nWdWhite + nGap )
if n == 4
nLeft += ( nWdWhite + nGap )
endif
next
nLeft += ( nWdWhite + nGap )
x += 12
next
return nil
//----------------------------------------------------------------------------//
static function TONE_2( nFreq, cTempo ) // cTempo can be "1/2", "1/4", "1/8"
local nTime
DEFAULT cTempo := "1/2"
nTime := &cTempo
nTime *= 24
return TONE( nFreq, nTime )
//----------------------------------------------------------------------------//
#pragma BEGINDUMP
/*
Author: Andi Jahja <harbour@cbn.net.id>
TONE() for Windows to replace the ugly-heard GT Tone :-)
Mono approach. Duration has been roughly estimated to be Cli**per-like,
please refer to tests/sound.prg.
Using Windows MMsystem, sound card is a must in order to make
this function work.
Syntax: TONE( nFreq, nDuration, [ lSmooth ], [ nVol ] ) -> NIL
nFreq = INTEGER, Tone frequency
nDuration = NUMERIC, Duration Time, as in Cl**per
lSmooth = LOGICAL, pass .F. to disable sound smoothing, default is .T.
nVol = INTEGER, Sound Intensity/Volume, value 0 - 127, Default 127 ( Max )
*/
#include "hbapi.h"
#include <windows.h>
#include <mmsystem.h>
#include <math.h>
#ifndef __XHARBOUR__
#define ISLOG( n ) HB_ISLOG( n )
#define ISNUM( n ) HB_ISNUM( n )
#endif
#define SAMPLING_RATE 44100
void HB_EXPORT hb_winTone( UINT, double, BOOL, UINT );
HB_FUNC( TONE )
{
if ISNUM( 1 )
{
hb_winTone( hb_parni( 1 ),
( ISNUM( 2 ) ? hb_parnd( 2 ) : 1.0 ) * 2100,
ISLOG( 3) ? hb_parl( 3 ) : TRUE,
ISNUM( 4 ) ? hb_parni( 4 ) : 127 );
}
}
/* Keep it here for access from C programs */
void HB_EXPORT hb_winTone( UINT uFrequency, double dwDuration, BOOL bSmoothing, UINT uVolume )
{
WAVEFORMATEX wfx;
HWAVEOUT hWaveOut = NULL;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 1;
wfx.nSamplesPerSec = SAMPLING_RATE;
wfx.nAvgBytesPerSec = SAMPLING_RATE;
wfx.nBlockAlign = 1;
wfx.wBitsPerSample = 8;
wfx.cbSize = 0;
/*
WAVE_MAPPER is the most commonly used device
CallBack is unnecessary since we only play simple tone
*/
if( waveOutOpen( &hWaveOut, WAVE_MAPPER, &wfx, NULL, NULL, CALLBACK_NULL ) == MMSYSERR_NOERROR )
{
char amp = uVolume;
int i;
unsigned char* buffer = (unsigned char*) hb_xgrab( (ULONG) dwDuration );
double dKoef = uFrequency * 2 * 3.14159 / SAMPLING_RATE;
WAVEHDR wh;
if ( buffer )
{
wh.lpData = (LPSTR) buffer;
wh.dwBufferLength = (DWORD) dwDuration;
wh.dwFlags = WHDR_BEGINLOOP;
wh.dwLoops = 1;
if( waveOutPrepareHeader( hWaveOut, &wh, sizeof( wh ) ) == MMSYSERR_NOERROR )
{
wh.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP | WHDR_PREPARED;
wh.dwLoops = 1;
if ( bSmoothing )
{
/*
Manipulating data to smooth sound from clicks at the start
and end (particularly noted when we call TONE() many times
in a row). This is a simulation of increasing volume gradually
before it reaches the peak, and decreasing volume gradually
before it reaches the end.
*/
for( i = 0; i < dwDuration; i++ )
{
if ( i < amp )
{
buffer[ i ] = (unsigned char) ( cos( i * dKoef ) * i + 127 );
}
else if ( dwDuration - i <= amp - 1 )
{
amp = max( 0, --amp );
buffer[ i ] = (unsigned char) ( cos( i * dKoef ) * amp + 127 );
}
else
{
buffer[ i ] = (unsigned char) ( cos( i * dKoef ) * amp + 127 );
}
}
}
else
{
/*
Raw sound, may cause annoying clicks when some tones are played
in a row.
*/
for( i = 0; i < (int) dwDuration; i++ )
{
buffer[ i ] = (unsigned char) ( cos( i * dKoef ) * amp + 127 );
}
}
/*
Play the sound here
*/
if ( waveOutWrite( hWaveOut, &wh, sizeof(WAVEHDR) ) == MMSYSERR_NOERROR )
{
/*
Wait until the sound is finished
*/
while (!(wh.dwFlags & WHDR_DONE))
{
Sleep( 1 );
}
waveOutUnprepareHeader(hWaveOut, &wh, sizeof(WAVEHDR));
}
}
hb_xfree( buffer );
}
}
}
#pragma ENDDUMP
//----------------------------------------------------------------------------//