/* Ausgabe einer monofonen Melodie auf PC-Speaker,
* Töne auf Kommandozeile ähnlich Handyklingeltonformat RTTTL / Nokring
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <math.h>
#define elemof(x) (sizeof(x)/sizeof(*(x)))
extern "C" {
int _fltused;
#ifdef _M_IX86
long _declspec(naked) _cdecl _ftol2_sse(void){ _asm{
push eax
fistp dword ptr [esp]
fwait
pop eax
ret
}}
#endif
}
//---------------------------------------------------------------------------
int Note2Freq(int note) {
static const double C = 0.057762265046662109118102676788181; //log (2) / 12;
return (int)(440*exp(note*C)+0.5);
}
int Note2Freq(const char *s) {
int nb = 0; // "Noten-Basis"
if ( *s == '#') {nb++; s++; } // Kreuz als Präfix
// effektiver Kode a b c d e f g h
static const signed char NB[]={0, 1,-9,-7,-5,-4,-2, 2};
register int idx=*s++ - 'a'; // Index zum Zugriff auf Tabelle
if ((unsigned)idx>=elemof(NB)) return 0; // falsche Zeichen -> Pause
nb+=NB[idx];
switch (*s++) { // Postfixe "#", "b", "s" (für "es" und "as")
case '#': nb++; break; // sowie "~is" und "~es" auswerten
case 'b':
case 's': nb--; break;
case 'i': nb++; goto kommt_s;
case 'e': nb--; kommt_s:
if (*s != 's') return 0; // nur "i" oder "e" macht Pause
s++;
break;
default: s--; // kein Postfix: Zeiger zurückstellen
}
return Note2Freq (nb + atoi(s)*12); // Oktave als numerischer Postfix
}
#ifdef _M_IX86
// Wie Windows NT auf allen Windows-Versionen (da fehlt ein shlwapi.Beep?)
BOOL MyBeep(DWORD dwFreq, DWORD dwDuration) {
if ((long)GetVersion()>=0) return Beep(dwFreq,dwDuration);
else{ // Win32s, Win9x/Me
if (dwFreq<1843200L/0x10000/2) return FALSE;
dwFreq=1843200L/2/dwFreq; // Teilerwert
_asm{
cli
mov al,0xB6 // Timer2: Rechteckgenerator, 16bit
out 0x43,al
mov eax,dwFreq
out 0x42,al // Timer2: Endwert Low-Teil setzen
xchg ah,al
out 0x42,al // Timer2: Endwert High-Teil setzen
in al,0x61
or al,0x03
out 0x61,al // Ein- und Ausgang des Timer2 freischalten
sti
}
Sleep(dwDuration);
_asm{
cli
in al,0x61
and al,~0x03
out 0x61,al // Ein- und Ausgang des Timer2 sperren
sti
}
return TRUE;
}
}
#else
# define MyBeep(f,d) Beep(f,d)
#endif
void PlayNote(const char *s) { // Spielt die angegebene Note
int laen = atoi(s); // Länge
while (*s>='0' && *s<='9') s++;
if (laen <= 0) laen = 4; // Wenn nicht angegeben: Viertelnote
int ms = 1000/laen; // Hier: Ganze Note = 1 Sekunde
if (*s == '.') { ms += ms>>1; s++; } // Punktierte Note = 1½fache Länge
int hz = Note2Freq(s); // String-Rest macht Tonhöhe
if (hz <= 0) Sleep(ms); // Pause oder Ton
else MyBeep(hz, ms);
}
extern "C" int CALLBACK WinMainCRTStartup() {
char *lpCmdLine=GetCommandLine();
for (;;) {
while (*lpCmdLine==' ') lpCmdLine++; // Führende Leerzeichen wegparsen
LPSTR p=strchr(lpCmdLine,' ');// aufs nächste Leerzeichen
if (p) *p='\0'; // Wenn vorhanden, dann wegpatchen
PlayNote(lpCmdLine);
if (!p) break; // raus!
lpCmdLine=p+1; // HINTER das (eine) Leerzeichen
}
return 0;
}
Detected encoding: ANSI (CP1252) | 4
|
|