home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d5xx
/
d566
/
am.lha
/
AM
/
AM.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-21
|
8KB
|
417 lines
/*
* Programm: AM (Algorithmische Musik)
* Aufgabe : Nach Parametern zufällig MIDI-Events erzeugen, sync. durch
* Prg "Takt"
*
* Version : 1.1
*
* Aufruf : AM [-w] [<file [>nil:]]
* -w = mit Parameterfenster
*
* Auto: make AM
*
*/
#include "AM.h"
#include <exec/execbase.h>
#include <dos/dosextens.h>
#include <midi/kawai_k1.h>
#include <string.h>
#include <stdio.h>
//#include <stdlib.h> und
//#include <math.h> klappt nicht!
#if 0
# define D(debug) debug
#else
# define D(debug)
#endif
#define abbruch SIGBREAKF_CTRL_C
//------------------------- Daten anderer Module...
extern struct ExecBase *SysBase;
extern struct Library *DOSBase;
//------------------------- Code anderer Module...
extern BOOL startwindow( void ); // Subtask für GUI starten
extern void closewindow( void ); // Subtask stoppen
//------------------------- Daten dieses Moduls...
struct MidiBase *MidiBase = NULL;
struct MSource *src = NULL;
struct MRoute *outroute = NULL;
struct MRouteInfo outinfo = {
/* SysExs und alle ChannelMsgs passieren diese Route */
MMF_SYSEX+MMF_CHAN, // MsgFlags; s. midi.h
-1, // ChanFlags; -1 = alle
0, // ChanOffset; Kanalverschiebung der Route
0, // NoteOffset; Tonhöhenversch. " "
{ 0,0,0,0 }, // SysExMatch; SysEx-Filter
{ 0,0,0,0 } }; // CtrlMatch; Controller-Filter
struct MsgPort *taktport = NULL;
struct TaktMsg taktmsg;
long taktsig=0, taktmask=0;
long channel = 0, // 0..15
instr = -1, // -1 = keine Änderung
freqmitte = 63, freqabw = 48, // mitte ± abw
volmitte = 63, volabw = 48; // mitte ± abw
double pausen = 0.40, // Pausenhäufigkeit
tonaus = 0.30, // NoteOff-Wahrsch.
volblend = 0.1; // Ein-/Ausblenden
char skala[13] = "999999999999", // Standard = Chromatisch
cskala[12][13]; // Standard = Leer
BOOL mitFenster = FALSE; // Flag für Parameter-Window
//------------------------- Code dieses Moduls...
void init( void );
void closedown( void );
void nextton( void );
LONG Printf( UBYTE *format, ... )
{
return( VPrintf(format, (LONG *)((long)&format + 4L)) );
}
main( int argc, char *argv[] )
{
long sgns;
if( argc > 1 )
{
if( argv[1][0]=='-' && argv[1][1]=='w' )
mitFenster = TRUE;
}
init();
while(1)
{
sgns = Wait( abbruch | taktmask );
if( sgns & taktmask )
{
D(PutStr("TAKT!\n"));
nextton();
SetSignal( 0, taktmask );
}
if( sgns & abbruch )
{
closedown();
}
}
}
void dump_param( void )
{
char buf[8];
long i;
void ftoa( double val, char *buf, int prec, int type );
Printf( "Kanal=%ld\n", channel );
Printf( "Instr=%ld\n", instr );
Printf( "FreqMitte=%ld\n", freqmitte );
Printf( "FreqAbw=%ld\n", freqabw );
Printf( "VolMitte=%ld\n", volmitte );
Printf( "VolAbw=%ld\n", volabw );
ftoa( pausen, buf, 2, 1 );
Printf( "Pausen=%s\n", buf );
ftoa( tonaus, buf, 2, 1 );
Printf( "TonAus=%s\n", buf );
Printf( "Skala=%s\n", skala );
for( i=0; i<=11; i++ )
{
if( cskala[i][0] )
Printf( "CSkala=%02ld:%s\n", i, cskala[i] );
}
Printf( "Ende\n", NULL );
}
BOOL parse_param( char *par )
{
static char key[64];
char *ks = key;
double atof( char * );
long atol( char * );
// Keyword parsen
while( *par != '\0' && *par != '=' )
*ks++ = *par++;
*ks = '\0';
// par hinter '=' positionieren
par++;
if( stricmp(key,"KANAL")==0 )
channel = atol(par);
else if( stricmp(key,"INSTR")==0 )
instr = atol(par);
else if( stricmp(key,"FREQMITTE")==0 )
freqmitte = atol(par);
else if( stricmp(key,"FREQABW")==0 )
freqabw = atol(par);
else if( stricmp(key,"VOLMITTE")==0 )
volmitte = atol(par);
else if( stricmp(key,"VOLABW")==0 )
volabw = atol(par);
else if( stricmp(key,"PAUSEN")==0 )
pausen = atof(par);
else if( stricmp(key,"TONAUS")==0 )
tonaus = atof(par);
else if( stricmp(key,"SKALA")==0 )
strncpy( skala, par, 12 );
else if( stricmp(key,"CSKALA")==0 )
strncpy( cskala[atol(par)], par+3, 12 );
else
return FALSE; // Unbekanntes Keyword -> Ende
// OK
return TRUE;
}
void read_param( void )
{
char buf[512];
memset( cskala, 0, sizeof(cskala) );
D(PutStr( "Bitte Parameter eingeben:\n" ));
while( gets(buf) )
if( !parse_param(buf) )
return; // Eingabe-Ende durch unbekanntes Keyword
}
void init( void )
{
struct MsgPort *p;
char buf[16];
void sran( double );
void ProgChange( int );
D(PutStr("init\n"));
// Parameter einlesen
read_param();
// die Midi.library brauchen wir
MidiBase = OpenLibrary( MIDINAME, MIDIVERSION );
if( !MidiBase ) {
PutStr("Benötigt midi.library!\n");
closedown(); }
// eine Midi-Datenquelle kreieren
sprintf( buf, "AMSource%03ld",
((struct Process *)SysBase->ThisTask)->pr_TaskNum );
src = CreateMSource( buf, NULL );
// und diese auf MidiOut routen
outroute = MRouteSource(src, "MidiOut", &outinfo);
taktport = CreateMsgPort();
taktmsg.tm_msg.mn_ReplyPort = taktport;
taktmsg.tm_msg.mn_Length = sizeof taktmsg;
taktsig = AllocSignal(-1);
taktmask = 1L << taktsig;
taktmsg.tm_op = OP_ADD;
taktmsg.tm_task = SysBase->ThisTask;
taktmsg.tm_sig = taktmask;
Forbid();
if( p = FindPort("TAKT") )
PutMsg( p, &taktmsg );
Permit();
if( p )
{
D(PutStr("OP_ADD abgeschickt\n"));
WaitPort( taktport );
GetMsg( taktport );
if( taktmsg.tm_task )
{
PutStr("Kein Taktslot mehr frei!\n");
closedown();
}
}
else
{
PutStr("Takt läuft nicht!\n");
closedown();
}
D(PutStr("OP_ADD ok\n"));
sran( (double) clock() );
if( instr >= 0 ) ProgChange( instr );
// GUI starten (goodie - egal ob ok)
if( mitFenster )
{
D(PutStr("startwindow...\n"));
startwindow();
}
}
void closedown( void )
{
struct MsgPort *p;
void AllNotesOff( void );
D(PutStr("closedown\n"));
closewindow();
AllNotesOff();
if(outroute) DeleteMRoute(outroute);
if(src) DeleteMSource(src);
if(MidiBase) CloseLibrary(MidiBase);
taktmsg.tm_op = OP_REM;
taktmsg.tm_task = SysBase->ThisTask;
Forbid();
if( p = FindPort("TAKT") )
PutMsg( p, &taktmsg );
Permit();
if( p )
{
WaitPort( taktport );
GetMsg( taktport );
}
FreeSignal( taktsig );
DeleteMsgPort( taktport );
// die (evtl. geänderten) Parameter ausgeben
dump_param();
exit(0);
}
void NoteOn( int note, int vel ) // Ton einschalten
{
UBYTE msg[3];
msg[0] = MS_NOTEON | channel;
msg[1] = note;
msg[2] = vel;
PutMidiMsg(src, msg);
}
void NoteOff( int note ) // Ton ausschalten */
{
UBYTE msg[3];
msg[0] = MS_NOTEOFF | channel;
msg[1] = note;
msg[2] = 64;
PutMidiMsg(src, msg);
}
void AllNotesOff( void ) // Alle Töne ausschalten
{
UBYTE msg[3];
msg[0] = MS_MODE | channel;
msg[1] = MM_ALLOFF;
msg[2] = 0;
PutMidiMsg(src, msg);
}
void ProgChange( int nr ) // Sound wechseln
{
UBYTE msg[3];
msg[0] = MS_PROG | channel;
msg[1] = nr;
msg[2] = 0;
PutMidiMsg(src, msg);
}
void nextton( void )
{
static int last_note = 0;
int vel;
char *akt_skala;
double r, ran();
// ran() ist aus unerfindlichen Gründen hier negativ
// ...wenn hier kein Kommentar steht... oder manchmal... oder...
// ach scheiss drauf
r = fabs(ran());
D(printf("%lf\n",r));
if( r > pausen )
{
// neue Note...
D(PutStr("nextnote\n"));
NoteOff( last_note );
// Nächste erlaubte Note suchen (Skala)
if( *(akt_skala = cskala[ last_note % 12 ]) == 0 )
akt_skala = skala;
last_note = freqmitte + 2 * freqabw * (0.50 - fabs(ran()));
while( akt_skala[ last_note % 12 ] == '0' ) ++last_note;
// Lautstärkegewichtung entsprechend Skala
vel = volmitte + 2 * volabw * (0.50 - fabs(ran()));
vel *= ( akt_skala[ last_note % 12 ] - '0' ) / 9.0;
// Einblendung:
if( volblend < 1.0 )
{
vel *= volblend;
volblend += 0.1;
}
D(printf("key=%d, vel=%d\n",last_note,vel));
NoteOn( last_note, vel );
}
else
{
// Pause: Ton evtl. ausschalten?
D(PutStr("pause\n"));
if( fabs(ran()) < tonaus )
{
NoteOff( last_note );
}
}
}