home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1995 August / IMM0895.ISO01.iso / share / os2 / track061 / player.c < prev    next >
Text File  |  1992-12-08  |  10KB  |  374 lines

  1. /* player.c */
  2.  
  3. /* modified by David Nichols for OS/2 PM MOD player */
  4.  
  5. /* $Author: espie $
  6.  * $Id: player.c,v 2.10 1991/12/03 23:03:39 espie Exp espie $
  7.  * $Revision: 2.10 $
  8.  * $Log: player.c,v $
  9.  * Revision 2.10  1991/12/03  23:03:39  espie
  10.  * Added transpose feature.
  11.  *
  12.  * Revision 2.9  1991/12/03  21:24:53  espie
  13.  * Reverted to previous behaviour because of intromusic6.b.
  14.  *
  15.  * Revision 2.8  1991/12/03  20:43:46  espie
  16.  * Added possibility to get back to MONO for the sgi.
  17.  *
  18.  * Revision 2.7  1991/12/03  18:07:38  espie
  19.  * Added stereo capabilities to the indigo version.
  20.  *
  21.  * Revision 2.6  1991/12/03  17:12:33  espie
  22.  * Minor changes ??
  23.  *
  24.  * Revision 2.5  1991/11/19  16:07:19  espie
  25.  * Added comments, moved minor stuff around.
  26.  *
  27.  * Revision 2.4  1991/11/18  14:10:30  espie
  28.  * Moved resample part and empty sample test to audio.
  29.  *
  30.  * Revision 2.3  1991/11/18  01:23:30  espie
  31.  * Added two level of fault tolerancy.
  32.  *
  33.  * Revision 2.2  1991/11/18  01:12:31  espie
  34.  * Added some control on the number of replays,
  35.  * and better error recovery.
  36.  *
  37.  * Revision 2.1  1991/11/17  23:07:58  espie
  38.  * Coming from str32.
  39.  *
  40.  */
  41.  
  42. #define INCL_DOS
  43. #define INCL_GPI
  44. #define INCL_WIN
  45.  
  46. #include <stdio.h>
  47. #include <os2.h>
  48. #include <string.h>
  49. #include "defs.h"
  50. #include "os2defs.h"
  51. #include "tracker.h"
  52.  
  53. char songtitle[128];
  54.  
  55. /* init_channel(ch, dummy):
  56.  * setup channel, with initially
  57.  * a dummy sample ready to play,
  58.  * and no note.
  59.  */
  60. void init_channel (struct channel *ch, struct sample_info *dummy)
  61. {
  62.   ch->samp = dummy;
  63.   ch->mode = DO_NOTHING;
  64.   ch->pointer = 0;
  65.   ch->step = 0;
  66.   ch->volume = 0;
  67.   ch->pitch = 0;
  68.   ch->note = NO_NOTE;
  69.  
  70.   /* we don't setup arpeggio values. */
  71.   ch->viboffset = 0;
  72.   ch->vibdepth = 0;
  73.  
  74.   ch->slide = 0;
  75.  
  76.   ch->pitchgoal = 0;
  77.   ch->pitchrate = 0;
  78.  
  79.   ch->volumerate = 0;
  80.  
  81.   ch->vibrate = 0;
  82.   ch->adjust = do_nothing;
  83. }
  84.  
  85. int VSYNC;            /* base number of sample to output */
  86. void (*eval[NUMBER_EFFECTS]) ();
  87.  
  88.  /* the effect table */
  89. int oversample;            /* oversample value */
  90. int frequency;            /* output frequency */
  91. int channel;            /* channel loop counter */
  92.  
  93. char allmodes[] = {PLAYER_PAUSE, PLAYER_RECORD, PLAYER_PLAY, 
  94.     PLAYER_STOP, PLAYER_REWIND, PLAYER_FASTFORWARD, '\0' };
  95.  
  96.  
  97. struct channel chan[NUMBER_TRACKS];
  98.  
  99.  /* every channel */
  100. int countdown;            /* keep playing the tune or not */
  101.  
  102. struct song_info *info;
  103. struct sample_info **voices;
  104.  
  105. int count = 0;
  106.  
  107. int susp = 0;
  108.  
  109. struct automaton a;
  110.  
  111. void init_player (int o, int f)
  112. {
  113.   oversample = o;
  114.   frequency = f;
  115.   init_tables (oversample, frequency);
  116.   init_effects (eval);
  117. }
  118.  
  119. void setup_effect (struct channel *ch, struct automaton *a, struct event *e)
  120. {
  121.   int samp, cmd;
  122.  
  123.   /* retrieves all the parameters */
  124.   samp = e[a->note_num].sample_number;
  125.   a->note = e[a->note_num].note;
  126.   if (a->note != NO_NOTE)
  127.     a->pitch = pitch_table[a->note];
  128.   else
  129.     a->pitch = e[a->note_num].pitch;
  130.   cmd = e[a->note_num].effect;
  131.   a->para = e[a->note_num].parameters;
  132.  
  133.   if (a->pitch >= MAX_PITCH)
  134.     {
  135.        trackerror(5, "Pitch out of bounds", NONFATAL_ERROR);
  136.       a->pitch = 0;
  137.       error = FAULT;
  138.     }
  139.  
  140.   /* load new instrument */
  141.   if (samp)
  142.     {
  143.       /* note that we can change sample in the middle
  144.        * of a note. This is a *feature*, not a bug (see
  145.        * intromusic6.b)
  146.        */
  147.       ch->samp = voices[samp];
  148.       ch->volume = voices[samp]->volume;
  149.     }
  150.   /* check for a new note: cmd 3 (portamento)
  151.    * is the special case where we do not restart
  152.    * the note.
  153.    */
  154.   if (a->pitch && cmd != 3)
  155.     reset_note (ch, a->note, a->pitch);
  156.   ch->adjust = do_nothing;
  157.   /* do effects */
  158.   (eval[cmd]) (a, ch);
  159. }
  160.  
  161. void UpdateControl(char *mess)
  162. {
  163.    static POINTL pl;
  164.  
  165.    pl.x = 15;
  166.    pl.y = 10;
  167.    
  168.    DosEnterCritSec();
  169.  
  170.    /*WinFillRect(hpsTime, &rclTime, CLR_BLACK);*/
  171.    GpiMove(hpsTime, &pl);
  172.    GpiSetColor(hpsTime, 0x00101010);
  173.    GpiCharString(hpsTime, 8, "88 88 88");
  174.    GpiMove(hpsTime, &pl);
  175.    GpiSetColor(hpsTime, 0x0000ff00);
  176.    if (mess) GpiCharString(hpsTime, strlen(mess), mess);
  177.  
  178.    DosExitCritSec();
  179. }
  180.  
  181. void PrintSong(char *fn)
  182. {
  183.    static POINTL pl;
  184.    static char buf[10];
  185.    static i;
  186.  
  187.    pl.x = 7;
  188.    pl.y = 7;
  189.    DosEnterCritSec();
  190.  
  191.    GpiSetColor(hpsSong, RGB_BLUE);
  192.    if (fn != NULL) GpiCharStringAt(hpsSong, &pl, strlen(fn), fn);
  193.    GpiSetColor(hpsName, RGB_BLUE);
  194.    if (fn != NULL) GpiCharStringAt(hpsName, &pl, strlen(songtitle), songtitle);
  195.    pl.y = 10; pl.x = 15;
  196.    sprintf(buf, "%03d:%03d", songnum, numsongs);
  197.    GpiSetColor(hpsQueue, 0x00101010);
  198.    GpiCharStringAt(hpsQueue, &pl, 7, "8888888");
  199.    GpiSetColor(hpsQueue, 0x0000ff00);
  200.    GpiCharStringAt(hpsQueue, &pl, strlen(buf), buf);
  201.    GpiSetColor(hpsTime, 0x0000ff00);
  202.    GpiCharStringAt(hpsTime, &pl, 15, "** ** **   $&**");
  203.    GpiQueryCurrentPosition(hpsTime, &pl);
  204.    GpiSetColor(hpsTime, 0x00101010);
  205.    GpiCharString(hpsTime, strlen(allmodes), allmodes);
  206.    GpiMove(hpsTime, &pl);
  207.    i = playermode[0] - PLAYER_PAUSE;
  208.    strcpy(buf, "\'\'\'\'\'\'\'\'");
  209.    buf[i] = playermode[0];
  210.    buf[i+1] = '\0';
  211.    GpiSetColor(hpsTime, 0x00d00000);
  212.    GpiCharStringAt(hpsTime, &pl, strlen(buf), buf);
  213.  
  214.    DosExitCritSec();
  215. }
  216.  
  217. void DoGraphics(ULONG arg)
  218. {
  219.    PTHREADPARAMS ptp;
  220.    ULONG inc;
  221.    int tenths = 0;
  222.    int hour, min, sec = 0;
  223.    int oldsec = 0;
  224.    char buf[30];
  225.    int sc = 0;
  226.  
  227.    blink = 0;
  228.    ptp = (PTHREADPARAMS)arg;
  229.    PrintSong(ptp->fn);
  230.    while (!ptp->fTerminate)
  231.    {
  232.       DosWaitEventSem(ptp->hevTimer, SEM_INDEFINITE_WAIT);
  233.       DosResetEventSem(ptp->hevTimer, &inc);
  234.       if (suspended || blink) sc += inc;
  235.       else tenths += inc;
  236.       if (blink) tenths += inc;
  237.       oldsec = sec;
  238.       sec = tenths/10;
  239.       min = sec / 60;
  240.       sec = sec - (min * 60);
  241.       hour = min / 60;
  242.       min = min - (hour * 60);
  243.       sprintf(buf, "%02d!%02d\"%02d#", hour, min, sec);
  244.       if (blink && ((sc/2)%3)) strcpy(buf, "**!**\"**#"); 
  245.       if (blink || (oldsec != sec)) UpdateControl(buf);
  246.       else if (suspended && !susp)
  247.       {
  248.      susp = 1;
  249.          UpdateControl(buf);
  250.       }
  251.    }
  252.    DosPostEventSem(ptp->hevDone);
  253. }
  254.  
  255. void PlaySong(ULONG arg)
  256. {
  257.    struct song *song;
  258.    struct pref *pref;
  259.    THREADPARAMS tp;
  260.    PTHREADPARAMS ptp;
  261.    RECTL rcl;
  262.    TID tid;
  263.    HTIMER hTimer;
  264.    static REAL_SWCNTRL SwitchData;
  265.  
  266.    ptp = (PTHREADPARAMS)arg;
  267.    song = ptp->song;
  268.    pref = ptp->pref;
  269.    init_automaton (&a, song);
  270.    strcpy(songtitle, song->title);
  271.    VSYNC = frequency * 100 / pref->speed;
  272.    if (pref->repeats) countdown = pref->repeats; /* if repeat == 0, repeat indefinitely */
  273.    else countdown = 1;
  274.  
  275.    info = song->info;
  276.    voices = song->samples;
  277.  
  278.    DosCreateEventSem("\\sem32\\graphicsdone", &tp.hevDone, 0, (BOOL32) FALSE);
  279.    DosCreateEventSem("\\sem32\\graphicstimer", &tp.hevTimer, 0, (BOOL32) FALSE);
  280.    tp.fTerminate = FALSE;
  281. /*   tp.hpsClient = ptp->hpsClient; */
  282.    tp.fn = ptp->fn;
  283.    DosCreateThread(&tid, DoGraphics, (ULONG)&tp, 0, 0x4000);
  284.    DosSetPriority(PRTYS_THREAD,PRTYC_REGULAR,-31,tid);
  285.    DosStartTimer(100, (HSEM)tp.hevTimer, &hTimer);
  286.   
  287.    for (channel = 0; channel < NUMBER_TRACKS; channel++)
  288.      init_channel (chan + channel, voices[0]);
  289.  
  290.    count = 0;
  291.    while (countdown && !ptp->fTerminate)
  292.    {
  293.       for (channel = 0; channel < NUMBER_TRACKS; channel++)
  294.     if (a.counter == 0) setup_effect (chan + channel, &a, a.pattern->e[channel]);
  295.     else (chan[channel].adjust) (chan + channel); /* do effects */
  296.  
  297.       /* advance player for the next tick */
  298.       next_tick (&a);
  299.       count++;
  300.       /* actually output samples */
  301.       resample (chan, oversample, VSYNC / a.finespeed);
  302.  
  303.       switch (error)
  304.       {
  305.      case NONE:
  306.         break;
  307.  
  308.      case ENDED:
  309.         if (pref->repeats) countdown--;
  310.         count = 0;
  311.         break;
  312.  
  313.      case SAMPLE_FAULT:
  314.          if (!pref->tolerate) countdown = 0;
  315.         break;
  316.  
  317.       case FAULT:
  318.         if (pref->tolerate < 2) countdown = 0;
  319.         break;
  320.  
  321.      case NEXT_SONG:
  322.      case UNRECOVERABLE:
  323.         countdown = 0;
  324.         break;
  325.  
  326.      default:
  327.         break;
  328.       }
  329.       error = NONE;
  330.       if (pauseack)
  331.       {
  332.             flush_DMA_buffers();
  333.         playermode[0] = PLAYER_PAUSE;
  334.         PrintSong(NULL);
  335.             pauseack = 0;
  336.             blink = 0;
  337.             suspended = 1;
  338.             DosWaitEventSem(ptp->hevPause, SEM_INDEFINITE_WAIT);
  339.         susp = 0;
  340.       }
  341.    }
  342.    release_song(song);
  343.    flush_DMA_buffers();
  344.    ptp->fPlaying = FALSE;
  345.    tp.fTerminate = TRUE;
  346.    DosStopTimer(hTimer);
  347.    DosPostEventSem(tp.hevTimer);
  348.    DosWaitEventSem(tp.hevDone, SEM_INDEFINITE_WAIT);
  349.    DosCloseEventSem(tp.hevTimer);
  350.    DosCloseEventSem(tp.hevDone);
  351.    DosEnterCritSec();
  352.  
  353.    WinQueryWindowRect(hwndSong, &rcl);
  354.    WinFillRect(hpsSong, &rcl, CLR_BLACK);
  355.    WinQueryWindowRect(hwndName, &rcl);
  356.    WinFillRect(hpsName, &rcl, CLR_BLACK);
  357.  
  358.    DosExitCritSec();
  359.    if (DosPostEventSem(ptp->hevDone)) trackerror(4, "Semaphore error", FATAL_ERROR);
  360.    WinQuerySwitchEntry(hSwitch, (PSWCNTRL) &SwitchData);
  361.    strcpy(SwitchData.szSwtitle, title);
  362.    WinChangeSwitchEntry(hSwitch, (PSWCNTRL) &SwitchData);
  363.    WinSetWindowText(hwndControl, title);
  364.    if (!abortsong) WinPostMsg(hwndControl,WM_COMMAND,MPFROM2SHORT(IDM_PLAY,0),0);
  365.    else
  366.    {
  367.       playermode[0] = PLAYER_STOP;
  368.       PrintSong(NULL);
  369.    }
  370.    abortsong = 0;
  371.    close_audio();
  372.    frequency = open_audio(frequency, DMAbuffersize);
  373. }
  374.