home *** CD-ROM | disk | FTP | other *** search
- /* AlgoRhythms.c
- ** Thomas E. Janzen 4 September 1989; 2-11-90
- ** 18 September 1989 26 nov 89 11 December 1989 16 December 1989
- ** Music played with this program is
- ** Copyright © 1990,1991,1992,1993,1993 Thomas E. Janzen
- ** The music is randomized but changes slowly by sinusoidal functions
- ** Copyright (c) © 1990, 1991, 1992, 1993 by Thomas E. Janzen
- ** All Rights Reserved
- **
- ** THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
- ** BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
- ** CHANGES FOR FREE DISTRIBUTION. NO TITLE TO AND OWNERSHIP OF THE
- ** SOFTWARE IS HEREBY TRANSFERRED. THOMAS E. JANZEN ASSUMES NO
- ** RESPONSIBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
- **
- ** Thomas E. Janzen
- ** 208A Olde Derby Road
- ** Norwood, MA 02062-1761
- ** (617)769-7733
- ** tej@world.std.com
- **
- ** FACILITY:
- **
- ** AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
- ** compiled with SAS/C Amiga Compiler 6.50
- **
- ** ABSTRACT:
- **
- ** AlgoRhythms.c improvises music over MIDI on a COMMODORE Amiga.
- **
- ** AUTHORS: Thomas E. Janzen
- **
- ** CREATION DATE: 26-MAR-1990
- **
- ** MODIFICATION HISTORY:
- ** DATE NAME DESCRIPTION
- 1.01 12 Aug 90 T Janzen Shortened duration string to fit in new gadgets
- 1.02 8 Jan 91 Misc. improvements of code; added Events.nv_r_stop_time
- 1.03 11 feb 91 misc. and fixed bug of cut off notes on short scales
- 1.04 23 Feb 91 put back autorequesters using new compile command no crash
- 1.05 24 Jul 91 created a custom screen; added quartal and quintal scales;
- 1.06 24 SEP 91 use algorhythms.col to define colors, update.
- 1.07 3 NOV 91 Use struct timeval for all times until it must be double
- 1.08 10 NOV 91 TEJ integers in CHARACTER struct.290 notes/sec @ 16V,64 @ 1
- 2.0 26 DEC 91 TEJ Record MIDI and save MIDI standard file
- Use req.library by Colin Fox and Bruce Dawson
- Use 20 voices.
- 2.1 12 JAN 92 Integers for MaxNoteLen and MinNoteLen
- 2.2 17 JUL 92 Use AmigaDOS (TM) 2.04 ASL library if available.
- 5 SEP 92 Fix texture thickness calc to be 0 to 1 * range
- 15 SEP 92 turn off notes in all voices before turning on voices
- Fix stuck notes in MUSICSERIAL
- 2.3 19 SEP 92 Reformat code
- 2.4 31 OCT 92 conform to SAS/C 6.0
- 2.5 23 FEB 93 interlace option/ 24 FEB 93 add workbench arguments
- 2.6 03 APR 93 Integrate internal audio and 8SVX instruments
- 2.7 14 OCT 93 used gadtools
- 2.8 22 OCT 93 added forms.c, voices.c with gadtools. Removed gadgets.c
- removed redundant menus.
- 3.0 1 JAN 94 added colors events. General 3.0 Version additions.
- 26 NOV 94 fixed file drawer bug; released as Version 3.0
- 5 Dec 94 fix form path bug
- 3.1 10 December 94. Made it run even if serial device fails.
- Improved serial device error reporting.
- **
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
- #include <string.h>
- #include <limits.h>
- #include <intuition/intuition.h>
- #include <exec/memory.h>
- #include <exec/interrupts.h>
- #include <exec/devices.h>
- #include <devices/serial.h>
- #include <devices/timer.h>
- #include <proto/all.h>
- #include <Workbench/startup.h>
- #include <Libraries/asl.h> /* asl */
- #include <proto/asl.h> /* asl */
- #include <utility/tagitem.h>
-
- #include <proto/req.h>
- #include "AlgoRhythms.h"
- #include "MusicTimer.h"
- #include "MusicSerial.h"
- #include "Files.h"
- #include "Scales.h"
- #include "audio.h"
- #ifndef CLI
- #include "Window.h"
- #include "DrawForm.h"
- #include "Menus.h"
- #include "Record.h"
- #include "Forms.h"
- #include "Voices.h"
- #include "musicrexx.h"
- #include "colors.h"
- #endif
-
- #define TWOPI (2 * PI)
- #define PROJECT (0)
- #define FORM (1)
- #define SCALE (2)
- #define CHANNEL (3)
-
- /*
- ** This type of structure holds the instantaneous values for the range and
- ** median pitch, dynamic, duration, and thickness.
- */
- typedef struct character_struct CHARACTER_TYPE;
- struct character_struct
- {
- int ch_i_pitch_range, /* range of pitches */
- ch_i_pitch_mean, /* ~ median pitch */
- ch_i_dynamic_range, /* range of dynamic levels */
- ch_i_dynamic_mean, /* ~ median of dynamic levels */
- ch_i_dur_range, /* range of durations */
- ch_i_dur_mean, /* ~ median of durations */
- ch_i_thickness; /* number of voices playing at once */
- };
-
- /*
- ** Inter-modular Globals: gi_fubar, scale, and gi_quit
- ** If the serial channel fails, gi_fubar is set and the program exits.
- */
- int gi_fubar = FALSE,
- gi_quit = FALSE; /* Was told to quit out of the program */
- static int playing = FALSE, /* playing music */
- started = FALSE, /* Has started playing music */
- done = FALSE, /* done playing because it timed out*/
- delay_ticks = 8, /* fiftieths of a second to wait */
- range = 10, /* length of scale array */
- half_range = 5, /* half of range (scale array len) */
- num_voices = 4, /* */
- scale[120] = {48,50,53,55,58,60,62,65,67,70,72,74,77};
- static struct timeval range_time = {0, 0};
-
- static double cvt_time_secs(struct timeval *Time);
- static void stop_note( NOTE_EVENT_TYPE *new_event,
- struct timeval *music_time);
- static void ranges( const FORM_TYPE *form, const struct timeval *cur_time,
- CHARACTER_TYPE *next_now, NOTE_LEN_TYPE *note_len);
- static void make_event( NOTE_EVENT_TYPE *new_event, CHARACTER_TYPE *style,
- struct timeval *music_time, const int event_index,
- NOTE_LEN_TYPE *note_len);
- static NOTE_EVENT_TYPE reset_event
- = {{0, 0}, {0, 0}, {0, 0}, 0, 0, -1, 0, 0, 0, 0, 0};
- const struct timeval zero_time = {0, 0};
- static struct timeval stop_time; /* The Time that the music stopped */
-
- #ifndef CLI
- static void parse_menu( const int class, const int code,
- struct timeval *str_time, FORM_TYPE *form,
- struct timeval *duration, int *tempo,
- NOTE_EVENT_TYPE *events, NOTE_LEN_TYPE *note_len);
- #endif
- int main(int argc, char *argv[]) /* CLI version */
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** AlgoRhythms main routine including Intuition maintenance loop
- **
- ** ARGUMENTS: (only for CLI version)
- **
- ** argc-
- ** description: count of arguments; only 2 allowed
- ** data_type: int
- ** access: read only
- **
- ** argv-
- ** description: name of form file for CLI version only
- ** data_type: pointer to pointers to char
- ** access: read only
- **
- ** DESIGN:
- ** ROUTINE main
- ** : open_wind()
- ** : open_midi_port()
- ** : IF midi port cannot be opened
- ** : : GOTO cleanup2
- ** : ENDIF
- ** : init_menu()
- ** : init temp, range, scale, and half_range.
- ** : get process pointer for ASL library
- ** : get process window pointer for ASL library
- ** : init voices
- ** : #if CLI
- ** : IF argument count was wrong
- ** : : put usage message
- ** : : GOTO cleanup2
- ** : ENDIF
- ** : copy argv[1] to file_string
- ** : read the specified form file
- ** : #else
- ** : randomize pitch, rhythm, dynamic, texture
- ** : IF workbench passed arguments
- ** : : IF arguments >= 1
- ** : : : get argument
- ** : : : IF argument is locked
- ** : : : : save current directory
- ** : : : : read form file from workbench argument
- ** : : : : restore directory
- ** : : : ENDIF
- ** : : ELSE
- ** : : : just read the form file from an unlocked workbench argument
- ** : : ENDIF
- ** : : set the window title from the workbench argument
- ** : ENDIF
- ** : #endif
- ** : IF file read in OK
- ** : : IF tempo = 0
- ** : : : init delay_ticks to 0
- ** : : ELSE
- ** : : : delay_ticks = 50/ tempo
- ** : : ENDIF
- ** : : half_range = range / 2
- ** : ENDIF
- ** : #endif
- ** : start_time()
- ** : put system time into sys_time
- ** : set pseudo-random number generator with time microseconds
- ** : start_time = sys_time
- ** : clear music_time
- ** : #ifndef CLI
- ** : draw_form()
- ** : #endif
- ** : cur_style = ranges
- ** : #if CLI
- ** : init started = TRUE, done = FALSE send_function(STARTFUNCT)
- ** : #endif
- ** : WHILE (not quitting)
- ** : : music_time = current time - start_time
- ** : : WHILE (playing = (!done AND started) AND !gi_quit)
- ** : : : music_time = current_time - start_time
- ** : : : IF it is time to update the instantaneous parameter ranges
- ** : : : : ranges(form, music_time, cur_style)
- ** : : : : range_time = music_time + 1/10 second
- ** : : : ENDIF
- ** : : : FOR event_index = 0 to num_voices
- ** : : : : IF music_time > the voice's stop_time
- ** : : : : : stop the note for that voice
- ** : : : : ENDIF
- ** : : : ENDFOR
- ** : : : FOR event_index = 0 to num_voices
- ** : : : : IF events[event_index] is not playing
- ** : : : : : make_event(events[event_index], cur_style, music_time)
- ** : : : : ENDIF
- ** : : : ENDFOR
- ** : : : #if not CLI
- ** : : : draw_time() (move time cursor on screen)
- ** : : : WHILE (message = GetMsg(w->UserPort) service Intuition windowing
- ** : : : : class = message->Class; code = message->Code
- ** : : : : ReplyMsg()
- ** : : : : IF class = MENUPICK AND code = MENUNULL
- ** : : : : : go to top of WHILE
- ** : : : : ENDIF
- ** : : : : parse_menu(class, code, start_time, form, piece_duration,
- ** tempo, events)
- ** : : : ENDWHILE
- ** : : : IF delay_ticks != 0
- ** : : : : FOR tick = 0 to delays_ticks BY 2
- ** : : : : : send MIDI clock byte
- ** : : : : : Delay about 1/25 sec
- ** : : : : ENDFOR
- ** : : : ENDIF
- ** : : : IF done = (music_time > piece_duration)
- ** : : : : #if CLI
- ** : : : : gi_quit = done
- ** : : : : #endif
- ** : : : : stop_all_notes()
- ** : : : : started = FALSE
- ** : : : ENDIF
- ** : : ENDWHILE
- ** : : #if not CLI
- ** : : set up Intuition signals
- ** : : wait for Intuition windowing signal
- ** : : interpret Intuition signal
- ** : : #endif
- ** : : continue
- ** : cleanup1:
- ** : #if not CLI
- ** : close_menu()
- ** : #endif
- ** : stop_all_notes()
- ** : Delay a little
- ** : remove_timer()
- ** : cleanup2:
- ** : #if not CLI
- ** : shut_window()
- ** : erase_recording()
- ** : #endif
- ** : stop_midi()
- ** : exit
- ** ENDROUTINE
- */
- {
- static FORM_TYPE form = {{180.0, -PID2, 200.0, -PID2},
- {200.0, PID2, 180.0, PID2},
- {170.0, -PID2, 165, -PID2},
- {0.0, 0.0, 190.0, -PID2}};
- auto char file_string[128];
- auto int sts,
- vox_index;
- #ifndef CLI
- static int code,
- class, /* mouse codes esp. for menus */
- main_mask,
- signal;
- auto struct IntuiMessage *message;
- static struct Process *process;
- static APTR old_error_window;
- auto struct WBStartup *wb_msg;
- auto struct WBArg *wb_arg;
- auto BPTR olddir;
- #endif
- static int event_index = 0; /* Index into Events */
- register int tick = 0; /* Index for counting 1/25's of a second*/
- auto int tempo, /* ticks per second */
- voice_index; /* index */
- auto struct timeval tenth_second = {0, 1000000};
- auto struct timeval music_time,
- start_time, /* the current time in seconds */
- piece_duration = {600, 0}, /* piece length */
- sys_time;
- static CHARACTER_TYPE cur_style;
- static NOTE_LEN_TYPE note_len = {100, 2000, 2000};
- static NOTE_EVENT_TYPE events[MAXVOICE]; /* currently playing notes */
-
- #ifndef CLI
- open_wind(); /* Open the window for AlgoRhythms */
- #endif
-
- open_midi_port(); /* Open the serial port for MIDI use */
-
- if (gi_fubar)
- {
- /*
- ** Get out if serial port failed to open
- */
- goto cleanup2; /* skip out on failure */
- }
- #ifndef CLI
- init_menu(); /* Set up the menu */
- tempo = 50 / delay_ticks; /* Tempo is pulses per second */
- range = install_scale(1, scale); /* Install a musical scale */
- half_range = range / 2; /* recalculate half_range */
- process = (struct Process *)FindTask(NULL);
- old_error_window = process->pr_WindowPtr;
- process->pr_WindowPtr = (APTR)w;
-
- open_orch_window();
- open_forms_window();
- open_voices_window();
- open_colors_window();
- init_rexx();
- #endif
- for (voice_index = 0; voice_index < MAXVOICE; voice_index++)
- {
- events[voice_index].nv_i_id = voice_index;
- events[voice_index].nv_i_scale_index = half_range;
- events[voice_index].nv_i_dynamic = 0.0;
- events[voice_index].nv_r_start_time.tv_micro
- = events[voice_index].nv_r_start_time.tv_secs
- = events[voice_index].nv_r_stop_time.tv_micro
- = events[voice_index].nv_r_stop_time.tv_secs
- = events[voice_index].nv_r_duration.tv_micro
- = events[voice_index].nv_r_duration.tv_secs
- = events[voice_index].nv_i_channel
- = 0;
- events[voice_index].nv_i_cur_pitch = 60;
- events[voice_index].nv_i_low_pitch = 24;
- events[voice_index].nv_i_high_pitch = 108;
- events[voice_index].nv_i_walking
- = events[voice_index].nv_i_audio
- = events[voice_index].nv_i_was_audio
- = FALSE;
- events[voice_index].nv_i_playing = FALSE;
- events[voice_index].nv_i_audio_chan = C_NO_CHAN;
- }
- for (voice_index = 0; voice_index < 4; voice_index++)
- {
- events[voice_index].nv_i_walking
- = events[voice_index].nv_i_audio
- = events[voice_index].nv_i_was_audio
- = TRUE;
- }
- init_audio();
- /*
- ** set the form of the piece
- */
- #ifdef CLI
- if (argc != 2)
- {
- puts("usage: AlgoRhythmsCLI {Form_file}\n");
- goto cleanup2;
- }
- strcpy(file_string, argv[1]);
- sts = read_file(file_string, &piece_duration, &range, scale,
- &num_voices, &tempo, &form, events,
- ¬e_len);
- #else
-
- if (0 == argc) /* if workbench passed an argument */
- {
- wb_msg = (struct WBStartup *)argv;
- if (wb_msg->sm_NumArgs >= 2)
- {
- wb_arg = wb_msg->sm_ArgList;
- wb_arg++;
- if (wb_arg->wa_Lock != NULL)
- {
- olddir = CurrentDir(wb_arg->wa_Lock);
- strcpy(file_string, wb_arg->wa_Name);
- sts = read_file(file_string, &piece_duration, &range,
- scale, &num_voices, &tempo, &form, events,
- ¬e_len);
- CurrentDir(olddir);
- }
- else
- {
- strcpy(file_string, wb_arg->wa_Name);
- sts = read_file(file_string, &piece_duration, &range,
- scale, &num_voices, &tempo, &form, events,
- ¬e_len);
- }
- SetWindowTitles(w, file_string, (void *) -1L);
-
- }
- }
- #endif
- if (!sts)
- {
- if (0 == tempo)
- {
- delay_ticks = 0;
- }
- else
- {
- delay_ticks = 50 / tempo;
- }
- half_range = range / 2;
- }
- start_timer(); /* Start timer device */
- GetSysTime(&sys_time); /* Get the time */
- srand(sys_time.tv_micro); /* use microseconds time to seed random */
- /*
- ** Save Time the program started
- */
- start_time = sys_time;
- music_time.tv_micro = music_time.tv_secs = 0; /*Clear time to start*/
-
- #ifndef CLI
- /*
- ** Initialize the Form parameters as random
- */
- randomize_parameter(&form.frm_s_pitch);
- randomize_parameter(&form.frm_s_rhythm);
- randomize_parameter(&form.frm_s_dynamic);
- randomize_parameter(&form.frm_s_texture);
- draw_form(&piece_duration, &form);
- set_form_gadgets(&form, &piece_duration, &tempo, events, ¬e_len,
- num_voices);
- set_voice_gadgets(events);
- #endif
- /*
- ** Initialize the ranges(pitch, dynamic, duration)
- */
- ranges(&form, &music_time, &cur_style, ¬e_len);
- #ifdef CLI
- started = TRUE;
- done = FALSE;
- send_function(STARTFUNCT);
- #endif
- /*
- ** Master Control Loop
- ** Program stays in here until it gi_quits
- */
- while ( !(gi_quit)) /* until we quit */
- {
- GetSysTime(&sys_time);
- music_time = sys_time;
- SubTime(&music_time, &start_time); /*music_time=cur_style - Start*/
- /*
- ** as long as you are playing
- */
- while (playing = ( !done && started) && !gi_quit)
- {
- /*
- ** get the time and convert
- ** to double normalize to
- ** the starting time of the
- ** piece of music
- */
- GetSysTime(&sys_time);
- music_time = sys_time;
- SubTime(&music_time, &start_time);
- /*
- ** Get the instantaneous mean & range of
- ** pitch, dynamics, duration, and texture
- */
- if (-1 == CmpTime(&music_time, &range_time))
- {
- ranges(&form, &music_time, &cur_style, ¬e_len);
- range_time = music_time;
- AddTime(&range_time, &tenth_second);
- }
- /*
- ** scan the voices
- */
- for (event_index = 0; event_index < MAXVOICE; event_index++)
- {
- /* if the note event is complete */
- if (-1 == CmpTime(&music_time,
- &events[event_index].nv_r_stop_time))
- {
- stop_note(&events[event_index], &music_time);
- }
- }
- for (event_index = 0; event_index < num_voices; event_index++)
- {
- if (!(events[event_index].nv_i_playing))
- {
- make_event(&events[event_index], &cur_style,
- &music_time, event_index, ¬e_len);
- }
- }
- /*
- ** Indicate the time on the form graph
- */
- #ifndef CLI
- draw_time(&music_time, &piece_duration);
- /* If there is an action, then find out what */
- while (message = (struct IntuiMessage *) GetMsg(w->UserPort))
- {
- class = message->Class;
- code = message->Code;
- ReplyMsg((struct Message *)message);
- if ((MENUPICK == class) && (MENUNULL == code))
- {
- continue;
- }
- parse_menu(class, code, &start_time, &form,
- &piece_duration, &tempo, events, ¬e_len);
- }
- if (process_form_events(&form, &piece_duration,
- &tempo, events, ¬e_len, &num_voices, scale, &range,
- &half_range, &delay_ticks))
- {
- set_form_gadgets(&form, &piece_duration, &tempo, events,
- ¬e_len, num_voices);
- }
- process_color_events();
- if (process_voice_events(events))
- {
- set_voice_gadgets(events);
- }
- process_audio_events();
- switch (process_rexx(&form, &piece_duration, &tempo,
- events, ¬e_len, &num_voices, scale, &range,
- &half_range, &delay_ticks))
- {
- case C_REXX_CHANG_VOICE:
- set_voice_gadgets(events);
- break;
- case C_REXX_CHANG_FORM:
- set_form_gadgets(&form, &piece_duration, &tempo,
- events, ¬e_len, num_voices);
- break;
- case C_REXX_CHANG_BOTH:
- set_voice_gadgets(events);
- set_form_gadgets(&form, &piece_duration, &tempo,
- events, ¬e_len, num_voices);
- break;
- case C_REXX_PLAY:
- started = TRUE;
- done = FALSE;
- GetSysTime(&start_time);
- play_note_on(&reset_event);
- for (vox_index = 0; vox_index < MAXVOICE; vox_index++)
- {
- events[vox_index].nv_r_start_time
- = events[vox_index].nv_r_duration
- = events[vox_index].nv_r_stop_time
- = zero_time;
- }
- send_function(STARTFUNCT);
- range_time = zero_time;
- break;
- case C_REXX_STOP:
- started = FALSE;
- for (vox_index = 0;
- vox_index < MAXVOICE; vox_index++)
- {
- events[vox_index].nv_r_start_time
- = events[vox_index].nv_r_duration
- = events[vox_index].nv_r_stop_time
- = zero_time;
- }
- stop_all_notes(events);
- GetSysTime(&stop_time);
- break;
- case C_REXX_CONTINUE:
- started = TRUE;
- play_note_on(&reset_event);
- GetSysTime(&sys_time);
- start_time.tv_secs
- += (sys_time.tv_secs - stop_time.tv_secs);
- break;
- }
- #endif
- /*
- ** If delay_ticks is not zero then pause to
- ** simulate a regular beat
- */
- if (delay_ticks != 0)
- {
- for (tick = 0; tick < delay_ticks; tick += 2)
- {
- send_function(CLOCKFUNCT); /* Send MIDI timing clock */
- Delay(1); /* wait 1/50's of a sec*/
- }
- }
- /*
- ** if the piece is done,
- */
- if (done = (-1 == CmpTime(&music_time, &piece_duration)))
- {
- #ifdef CLI
- gi_quit = done;
- #endif
- stop_all_notes(events);
- started = FALSE;
- }
- }
- /*
- ** if the piece is playing, then wait, free up AmigaDOS,
- ** until a mouse event hits this window
- */
- #ifndef CLI
- main_mask = 1L << w->UserPort->mp_SigBit;
- signal
- = Wait(main_mask | forms_mask | orch_mask
- | voices_mask | rexx_mask | colors_mask);
- /*
- ** When the event hits, find out what
- */
- if (signal & main_mask)
- {
- while (message = (struct IntuiMessage *) GetMsg(w->UserPort))
- {
- class = message->Class;
- code = message->Code;
- ReplyMsg((struct Message *)message);
- if ((MENUPICK == class) && (MENUNULL == code))
- {
- continue;
- }
- parse_menu(class, code, &start_time, &form, &piece_duration,
- &tempo, events, ¬e_len);
- }
- }
- if (signal & forms_mask)
- {
- if (process_form_events(&form, &piece_duration,
- &tempo, events, ¬e_len, &num_voices, scale, &range,
- &half_range, &delay_ticks))
- {
- set_form_gadgets(&form, &piece_duration, &tempo, events,
- ¬e_len, num_voices);
- }
- }
- if (signal & voices_mask)
- {
- if (process_voice_events(events))
- {
- set_voice_gadgets(events);
- }
- }
- if (signal & orch_mask)
- {
- process_audio_events();
- }
- if (signal & colors_mask)
- {
- process_color_events();
- }
- if (signal & rexx_mask)
- {
- switch (process_rexx(&form, &piece_duration, &tempo,
- events, ¬e_len, &num_voices, scale, &range,
- &half_range, &delay_ticks))
- {
- case C_REXX_CHANG_VOICE:
- set_voice_gadgets(events);
- break;
- case C_REXX_CHANG_FORM:
- set_form_gadgets(&form, &piece_duration, &tempo,
- events, ¬e_len, num_voices);
- break;
- case C_REXX_CHANG_BOTH:
- set_voice_gadgets(events);
- set_form_gadgets(&form, &piece_duration, &tempo,
- events, ¬e_len, num_voices);
- break;
- case C_REXX_PLAY:
- started = TRUE;
- done = FALSE;
- GetSysTime(&start_time);
- play_note_on(&reset_event);
- for (vox_index = 0; vox_index < MAXVOICE; vox_index++)
- {
- events[vox_index].nv_r_start_time
- = events[vox_index].nv_r_duration
- = events[vox_index].nv_r_stop_time
- = zero_time;
- }
- send_function(STARTFUNCT);
- range_time = zero_time;
- break;
- case C_REXX_STOP:
- started = FALSE;
- for (vox_index = 0;
- vox_index < MAXVOICE; vox_index++)
- {
- events[vox_index].nv_r_start_time
- = events[vox_index].nv_r_duration
- = events[vox_index].nv_r_stop_time
- = zero_time;
- }
- stop_all_notes(events);
- GetSysTime(&stop_time);
- break;
- case C_REXX_CONTINUE:
- started = TRUE;
- play_note_on(&reset_event);
- GetSysTime(&sys_time);
- start_time.tv_secs
- += (sys_time.tv_secs - stop_time.tv_secs);
- break;
- }
- }
- #endif
- continue; /* continue in Master Control Loop until gi_quit */
- }
- cleanup1: /* normal dump out of the program */
- #ifndef CLI
- process->pr_WindowPtr = old_error_window;
-
- close_colors();
- close_voices();
- close_forms();
- close_orch();
- shut_rexx();
- #endif
- stop_all_notes(events); /* turn off all the notes */
- de_init_audio();
- Delay(10); /* wait 1/5 seconds */
- remove_timer(); /* release the timer device */
- cleanup2: /* exit here if the serial port wouldn't open*/
- #ifndef CLI
- close_menu(); /* shut down menu */
- shut_window(); /* remove the window */
- erase_recording();
- #endif
- stop_midi(); /* close the serial device */
-
- exit(EXIT_SUCCESS); /* exit program */
- }
-
- static void ranges( const FORM_TYPE *form,
- const struct timeval *cur_time,
- CHARACTER_TYPE *next_now, NOTE_LEN_TYPE *note_len)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Calculates the current ranges for pitch, dynamic, duration, and the
- ** number of voices playing.
- **
- ** ARGUMENTS:
- **
- ** form-
- ** description: period and phase of mean and range
- ** for pitch,dyn,text,rhythm
- ** data_type: pointer to FORM_TYPE
- ** access: read only
- **
- ** cur_time-
- ** description: period and phase of mean and range
- ** data_type: pointer to timeval
- ** access: read only
- **
- ** next_now-
- ** description: period and phase of mean and range
- ** data_type: pointer to CHARACTER_TYPE
- ** access: write only
- **
- ** DESIGN:
- ** ROUTINE ranges
- ** : phase = TWOPI * (CurrentTime->tv_secs
- ** + (CurrentTime->tv_micro * 1E-6))
- ** : next_now->ch_i_pitch_range = (sin(phase / pitch->prm_d_range_cycle
- ** + pitch->prm_d_range_phase) + 1) * realhalf_range
- ** : next_now->ch_i_pitch_mean = (sin(phase / pitch->prm_d_mean_cycle
- ** + pitch->prm_d_mean_phase) + 1.0) * realhalf_range
- ** : IF pitch_mean and range could create negative note numbers
- ** : : center up range smaller
- ** : ENDIF
- ** : ELSE
- ** : : IF pitch_mean and range could create scale notes beyond the scale
- ** : : : center up range smaller
- ** : : ENDIF
- ** : ENDIF
- ** : next_now->ch_i_dynamic_range= (sin(phase / dynamic->prm_d_range_cycle
- ** + dynamic->prm_d_range_phase) + 1.01) * 63.0
- ** : next_now->ch_i_dynamic_mean = (sin(phase / dynamic->prm_d_mean_cycle
- ** + dynamic->prm_d_mean_phase) + 1.01) * 50.0 + 25.0
- ** : next_now->ch_i_dur_range = (sin(phase / duration->prm_d_range_cycle
- ** + duration->prm_d_range_phase) + 1.01) / 2.0 * dif_note_len_ms
- ** : next_now->ch_i_dur_mean = (sin(phase / duration->prm_d_mean_cycle
- ** + duration->prm_d_mean_phase) + 1.01) / 2.0 * dif_note_len_ms
- ** + min_note_len_ms
- ** : next_now->ch_i_thickness = (sin(phase / thickness->prm_d_range_cycle
- ** + thickness->prm_d_range_phase) + 1) / 2
- ** * (num_voices - 1)
- ** ENDROUTINE
- */
- {
- auto double realrange, /* floating-point version of range */
- realhalf_range, /* floating-point version of half_range */
- phase;
-
- realrange = (double) range;
- realhalf_range = (double) half_range;
-
- phase = TWOPI * ((double)(cur_time->tv_secs) +
- ((double)(cur_time->tv_micro) * 1E-6));
- next_now->ch_i_pitch_range
- = (int)floor(((sin((phase / form->frm_s_pitch.prm_d_range_cycle)
- + form->frm_s_pitch.prm_d_range_phase) + 1.0) * realhalf_range));
- /* pitch range is a sin function of time*/
- next_now->ch_i_pitch_mean
- = (int)floor(((sin((phase / form->frm_s_pitch.prm_d_mean_cycle)
- + form->frm_s_pitch.prm_d_mean_phase) + 1.0) * realhalf_range));
- /*
- ** The following bounds checking prevents pitch range from
- ** overlapping into non-usable notes (less than 0 and higher
- ** than the top scale note). It forces the range to be
- ** from top or bottom of the scale through the mean and
- ** an equal distance to the other side
- */
- if ((next_now->ch_i_pitch_mean - (next_now->ch_i_pitch_range / 2)) < 0)
- {
- next_now->ch_i_pitch_mean = 1 + ((next_now->ch_i_pitch_mean
- + (next_now->ch_i_pitch_range / 2)) / 2);
- }
- else
- {
- if ((next_now->ch_i_pitch_mean + (next_now->ch_i_pitch_range / 2))
- > (double)range)
- {
- next_now->ch_i_pitch_mean = realhalf_range - 1
- + ((next_now->ch_i_pitch_mean
- - (next_now->ch_i_pitch_range / 2)) / 2);
- }
- }
- next_now->ch_i_dynamic_range
- = (int)floor(((
- sin((phase / (form->frm_s_dynamic.prm_d_range_cycle))
- + form->frm_s_dynamic.prm_d_range_phase) + 1.01) * 63.0));
- /* Range of dynamics is a sin function of time */
- next_now->ch_i_dynamic_mean
- = (int)floor(((sin(phase / form->frm_s_dynamic.prm_d_mean_cycle
- + form->frm_s_dynamic.prm_d_mean_phase) + 1.01) * 50.0 + 25.0));
- /* Median dynamic is a sin function of time */
- next_now->ch_i_dur_range
- = (int)floor((((sin(phase / form->frm_s_rhythm.prm_d_range_cycle
- + form->frm_s_rhythm.prm_d_range_phase) + 1.01) / 2.0)
- * (double)note_len->len_i_dif));
- /*
- ** Range of durations is a sin function of time
- */
- next_now->ch_i_dur_mean
- = (int)floor(((sin(phase / form->frm_s_rhythm.prm_d_mean_cycle
- + form->frm_s_rhythm.prm_d_mean_phase) + 1.01) / 2.0
- * (double)note_len->len_i_dif)) + note_len->len_i_min;
- /* Median duration is a sin function of time */
- next_now->ch_i_thickness
- = (int)floor((((sin((phase / form->frm_s_texture.prm_d_range_cycle)
- + form->frm_s_texture.prm_d_range_phase) + 1.0) / 2.0
- * (double)(num_voices - 1))) + 0.5);
- /* the number of voices playing is a sin function of time */
- return;
- }
-
- void randomize_parameter(PARAMETER_TYPE *param)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Calculate random values for period/phase of mean/range for parameter
- **
- ** RETURN VALUE:
- ** description: randomized period/phase of mean/range
- ** data_type: PARAMETER_TYPE
- **
- ** DESIGN:
- ** ROUTINE randomize_parameter()
- ** : param->prm_d_mean_cycle = rand() / realrand_max * 120 + 90
- ** : param->prm_d_mean_phase = rand() / realrand_max * TWOPI
- ** : param->prm_d_range_cycle = rand() / realrand_max * 120 + 90
- ** : param->prm_d_range_phase = rand() / realrand_max * TWOPI
- ** ENDROUTINE
- */
- {
- /*
- ** Returns a randomized parameter of any type
- ** Periods are 1.5 to 3.5 minutes
- */
- register double realrand_max;
-
- realrand_max = (double)RAND_MAX;
- param->prm_d_mean_cycle
- = ((double)rand() / realrand_max) * 120.0 + 90.0;
- param->prm_d_mean_phase
- = ((double)rand() / realrand_max) * TWOPI - PI;
- param->prm_d_range_cycle
- = ((double)rand() / realrand_max) * 120.0 + 90.0;
- param->prm_d_range_phase
- = ((double)rand() / realrand_max) * TWOPI - PI;
- return;
- }
-
- static void make_event(NOTE_EVENT_TYPE *new_event, CHARACTER_TYPE *style,
- struct timeval *music_time, const int event_index,
- NOTE_LEN_TYPE *note_len)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Calculate and play a note
- **
- ** ARGUMENTS:
- **
- ** new_event-
- ** description: One voice's event structure
- ** data_type: pointer to NOTE_EVENT_TYPE
- ** access: read/write
- **
- ** style-
- ** description: current ranges of pitch/dynamic/duration/texture
- ** data_type: pointer to CHARACTER_TYPE
- ** access: read only
- **
- ** music_time-
- ** description: relative time since starting playing music
- ** data_type: pointer to timeval
- ** access: read only
- **
- ** event_index-
- ** description: number of voice
- ** data_type: int
- ** access: read only
- **
- ** DESIGN
- /*
- ** ROUTINE make_event()
- ** : IF voice is playing (won't happen any more)
- ** : : turn off the note
- ** : : #if not CLI
- ** : : IF recording
- ** : : : record note off
- ** : : ENDIF
- ** : : #endif
- ** : ENDIF
- ** : IF this voice is higher than the current number of voices playing
- ** : : return
- ** : ENDIF
- ** : IF dynamic_range > 1
- ** : : new_dynamic = (rand() % style->ch_i_dynamic_range)
- ** - (style->ch_i_dynamic_range / 2) + style->ch_i_dynamic_mean
- ** : ELSE
- ** : : new_dynamic = style->ch_i_dynamic_mean
- ** : ENDIF
- ** : check bounds on new_dynamic and fold in if necessary
- ** : new_event->nv_i_dynamic = new_dynamic
- ** : IF duration range is > 1 ms
- ** : : new_duration = (rand() % style->ch_i_dur_range
- ** - style->ch_i_dur_range / 2 + style->ch_i_dur_mean)
- ** : ELSE
- ** : : new_duration = style->ch_i_dur_mean
- ** : ENDIF
- ** : IF new_duration is shorter than min_note_len_ms
- ** : : force new_duration = min_note_len_ms
- ** : ENDIF
- ** : IF new_duration is longer than max_note_len_ms
- ** : : force new_duration = max_note_len_ms
- ** : ENDIF
- ** : convert new_duration from millisecs to sys time in new_duration_time
- ** : copy new_duration_time to new_event->nr_r_duration
- ** : new_event->nv_r_stop_time = music_time + duration
- ** : IF voice is walking
- ** : : high_note = current pitch is >= highest pitch allowed in voice
- ** : : low_note = current pitch is <= lowest pitch allowed in voice
- ** : : walk = rand() % 3 - 1
- ** : : IF low_note
- ** : : : walk = 1
- ** : : ENDIF
- ** : : IF high_note
- ** : : : walk = -1
- ** : : ENDIF
- ** : : new_pitch_index = new_event->nv_i_scale_index + walk
- ** : ELSE
- ** : : IF pitch_range > 0
- ** : : : new_pitch_index = rand() % style->ch_i_pitch_range
- ** - style->ch_i_pitch_range / 2 + style->ch_i_pitch_mean
- ** : : ELSE
- ** : : : new_pitch_index = style->ch_i_pitch_mean
- ** : : ENDIF
- ** : : high_note = pitch > highest pitch allowed in voice
- ** : : low_note = pitch < lowest pitch allowed in voice
- ** : : ok_rand_note = not high_note or low_note
- ** : ENDIF
- ** : IF pitch index >= range
- ** : : new_pitch_index = range -1 fold under if too high
- ** : ENDIF
- ** : IF new_pitch_index < 0
- ** : : new_pitch_index = 0
- ** : ENDIF
- ** : new_event->nv_i_scale_index = new_pitch_index
- ** : new_event->nv_i_scale_index = scale[new_pitch_index]
- ** : IF (playing AND ok_rand_note)
- ** : : play_note_on(new_event)
- ** : : set playing for voice
- ** : : #if not CLI
- ** : : IF recording
- ** : : : record_note_event(new_event)
- ** : : ENDIF
- ** : ENDIF
- ** ENDROUTINE
- */
- {
- auto int low_note, /* Boolean flag that the note is as the */
- /* bottom of the scale */
- high_note, /* Boolean flag = note is at top of scale*/
- ok_rand_note = TRUE, /* not low and not high */
- walk, /* a direction for the note to walk */
- new_pitch_index, /* index to the new pitch */
- new_dynamic, /* temp new dynamic value */
- new_duration; /* a temporary new duration value */
- auto struct timeval new_duration_time;
-
- if (new_event->nv_i_playing)
- {
- new_event->nv_i_dynamic = 0;
- new_event->nv_r_stop_time = *music_time;
- if (new_event->nv_i_was_audio)
- {
- play_audio_note(new_event);
- }
- else
- {
- play_note_on(new_event); /* Turn off the old note */
- }
- new_event->nv_i_playing = FALSE;
- #ifndef CLI
- if (recording)
- {
- record_note_event(new_event);
- }
- #endif
- }
- if (event_index > style->ch_i_thickness)
- {
- return;
- }
- if (style->ch_i_dynamic_range > 1)
- {
- new_dynamic = (rand() % style->ch_i_dynamic_range)
- - (style->ch_i_dynamic_range / 2)
- + style->ch_i_dynamic_mean;
- }
- else
- {
- new_dynamic = style->ch_i_dynamic_mean;
- }
- /*
- ** Check boundaries on dynamic
- */
- if (new_dynamic > 127)
- {
- new_dynamic = 127;
- }
- if (new_dynamic < 30 )
- {
- new_dynamic = 30;
- }
- new_event->nv_i_dynamic = new_dynamic; /* make dynamic a byte*/
-
- if (style->ch_i_dur_range > 1)
- {
- new_duration = (rand() % style->ch_i_dur_range
- - style->ch_i_dur_range / 2
- + style->ch_i_dur_mean);
- }
- else
- {
- new_duration = style->ch_i_dur_mean;
- }
- new_duration =
- ((new_duration < note_len->len_i_min)
- ? note_len->len_i_min : new_duration);
- new_duration =
- ((new_duration > note_len->len_i_max)
- ? note_len->len_i_max : new_duration);
- new_duration_time.tv_secs = new_duration / 1000;
- new_duration_time.tv_micro = (new_duration * 1000) % 1000000;
- /*
- ** Put duration in durations list
- */
- new_event->nv_r_duration = new_duration_time;
- new_event->nv_r_start_time = *music_time;
- new_event->nv_r_stop_time = new_duration_time;
- AddTime(&new_event->nv_r_stop_time, music_time);
-
- /*
- ** If the voice is walking
- */
- if (new_event->nv_i_walking)
- {
- high_note
- = new_event->nv_i_cur_pitch >= new_event->nv_i_high_pitch;
- low_note = new_event->nv_i_cur_pitch <= new_event->nv_i_low_pitch;
- walk = (rand() % 3) - 1;
- if (low_note)
- {
- walk = 1;
- }
- if (high_note)
- {
- walk = -1;
- }
- new_pitch_index = new_event->nv_i_scale_index + walk;
- }
- else
- {
- if (style->ch_i_pitch_range > 0)
- {
- new_pitch_index = rand() % style->ch_i_pitch_range
- - style->ch_i_pitch_range / 2
- + style->ch_i_pitch_mean;
- }
- else
- {
- new_pitch_index = style->ch_i_pitch_mean;
- }
- high_note = (scale[new_pitch_index] >= new_event->nv_i_high_pitch);
- low_note = (scale[new_pitch_index] <= new_event->nv_i_low_pitch);
- ok_rand_note = !(high_note || low_note);
- }
- if (new_pitch_index >= range)
- {
- new_pitch_index = range - 1; /* fold under if too high */
- }
- if (new_pitch_index < 0)
- {
- new_pitch_index = 0; /* fold up if too low */
- }
- new_event->nv_i_scale_index = new_pitch_index;
- new_event->nv_i_cur_pitch = scale[new_pitch_index];
- /*
- ** Play the note
- */
- if (playing && ok_rand_note)
- {
- if (new_event->nv_i_audio)
- {
- play_audio_note(new_event);
- }
- else
- {
- play_note_on(new_event);
- }
- new_event->nv_i_playing = TRUE;
- #ifndef CLI
- if (recording)
- {
- record_note_event(new_event);
- }
- #endif
- }
- return;
- }
-
- #ifndef CLI
- static void parse_menu(const int class, const int code,
- struct timeval *str_time, FORM_TYPE *form,
- struct timeval *duration, int *tempo,
- NOTE_EVENT_TYPE *events, NOTE_LEN_TYPE *note_len)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Interpret Intuition mouse/menu operations
- **
- ** ARGUMENTS:
- **
- ** class-
- ** description: Intuition event class
- ** data_type: int
- ** access: read only
- **
- ** code-
- ** description: Intuition event code
- ** data_type: int
- ** access: read only
- **
- ** str_time-
- ** description: the real clock time that the piece started playing
- ** data_type: pointer to struct timeval
- ** access: write only
- **
- ** form-
- ** description: period/phase of mean/range for pitch/dyn/rhyth/text
- ** data_type: pointer to FORM_TYPE
- ** access: read/write
- **
- ** duration-
- ** description: Length of piece
- ** data_type: pointer to struct timeval
- ** access: read/write
- **
- ** tempo-
- ** description: beats per second
- ** data_type: pointer to int
- ** access: read/write
- **
- ** events-
- ** description:
- ** data_type: pointer to NOTE_EVENT_TYPE
- ** access: read/write
- **
- ** DESIGN:
- **
- ** ROUTINE parse_menu
- ** : init file_req
- ** : CASE class
- ** : : NEWSIZE
- ** : : : draw_form()
- ** : : MENUPICK
- ** : : : IF code != MENUNULL
- ** : : : : item = ITEMNUM(code)
- ** : : : : subitem = SUBNUM(code)
- ** : : : : CASE MENUNUM(code)
- ** : : : : : PROJECT:
- ** : : : : : : IF item != NOITEM
- ** : : : : : : : CASE item
- ** : : : : : : : : 0
- ** : : : : : : : : : set gi_quit
- ** : : : : : : : : 1
- ** : : : : : : : : : response = AutoRequest thanks
- ** : : : : : : : : 2
- ** : : : : : : : : : IF AslBase != NULL
- ** : : : : : : : : : : use file requester to get MIDI file name
- ** : : : : : : : : 3
- ** : : : : : : : : : erase_recording
- ** : : : : : : : : 4
- ** : : : : : : : : : record_init
- ** : : : : : : : : : toggle recording
- ** : : : : : : : : 5
- ** : : : : : : : : : use file requester to save form file
- ** : : : : : : : : 6
- ** : : : : : : : : : use file requester to load form file
- ** : : : : : : : : 7
- ** : : : : : : : : : continue playing
- ** : : : : : : : : 8
- ** : : : : : : : : : stop playing
- ** : : : : : : : : 9
- ** : : : : : : : : : Start playing music
- ** : : : : : : : FORM
- ** : : CLOSEWINDOW
- ** : : : gi_quit = TRUE
- ** ENDROUTINE
- */
- {
- auto int asl_result,
- vox_index,
- sts, /* file status */
- item = 0, /* menu item */
- subitem = 0, /* menu subitem */
- response;
- static struct FileRequester *asl_request;
- static struct TagItem asl_tags[8] =
- {{ASL_Dir, NULL}, {ASL_File, NULL}, {ASL_Hail, NULL},
- {ASL_Window, NULL}, {ASL_LeftEdge, 10}, {ASL_TopEdge, 10},
- {ASL_Height, 180}, {TAG_DONE, NULL}};
- #ifdef MEASURE
- static unsigned char measure_string[32];
- static struct IntuiText measure_txt
- = {2, 1, JAM2, 15, 10, &font_choice, measure_string, NULL};
- #endif
- const struct timeval zero_time = {0, 0};
- static struct timeval sys_time;
- static struct ReqFileRequester file_req;
- static char midi_path[96] = "\0",
- midi_dir[96] = "\0",
- midi_file[64] = "\0",
- form_path[64] = "\0",
- form_dir[96] = "\0",
- form_file[64] = "\0",
- title_string[128] = "\0";
- /*
- ** Strings for gadgets
- */
- static char load_file_banner[] = "Load Form File",
- save_form_banner[] = "Save Form File",
- midi_form_banner[] = "Save MIDI file",
- about1_str[32] = "Welcome to AlgoRhythms 3.1",
- about2_str[40] = "Copyright 1994 Thomas E. Janzen",
- thanks_str[7] = "Thanks";
- static struct IntuiText
- about1_txt = {2, 1, JAM2, 5, 4, &font_choice, about1_str, NULL},
- about2_txt = {2, 1, JAM2, 5, 15, NULL, about2_str, &about1_txt},
- thanks_txt = {2, 1, JAM1, 5, 4, NULL, thanks_str, NULL};
-
- file_req.dirnamescolor = 2;
- file_req.devicenamescolor = 2;
-
- switch (class)
- {
- case NEWSIZE: /* Window has been re-sized, so re-draw the graph */
- draw_form(duration, form);
- break;
- case MENUPICK: /* a menu selection was made */
- if (code != MENUNULL)
- {
- item = ITEMNUM(code);
- subitem = SUBNUM(code);
- switch (MENUNUM(code))
- {
- case PROJECT: /* Project menu strip was selected */
- if (item != NOITEM)
- switch (item)
- {
- case 9: /* gi_quit program */
- gi_quit = TRUE;
- break;
- case 8: /* About copyright notice */
- response
- = AutoRequest(w, &about2_txt, &thanks_txt,
- &thanks_txt, 0L, 0L, 300L, 60L);
- break;
- case 7: /* Save MIDI file */
- asl_tags[0].ti_Data = (ULONG)midi_dir;
- asl_tags[1].ti_Data = (ULONG)midi_file;
- asl_tags[2].ti_Data
- = (ULONG)midi_form_banner;
- asl_tags[3].ti_Data = (ULONG)w;
- asl_request
- = AllocAslRequest(ASL_FileRequest,
- asl_tags);
- asl_result = AslRequest(asl_request, NULL);
- if (NULL == asl_result)
- {
- DisplayBeep(NULL);
- break;
- }
- strcpy(midi_dir, asl_request->rf_Dir);
- strcpy(midi_file, asl_request->rf_File);
- strcpy(midi_path, asl_request->rf_Dir);
- if ( (midi_path[strlen(midi_path) - 1] != ':')
- && (strlen(midi_path) != 0))
- {
- strcat(midi_path, "/");
- }
- strcat(midi_path, asl_request->rf_File);
- write_midi(midi_path);
- FreeAslRequest(asl_request);
- break;
- case 6: /* Erase */
- erase_recording();
- break;
- case 5: /* Record */
- recording = record_init();
- break;
- case 4: /* Save a form file */
- asl_tags[0].ti_Data = (ULONG)form_dir;
- asl_tags[1].ti_Data = (ULONG)form_file;
- asl_tags[2].ti_Data
- = (ULONG)save_form_banner;
- asl_tags[3].ti_Data = (ULONG)w;
- asl_request
- = AllocAslRequest(ASL_FileRequest,
- asl_tags);
- asl_result = AslRequest(asl_request, NULL);
- if (NULL == asl_result)
- {
- DisplayBeep(NULL);
- break;
- }
- strcpy(form_dir, asl_request->rf_Dir);
- strcpy(form_file, asl_request->rf_File);
- strcpy(form_path, asl_request->rf_Dir);
- if ((form_path[strlen(form_path) - 1] != ':')
- && (strlen(form_path) != 0))
- {
- strcat(form_path, "/");
- }
- strcat(form_path, asl_request->rf_File);
- sts = save_file(form_path, duration, &range,
- scale, &num_voices, tempo,
- form, events, note_len);
- if (sts)
- {
- DisplayBeep(NULL);
- break;
- }
- strcpy(title_string, form_path);
- SetWindowTitles(w, title_string, (void *) -1L);
- FreeAslRequest(asl_request);
- break;
- case 3: /* load a form file */
- asl_tags[0].ti_Data = (ULONG)form_dir;
- asl_tags[1].ti_Data = (ULONG)form_file;
- asl_tags[2].ti_Data
- = (ULONG)load_file_banner;
- asl_tags[3].ti_Data = (ULONG)w;
- asl_request
- = AllocAslRequest(ASL_FileRequest,
- asl_tags);
- asl_result = AslRequest(asl_request, NULL);
- if (NULL == asl_result)
- {
- DisplayBeep(NULL);
- break;
- }
- strcpy(form_dir, asl_request->rf_Dir);
- strcpy(form_file, asl_request->rf_File);
- strcpy(form_path, asl_request->rf_Dir);
- if ((form_path[strlen(form_path)- 1] != ':')
- && (strlen(form_path) != 0))
- {
- strcat(form_path, "/");
- }
- strcat(form_path, asl_request->rf_File);
- sts = read_file(form_path,duration, &range,
- scale, &num_voices, tempo,
- form, events, note_len);
- if (!sts)
- {
- if (0 == *tempo)
- {
- delay_ticks = 0;
- }
- else
- {
- delay_ticks = 50 / (*tempo);
- }
- half_range = range / 2;
- draw_form(duration, form);
- strcpy(title_string, form_path);
- SetWindowTitles(w, title_string,
- (void *) -1L);
- range_time = zero_time;
- set_form_gadgets(form, duration,
- tempo, events, note_len, num_voices);
- set_voice_gadgets(events);
- }
- else
- {
- DisplayBeep(NULL);
- }
- FreeAslRequest(asl_request);
- break;
- case 2: /* Continue after stopping */
- started = TRUE;
- play_note_on(&reset_event);
- GetSysTime(&sys_time);
- str_time->tv_secs = str_time->tv_secs
- + (sys_time.tv_secs - stop_time.tv_secs);
- break;
- case 1: /* stop the music but don't exit */
- started = FALSE;
- for (vox_index = 0;
- vox_index < MAXVOICE; vox_index++)
- {
- events[vox_index].nv_r_start_time
- = events[vox_index].nv_r_duration
- = events[vox_index].nv_r_stop_time
- = zero_time;
- }
- stop_all_notes(events);
- GetSysTime(&stop_time);
- #ifdef MEASURE
- sprintf(measure_string,"%d", gi_notes_measure);
- PrintIText(rast_port, &measure_txt, 1, 1);
- gi_notes_measure = 0;
- #endif
- break;
- case 0: /* Start to Play music */
- started = TRUE;
- done = FALSE;
- GetSysTime(str_time);
- play_note_on(&reset_event);
- for (vox_index = 0;
- vox_index < MAXVOICE; vox_index++)
- {
- events[vox_index].nv_r_start_time
- = events[vox_index].nv_r_duration
- = events[vox_index].nv_r_stop_time
- = zero_time;
- }
- send_function(STARTFUNCT);
- range_time = zero_time;
- break;
- default:
- break;
- } /*switch itemnum*/
- break;
- case FORM: /* Form menu strip was selected */
- if (item != NOITEM)
- switch (item)
- {
- case 0: /* ReDraw */
- draw_form(duration, form);
- break;
- case 1: /* Form */
- open_forms_window();
- break;
- case 2: /* Voice */
- open_voices_window();
- break;
- case 3: /* Orchestra */
- open_orch_window();
- break;
- case 4: /* Colors */
- open_colors_window();
- break;
- default:
- break;
- } /* switch itemnum */
- break;
- } /* switch menunum */
- } /* while not menunull */
- break;
- case CLOSEWINDOW:
- gi_quit = TRUE;
- break;
- default:
- break;
- } /* switch class */
- return;
- } /* end function */
- #endif
-
- static double cvt_time_secs(struct timeval *Time)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Converts system time into floating seconds
- **
- ** RETURN VALUE:
- ** description: floating point seconds
- ** data_type: double
- **
- ** ARGUMENTS:
- **
- ** Time-
- ** description: time
- ** data_type: pointer to struct timeval
- ** access: read only
- **
- ** DESIGN:
- **
- ** ROUTINE cvt_time_secs
- ** : return Time->tv_secs + Time->tv_micro / 1E6
- ** ENDROUTINE
- */
- {
- return (double)Time->tv_secs + ((double)Time->tv_micro / 1E6);
- }
-
- static void stop_note( NOTE_EVENT_TYPE *new_event,
- struct timeval *music_time)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Turn off a note
- **
- ** ARGUMENTS:
- **
- ** new_event-
- ** description: a voice
- ** data_type: pointer to NOTE_EVENT_TYPE
- ** access: read/write
- **
- ** music_time-
- ** description: Current relative time since starting to play
- ** data_type: pointer to struct timeval
- ** access: read only
- **
- ** DESIGN
- **
- ** ROUTINE stop_note
- ** : IF note is playing
- ** : : clear dynamic
- ** : : set stop time to music time
- ** : : play_note_on(new_event)
- ** : : clear playing flag
- ** #if not CLI
- ** : : IF recording
- ** : : : record_note_event(new_event)
- ** : : ENDIF
- ** : ENDIF
- ** ENDROUTINE
- */
- {
- if (new_event->nv_i_playing)
- {
- new_event->nv_i_dynamic = 0;
- new_event->nv_r_stop_time = *music_time;
- if (new_event->nv_i_was_audio)
- {
- play_audio_note(new_event);
- }
- else
- {
- play_note_on(new_event); /* Turn off the old note */
- }
- new_event->nv_i_playing = FALSE;
- #ifndef CLI
- if (recording)
- {
- record_note_event(new_event);
- }
- #endif
- }
- return;
- }
-