/* * Programm: AM (Algorithmische Musik) * Aufgabe : Nach Parametern zufällig MIDI-Events erzeugen, sync. durch * Prg "Takt" * * Version : 1.1 * * Aufruf : AM [-w] [nil:]] * -w = mit Parameterfenster * * Auto: make AM * */ #include "AM.h" #include #include #include #include #include //#include und //#include 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 ); } } }