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 >
C/C++ Source or Header  |  1991-11-21  |  8KB  |  417 lines

  1. /*
  2.  * Programm: AM (Algorithmische Musik)
  3.  * Aufgabe : Nach Parametern zufällig MIDI-Events erzeugen, sync. durch
  4.  *           Prg "Takt"
  5.  * 
  6.  * Version : 1.1
  7.  * 
  8.  * Aufruf  : AM [-w] [<file [>nil:]]
  9.  *               -w = mit Parameterfenster
  10.  *
  11.  * Auto: make AM
  12.  *
  13.  */
  14.  
  15.  
  16. #include "AM.h"
  17. #include <exec/execbase.h>
  18. #include <dos/dosextens.h>
  19. #include <midi/kawai_k1.h>
  20. #include <string.h>
  21. #include <stdio.h>
  22. //#include <stdlib.h>    und
  23. //#include <math.h>        klappt nicht!
  24.  
  25.  
  26. #if 0
  27. # define D(debug) debug
  28. #else
  29. # define D(debug)
  30. #endif
  31.  
  32. #define abbruch SIGBREAKF_CTRL_C
  33.  
  34.  
  35. //------------------------- Daten anderer Module...
  36.  
  37.  
  38. extern struct ExecBase    *SysBase;
  39. extern struct Library    *DOSBase;
  40.  
  41.  
  42. //------------------------- Code anderer Module...
  43.  
  44.  
  45. extern BOOL startwindow( void ); // Subtask für GUI starten
  46. extern void closewindow( void ); // Subtask stoppen
  47.  
  48.  
  49. //------------------------- Daten dieses Moduls...
  50.  
  51.  
  52. struct MidiBase        *MidiBase = NULL;
  53. struct MSource        *src = NULL;
  54. struct MRoute        *outroute = NULL;
  55.  
  56. struct MRouteInfo outinfo = {
  57.     /* SysExs und alle ChannelMsgs passieren diese Route */
  58.     MMF_SYSEX+MMF_CHAN,        // MsgFlags; s. midi.h
  59.     -1,                        // ChanFlags; -1 = alle
  60.     0,                        // ChanOffset; Kanalverschiebung der Route
  61.     0,                        // NoteOffset; Tonhöhenversch.    "    "
  62.     { 0,0,0,0 },            // SysExMatch; SysEx-Filter
  63.     { 0,0,0,0 } };            // CtrlMatch; Controller-Filter
  64.  
  65.  
  66. struct MsgPort        *taktport = NULL;
  67. struct TaktMsg        taktmsg;
  68. long                taktsig=0, taktmask=0;
  69.  
  70.  
  71. long                channel = 0,                    // 0..15
  72.                     instr = -1,                        // -1 = keine Änderung
  73.                     freqmitte = 63, freqabw = 48,    // mitte ± abw
  74.                     volmitte = 63, volabw = 48;        // mitte ± abw
  75. double                pausen = 0.40,                    // Pausenhäufigkeit
  76.                     tonaus = 0.30,                    // NoteOff-Wahrsch.
  77.                     volblend = 0.1;                    // Ein-/Ausblenden
  78. char                skala[13] = "999999999999",        // Standard = Chromatisch
  79.                     cskala[12][13];                    // Standard = Leer
  80.  
  81.  
  82. BOOL                mitFenster = FALSE;            // Flag für Parameter-Window
  83.  
  84.  
  85. //------------------------- Code dieses Moduls...
  86.  
  87.  
  88. void init( void );
  89. void closedown( void );
  90. void nextton( void );
  91.  
  92.  
  93. LONG Printf( UBYTE *format, ... )
  94. {
  95.     return( VPrintf(format, (LONG *)((long)&format + 4L)) );
  96. }
  97.  
  98.  
  99. main( int argc, char *argv[] )
  100. {
  101.     long sgns;
  102.     
  103.     if( argc > 1 )
  104.     {
  105.         if( argv[1][0]=='-' && argv[1][1]=='w' )
  106.             mitFenster = TRUE;
  107.     }
  108.     init();
  109.     
  110.     while(1)
  111.     {
  112.     
  113.         sgns = Wait( abbruch | taktmask );
  114.         
  115.         if( sgns & taktmask )
  116.         {
  117.             D(PutStr("TAKT!\n"));
  118.             
  119.             nextton();
  120.             SetSignal( 0, taktmask );
  121.         }
  122.             
  123.         if( sgns & abbruch )
  124.         {
  125.             closedown();
  126.         }
  127.         
  128.     }
  129. }
  130.  
  131.  
  132. void dump_param( void )
  133. {
  134.     char buf[8];
  135.     long i;
  136.     void ftoa( double val, char *buf, int prec, int type );
  137.  
  138.     Printf( "Kanal=%ld\n",        channel );
  139.     Printf( "Instr=%ld\n",        instr );
  140.     Printf( "FreqMitte=%ld\n",    freqmitte );
  141.     Printf( "FreqAbw=%ld\n",    freqabw );
  142.     Printf( "VolMitte=%ld\n",     volmitte );
  143.     Printf( "VolAbw=%ld\n",     volabw );
  144.     ftoa( pausen, buf, 2, 1 );
  145.     Printf( "Pausen=%s\n", buf );
  146.     ftoa( tonaus, buf, 2, 1 );
  147.     Printf( "TonAus=%s\n", buf );
  148.     Printf( "Skala=%s\n", skala );
  149.     
  150.     for( i=0; i<=11; i++ )
  151.     {
  152.         if( cskala[i][0] )
  153.             Printf( "CSkala=%02ld:%s\n", i, cskala[i] );
  154.     }
  155.     
  156.     Printf( "Ende\n", NULL );
  157. }
  158.  
  159.  
  160. BOOL parse_param( char *par )
  161. {
  162.     static char key[64];
  163.     char *ks = key;
  164.     double atof( char * );
  165.     long atol( char * );
  166.     
  167.     // Keyword parsen
  168.     while( *par != '\0' && *par != '=' )
  169.         *ks++ = *par++;
  170.     *ks = '\0';
  171.     // par hinter '=' positionieren
  172.     par++;
  173.     
  174.     if(      stricmp(key,"KANAL")==0 )
  175.         channel = atol(par);
  176.     else if( stricmp(key,"INSTR")==0 )
  177.         instr = atol(par);
  178.     else if( stricmp(key,"FREQMITTE")==0 )
  179.         freqmitte = atol(par);
  180.     else if( stricmp(key,"FREQABW")==0 )
  181.         freqabw = atol(par);
  182.     else if( stricmp(key,"VOLMITTE")==0 )
  183.         volmitte = atol(par);
  184.     else if( stricmp(key,"VOLABW")==0 )
  185.         volabw = atol(par);
  186.     else if( stricmp(key,"PAUSEN")==0 )
  187.         pausen = atof(par);
  188.     else if( stricmp(key,"TONAUS")==0 )
  189.         tonaus = atof(par);
  190.     else if( stricmp(key,"SKALA")==0 )
  191.         strncpy( skala, par, 12 );
  192.     else if( stricmp(key,"CSKALA")==0 )
  193.         strncpy( cskala[atol(par)], par+3, 12 );
  194.     else
  195.         return FALSE; // Unbekanntes Keyword -> Ende
  196.     
  197.     // OK
  198.     return TRUE;
  199. }
  200.  
  201.  
  202. void read_param( void )
  203. {
  204.     char buf[512];
  205.  
  206.     memset( cskala, 0, sizeof(cskala) );
  207.     D(PutStr( "Bitte Parameter eingeben:\n" ));
  208.     
  209.     while( gets(buf) )
  210.         if( !parse_param(buf) )
  211.             return;                    // Eingabe-Ende durch unbekanntes Keyword
  212. }
  213.  
  214.  
  215. void init( void )
  216. {
  217.     struct MsgPort *p;
  218.     char buf[16];
  219.     void sran( double );
  220.     void ProgChange( int );
  221.     
  222.     D(PutStr("init\n"));
  223.     
  224.     // Parameter einlesen
  225.     read_param();
  226.     
  227.     // die Midi.library brauchen wir
  228.     MidiBase = OpenLibrary( MIDINAME, MIDIVERSION );
  229.     if( !MidiBase ) {
  230.         PutStr("Benötigt midi.library!\n");
  231.         closedown(); }
  232.     
  233.     // eine Midi-Datenquelle kreieren
  234.     sprintf( buf, "AMSource%03ld",
  235.         ((struct Process *)SysBase->ThisTask)->pr_TaskNum );
  236.     src = CreateMSource( buf, NULL );
  237.     
  238.     // und diese auf MidiOut routen
  239.     outroute = MRouteSource(src, "MidiOut", &outinfo);
  240.     
  241.     taktport = CreateMsgPort();
  242.     taktmsg.tm_msg.mn_ReplyPort = taktport;
  243.     taktmsg.tm_msg.mn_Length = sizeof taktmsg;
  244.     
  245.     taktsig  = AllocSignal(-1);
  246.     taktmask = 1L << taktsig;
  247.     
  248.     taktmsg.tm_op   = OP_ADD;
  249.     taktmsg.tm_task = SysBase->ThisTask;
  250.     taktmsg.tm_sig  = taktmask;
  251.     
  252.     Forbid();
  253.      if( p = FindPort("TAKT") )
  254.       PutMsg( p, &taktmsg );
  255.     Permit();
  256.     
  257.     if( p )
  258.     {
  259.         D(PutStr("OP_ADD abgeschickt\n"));
  260.         WaitPort( taktport );
  261.         GetMsg( taktport );
  262.         if( taktmsg.tm_task )
  263.         {
  264.             PutStr("Kein Taktslot mehr frei!\n");
  265.             closedown();
  266.         }
  267.     }
  268.     else
  269.     {
  270.         PutStr("Takt läuft nicht!\n");
  271.         closedown();
  272.     }
  273.     D(PutStr("OP_ADD ok\n"));
  274.     
  275.     sran( (double) clock() );
  276.     if( instr >= 0 ) ProgChange( instr );
  277.  
  278.     // GUI starten (goodie - egal ob ok)
  279.     if( mitFenster )
  280.     {
  281.         D(PutStr("startwindow...\n"));
  282.         startwindow();
  283.     }
  284. }
  285.  
  286.  
  287. void closedown( void )
  288. {
  289.     struct MsgPort *p;
  290.     void AllNotesOff( void );
  291.  
  292.     D(PutStr("closedown\n"));
  293.     closewindow();
  294.     
  295.     AllNotesOff();
  296.     if(outroute) DeleteMRoute(outroute);
  297.     if(src) DeleteMSource(src);
  298.     if(MidiBase) CloseLibrary(MidiBase);
  299.     
  300.     taktmsg.tm_op   = OP_REM;
  301.     taktmsg.tm_task = SysBase->ThisTask;
  302.     
  303.     Forbid();
  304.      if( p = FindPort("TAKT") )
  305.       PutMsg( p, &taktmsg );
  306.     Permit();
  307.     
  308.     if( p )
  309.     {
  310.         WaitPort( taktport );
  311.         GetMsg( taktport );
  312.     }
  313.     
  314.     FreeSignal( taktsig );
  315.     DeleteMsgPort( taktport );
  316.     
  317.     // die (evtl. geänderten) Parameter ausgeben
  318.     dump_param();
  319.     
  320.     exit(0);
  321. }
  322.  
  323.  
  324. void NoteOn( int note, int vel )    // Ton einschalten
  325. {
  326.     UBYTE msg[3];
  327.  
  328.     msg[0] = MS_NOTEON | channel;
  329.     msg[1] = note;
  330.     msg[2] = vel;
  331.     PutMidiMsg(src, msg);
  332. }
  333.  
  334. void NoteOff( int note )            // Ton ausschalten */
  335. {
  336.     UBYTE msg[3];
  337.  
  338.     msg[0] = MS_NOTEOFF | channel;
  339.     msg[1] = note;
  340.     msg[2] = 64;
  341.     PutMidiMsg(src, msg);
  342. }
  343.  
  344. void AllNotesOff( void )            // Alle Töne ausschalten
  345. {
  346.     UBYTE msg[3];
  347.  
  348.     msg[0] = MS_MODE | channel;
  349.     msg[1] = MM_ALLOFF;
  350.     msg[2] = 0;
  351.     PutMidiMsg(src, msg);
  352. }
  353.  
  354. void ProgChange( int nr )            // Sound wechseln
  355. {
  356.     UBYTE msg[3];
  357.  
  358.     msg[0] = MS_PROG | channel;
  359.     msg[1] = nr;
  360.     msg[2] = 0;
  361.     PutMidiMsg(src, msg);
  362. }
  363.  
  364.  
  365. void nextton( void )
  366. {
  367.     static int last_note = 0;
  368.     int vel;
  369.     char *akt_skala;
  370.     double r, ran();
  371.     // ran() ist aus unerfindlichen Gründen hier negativ
  372.     
  373.     // ...wenn hier kein Kommentar steht... oder manchmal... oder...
  374.     
  375.     // ach scheiss drauf
  376.     r = fabs(ran());
  377.     D(printf("%lf\n",r));
  378.     
  379.     if( r > pausen )
  380.     {
  381.         // neue Note...
  382.         D(PutStr("nextnote\n"));
  383.         NoteOff( last_note );
  384.         
  385.         // Nächste erlaubte Note suchen (Skala)
  386.         if( *(akt_skala = cskala[ last_note % 12 ]) == 0 )
  387.             akt_skala = skala;
  388.         
  389.         last_note = freqmitte + 2 * freqabw * (0.50 - fabs(ran()));
  390.         while( akt_skala[ last_note % 12 ] == '0' ) ++last_note;
  391.         
  392.         // Lautstärkegewichtung entsprechend Skala
  393.         vel = volmitte + 2 * volabw * (0.50 - fabs(ran()));
  394.         vel *= ( akt_skala[ last_note % 12 ] - '0' ) / 9.0;
  395.         
  396.         // Einblendung:
  397.         if( volblend < 1.0 )
  398.         {
  399.             vel *= volblend;
  400.             volblend += 0.1;
  401.         }
  402.         
  403.         D(printf("key=%d, vel=%d\n",last_note,vel));
  404.         NoteOn( last_note, vel );
  405.     }
  406.     else
  407.     {
  408.         // Pause: Ton evtl. ausschalten?
  409.         D(PutStr("pause\n"));
  410.         
  411.         if( fabs(ran()) < tonaus )
  412.         {
  413.             NoteOff( last_note );
  414.         }
  415.     }
  416. }
  417.