home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * Copyright (C) 1991, Silicon Graphics, Inc.
- * All Rights Reserved.
- */
-
- /*
- * synthia - A MIDI synthesizer program for Hollywood
- *
- * Jim Bennett
- * 1991
- *
- * Added test to see of audio port successfully open
- * (10/30/91, Marvin Kong).
- */
-
- #include <limits.h>
- #include <sys/types.h>
- #include <sys/prctl.h>
- #include <sys/schedctl.h>
- #include <sys/time.h>
-
- #include <audio.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <getopt.h>
- #include <signal.h>
- #include <gl/gl.h>
- #include <gl/device.h>
- #include "paths.h"
- #include "midif.h"
- #include "globj.h"
-
- /*
- * Global variables
- */
-
- float current_volume = 0.5;
- int current_voice = -1;
-
- int dographics;
- int maxvoices;
- int tracklist [MAX_TRACKS];
- int instruments [INSTRUMENTS];
- float beat_time;
-
- int keydowns[128] = {0};
- int maxfinger;
-
- /*
- * Local variables
- */
-
- static int allups[128] = {0};
-
- static struct s_mfhd mf_header;
-
- static struct s_ptrk *tracks;
-
- static int toggle_state;
-
- /*
- * Input status
- */
-
- #define MAX_VOLUME 0.85
- #define MIN_VOLUME 0.1
- #define MSCALE 0.01
-
- static int change_volume = FALSE;
- static int lastx = 0;
- static int lasty = 0;
-
-
- /*
- * synthia: Usage: synthia [options] <midifile>
- *
- * Options: -n No graphics
- * -v # Number of voices (default 6)
- * -t <list> Play specific tracks only
- * -i <alist> Assign instruments
- * -b # Set beat time (default .5 seconds)
- */
-
- main (argc, argv)
-
- int argc;
- char *argv[];
-
- {
- int c;
- long param;
- double fparam;
- char *ptr;
- FILE *midifile;
- char *buf;
- char *path;
- int frames, resolution, i, n;
- ALconfig config;
- ALport audio_out;
- long parambuf[2];
-
- printf ("Synthia version 1.3\n");
-
- /* Process command line arguments */
-
- dographics = 1; /* Set defaults */
- maxvoices = 6;
- for (i=0; i<MAX_TRACKS; i++)
- tracklist[i] = 1; /* Play all tracks */
- for (i=0; i<INSTRUMENTS; i++)
- instruments[i] = i; /* Default instruments */
- beat_time = 0.5;
-
- while ((c = getopt (argc, argv, "nv:t:i:b:")) != -1)
- {
- switch (c)
- {
- case 'n':
- dographics = 0;
- break;
-
- case 'v':
- param = strtol (optarg, &ptr, 10);
- if ((ptr == optarg) ||
- (*ptr && !isspace (*ptr)))
- {
- printf ("Bad argument for v option\n\n");
- print_usage ();
- exit (1);
- }
- if ((param < 0) || (param >= MAX_VOICES))
- {
- printf ("Max voices of range (0-%d)\n\n", MAX_VOICES-1);
- print_usage ();
- exit (1);
- }
- maxvoices = param;
- break;
-
- case 't':
- if (process_tracklist (optarg))
- {
- print_usage ();
- exit (1);
- }
- break;
-
- case 'i':
- if (process_instlist (optarg))
- {
- print_usage ();
- exit (1);
- }
- break;
-
- case 'b':
- fparam = strtod (optarg, &ptr);
- if ((ptr == optarg) ||
- (*ptr && !isspace (*ptr)))
- {
- printf ("Bad argument for b option\n\n");
- print_usage ();
- exit (1);
- }
- beat_time = fparam;
- break;
-
- default:
- printf ("\n");
- print_usage ();
- exit (1);
- }
- }
-
- /* The final argument is the MIDI file */
- /* Validate the file and read in the header */
-
- if (optind != argc-1)
- {
- print_usage ();
- exit (1);
- }
-
- midifile = fopen (argv[optind], "r");
- if ((midifile == NULL) && (*argv[optind] != '/'))
- {
- if (!(path = getenv("SYNTHIA_MIDI_PATH")))
- path = MIDI_PATH;
- buf = (char *)malloc
- (strlen(argv[optind]) + strlen(path) + 2);
- strcpy (buf, path);
- strcat (buf, "/");
- strcat (buf, argv[optind]);
- midifile = fopen (buf, "r");
- }
- if (midifile == NULL)
- {
- fprintf (stderr, "Can't open %s\n", argv[optind]);
- exit (1);
- }
-
- if (mf_read_hd (midifile, &mf_header) < 0)
- {
- fprintf (stderr, "%s is not a valid MIDI file\n",
- argv[optind]);
- exit (1);
- }
-
- /* Put up a window if we are doing graphics */
-
- if (dographics)
- {
- keepaspect (2, 1);
- fflush (midifile);
- /* Needed because winopen does a fork, */
- /* and new POSIX compliant stdio gets */
- /* confused by forks. */
- winopen ("MIDI synthesizer");
- RGBmode ();
- gconfig ();
- RGBcolor (0, 0, 0);
- clear ();
-
- shademodel (FLAT);
- backface (TRUE);
- zbuffer (TRUE);
- subpixel (TRUE);
-
- def_curs ();
- setcursor (BUSY_BEE_1, 0, 0);
- start_waiting ();
-
- def_kbd ();
- draw_scene (FALSE);
-
- qdevice (WINSHUT);
- qdevice (WINQUIT);
- qdevice (WINCLOSE);
- qdevice (LEFTMOUSE);
- qdevice (MOUSEX); qdevice (MOUSEY);
- }
-
- /* File opened, and header is valid, print it out */
-
- #ifdef DEBUG
- printf ("MIDI file header:\n");
- printf (" format = %d\n", mf_header.format);
- printf (" ntrks = %d\n", mf_header.ntrks);
- printf (" division = %d\n", mf_header.division);
- #endif
-
- if (mf_header.format != 1)
- {
- fprintf (stderr, "\nOnly format 1 is supported.\n");
- exit (1);
- }
-
- /* Compute time resolution */
-
- if ((mf_header.division & 0x8000) == 0x8000)
- { /* Real time mode */
- frames = (mf_header.division >> 8) & 0xff;
- frames = 256 - frames;
- resolution = mf_header.division & 0xff;
- resolution = resolution * frames;
- }
- else
- /* Else is quarter note division */
- resolution = mf_header.division * (1.0/beat_time);
-
- /* Then read in the tracks */
-
- tracks = (struct s_ptrk *)malloc
- (sizeof(struct s_ptrk) * mf_header.ntrks);
- for (i=0; i<mf_header.ntrks; i++)
- {
- tracks[i].base = (struct s_mfevent *)mf_read_trk
- (midifile, resolution);
- n = (int)tracks[i].base;
- if (n < 0)
- {
- printf ("Bad MIDI file: error %d\n", n);
- exit (1);
- }
- tracks[i].nfingers = maxfinger;
-
- /* Disable all tracks that aren't selected */
-
- if (!tracklist[i])
- (tracks[i].base)->time = END_TIME;
- }
-
- /* Now the data is in a handy format, try playing the tracks */
-
- /* First initialize waveform tables and audio ports */
-
- wf_init (); /* Initialize wave form tables */
- wl_init (); /* Initialize wavelength table */
-
- config = ALnewconfig ();
-
- ALsetwidth (config, AL_SAMPLE_16);
- ALsetqueuesize (config, 2*SAMPLE_BUFSIZE);
- parambuf[0] = AL_OUTPUT_RATE;
- parambuf[1] = SYNTHIA_RATE;
- ALsetparams (AL_DEFAULT_DEVICE, parambuf, 2);
-
- audio_out = ALopenport ("outport", "w", config);
-
- /* Test if audio port OK. */
- if( audio_out == 0 ) {
- printf("\nERROR: Could not open audio port.\n");
- exit(0);
- }
-
- /* All ready, set up non-degrading priority and get to work */
-
- if (schedctl (NDPRI, 0, NDPNORMMAX+10) < 0)
- perror ("schedctl");
- stop_waiting ();
- setcursor (0, 0, 0);
-
- playtracks (audio_out, mf_header.ntrks, tracks);
-
- while (ALgetfilled(audio_out) > 0)
- sleep (1);
-
- ALcloseport (audio_out);
- }
-
- /*
- * process_tracklist - Process comma separated list of tracks
- * to play
- *
- * Returns 1 if error
- */
-
- process_tracklist (list)
-
- char *list;
-
- {
- int i;
- char *ptr;
- long track, endtrack;
-
- for (i=0; i<MAX_TRACKS; i++)
- tracklist[i] = 0;
- ptr = list;
- while (*list && !isspace(*list))
- {
- track = strtol (list, &ptr, 10);
- if (ptr == list)
- {
- printf ("Bad track list\n\n");
- return (1);
- }
- if (isspace(*ptr) || (*ptr == ',') || (*ptr == 0))
- {
- if ((track < 0) || (track >= MAX_TRACKS))
- {
- printf ("track number out of range (0-%d)\n\n", MAX_TRACKS-1);
- return (1);
- }
- tracklist[track] = 1;
- if (*ptr == ',') ptr++;
- }
- else if (*ptr == '-')
- { /* Handle range of tracks */
- ptr++;
- list = ptr;
- endtrack = strtol (list, &ptr, 10);
- if (ptr == list)
- {
- printf ("Bad track list\n\n");
- return (1);
- }
- if (isspace(*ptr) || (*ptr == ',') || (*ptr == 0))
- {
- if ((endtrack < 0) || (endtrack >= MAX_TRACKS))
- {
- printf ("track number out of range (0-%d)\n\n", MAX_TRACKS-1);
- return (1);
- }
- for (i=track; i<=endtrack; i++)
- tracklist[i] = 1;
- if (*ptr == ',') ptr++;
- }
- else
- {
- printf ("Bad track list\n\n");
- return (1);
- }
- }
- else
- {
- printf ("Bad track list\n\n");
- return (1);
- }
- list = ptr;
- }
- return (0);
- }
-
- /*
- * process_instlist - Process comma separated list of instrument
- * assignments
- *
- * Returns 1 if error
- */
-
- process_instlist (list)
-
- char *list;
-
- {
- char *ptr;
- long inst1, inst2;
-
- ptr = list;
- while (*list && !isspace(*list))
- {
- inst1 = strtol (list, &ptr, 10);
- if ((ptr == list) || (*ptr != '='))
- {
- printf ("Bad instrument assignment\n\n");
- return (1);
- }
- if ((inst1<0) || (inst1 >= INSTRUMENTS))
- {
- printf ("instrument number out of range (0-%d)\n\n", INSTRUMENTS-1);
- return (1);
- }
- ptr++;
- list = ptr;
-
- inst2 = strtol (list, &ptr, 10);
- if ((ptr == list) || (*ptr && !isspace(*ptr) && (*ptr != ',')))
- {
- printf ("Bad instrument assignment\n\n");
- return (1);
- }
- if ((inst2<0) || (inst2 >= INSTRUMENTS))
- {
- printf ("instrument number out of range (0-%d)\n\n", INSTRUMENTS-1);
- return (1);
- }
-
- instruments[inst1] = inst2;
- if (*ptr == ',') ptr++;
- list = ptr;
- }
- return (0);
- }
-
- /*
- * print_usage - Print out usage message
- */
-
- print_usage ()
-
- {
- printf ("Usage: synthia [options] <midifile>\n");
- printf ("Options: -n No graphics\n");
- printf (" -v # Number of voices (default 6)\n");
- printf (" -t <list> Play specific tracks only\n");
- printf (" -i <alist> Assign instruments\n");
- printf (" -b # Set beat time (default .5 seconds)\n");
- }
-
- /*
- * check_input - Check for input and handle it
- */
-
- check_input ()
-
- {
- long idev;
- short idata;
- int do_redraw;
- int do_slider;
- int do_buttons;
- int mx, my, dx, dy;
- int picked, new_voice;
-
- do_redraw = FALSE;
- do_slider = FALSE;
- do_buttons = FALSE;
- while (qtest ())
- {
- idev = qread (&idata);
- switch (idev)
- {
- case REDRAW:
- do_redraw = TRUE;
- break;
-
- case WINQUIT:
- case WINCLOSE:
- exit (0);
-
- case LEFTMOUSE:
- if (idata)
- {
- picked = check_pick ();
- if (picked == VPEG)
- change_volume = TRUE;
- else
- if ((picked >= SEL_BUTTON) &&
- (picked <(SEL_BUTTON+NUM_BUTTONS)))
- {
- new_voice = picked-SEL_BUTTON;
- if (new_voice == current_voice)
- current_voice = -1;
- else
- current_voice = new_voice;
- do_buttons = TRUE;
- }
- restore_projection ();
- }
- else
- change_volume = FALSE;
- break;
-
- case MOUSEX:
- mx = idata;
- my = lasty;
- goto do_mouse;
-
- case MOUSEY:
- my = idata;
- mx = lastx;
-
- do_mouse: if (change_volume && ((my-lasty) != 0))
- {
- current_volume += MSCALE * (my-lasty);
- if (current_volume > MAX_VOLUME)
- current_volume = MAX_VOLUME;
- if (current_volume < MIN_VOLUME)
- current_volume = MIN_VOLUME;
- do_slider = TRUE;
- }
-
- lastx = mx;
- lasty = my;
- break;
-
- default:
- break;
- }
- }
- if (do_redraw)
- draw_scene (FALSE);
- else if (do_slider)
- display_slider (current_volume);
- else if (do_buttons)
- display_buttons (current_voice);
- }
-
- /*
- * draw_scene - Draw complete image
- */
-
- draw_scene (in_picking)
-
- int in_picking;
-
- {
- restore_projection ();
- RGBcolor (BACKGROUND);
- clear ();
- zclear ();
- if (!in_picking) callobj (CASE_OBJ);
- display_slider (current_volume);
- display_buttons (current_voice);
- display_keys (allups);
- }
-
- /*
- * restore_projection - Reset viewport and projection
- */
-
- restore_projection ()
-
- {
- reshapeviewport ();
- perspective (150, 2.0, 1.0, 200.0);
- translate (-(CASE_W/2.0), -5.0, -80.0);
- rotate (300, 'x');
- }
-
- /*
- * start_waiting - Enable the busy cursor display
- */
-
- start_waiting ()
-
- {
- struct itimerval setval;
- void toggle_cursor ();
-
- toggle_state = FALSE;
- signal (SIGALRM, toggle_cursor);
-
- setval.it_interval.tv_sec = 0;
- setval.it_interval.tv_usec = 250000;
- setval.it_value.tv_sec = 0;
- setval.it_value.tv_usec = 250000;
- setitimer (ITIMER_REAL, &setval, NULL);
- }
-
- /*
- * stop_waiting - Disable the busy cursor display
- */
-
- stop_waiting ()
-
- {
- struct itimerval setval;
-
- signal (SIGALRM, SIG_IGN);
-
- setval.it_interval.tv_sec = 0;
- setval.it_interval.tv_usec = 0;
- setval.it_value.tv_sec = 0;
- setval.it_value.tv_usec = 0;
- setitimer (ITIMER_REAL, &setval, NULL);
- }
-
- /*
- * toggle_cursor - Toggle the cursor periodically to indicate
- * a busy state.
- */
-
- void toggle_cursor ()
-
- {
- signal (SIGALRM, toggle_cursor);
- if (toggle_state)
- {
- setcursor (BUSY_BEE_1, 0, 0);
- toggle_state = FALSE;
- }
- else
- {
- setcursor (BUSY_BEE_2, 0, 0);
- toggle_state = TRUE;
- }
- }
-