home *** CD-ROM | disk | FTP | other *** search
/ Audio Version 4.94 / audioversion4.94knowledgemediaresourcelibraryoctober1994.iso / amiga / utils / exp_iv / interrup.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  13KB  |  414 lines

  1. /* interrupt.c */
  2.  
  3. /* set up a CIA interrupt to play the music
  4.  */
  5.  
  6. /* $Author: Espie $
  7.  * $Date: 91/05/20 22:44:37 $
  8.  * $Revision: 1.32 $
  9.  * $Log:    interrupt.c,v $
  10.  * Revision 1.32  91/05/20  22:44:37  Espie
  11.  * *** empty log message ***
  12.  * 
  13.  * Revision 1.31  91/05/16  15:05:08  Espie
  14.  * Modified far stuff.
  15.  *
  16.  * Revision 1.30  91/05/12  19:55:31  Espie
  17.  * correct handling of resume.
  18.  *
  19.  * Revision 1.29  91/05/12  15:59:08  Espie
  20.  * Suppressed some unnecessary assignments... More cleanup in order.
  21.  *
  22.  * Revision 1.28  91/05/09  17:36:26  Espie
  23.  * Support for non standard speed modes.
  24.  *
  25.  * Revision 1.27  91/05/08  15:51:18  Espie
  26.  * Added set_volume command for slider.
  27.  *
  28.  * Revision 1.26  91/05/07  12:13:06  Espie
  29.  * *** empty log message ***
  30.  *
  31.  * Revision 1.25  91/05/06  23:38:32  Espie
  32.  * Changed some includes ???
  33.  *
  34.  * Revision 1.24  91/05/06  15:14:46  Espie
  35.  * Speed is now entirely the responsibility of the player itself.
  36.  *
  37.  * Revision 1.23  91/05/05  19:05:38  Espie
  38.  * Moved most of the player stuff which should be private
  39.  * to the player itself.
  40.  *
  41.  * Revision 1.22  91/05/05  15:38:21  Espie
  42.  * Play is now private/public...
  43.  *
  44.  * Revision 1.21  91/05/02  23:26:38  Espie
  45.  * Almost tested, reliable. Needs some cleanup.
  46.  *
  47.  * Revision 1.20  91/05/02  11:19:22  Espie
  48.  * Added some more tests... Not incredibly reliable.
  49.  *
  50.  * Revision 1.19  91/05/02  01:29:22  Espie
  51.  * Completely new interface, much safer.
  52.  * The hardware part is now completely isolated from the software part.
  53.  *
  54.  * Revision 1.18  91/04/30  00:35:35  Espie
  55.  * Stable version III.
  56.  *
  57.  * Revision 1.17  91/04/30  00:24:28  Espie
  58.  * Modified launch_play() slightly: now resets the speed.
  59.  *
  60.  * Revision 1.16  91/04/29  15:07:26  Espie
  61.  * Cleaned-up, now allocates cia timer on the fly.
  62.  * Important: always ask for audio first, because the system
  63.  * avoids deadlock in that case.
  64.  *
  65.  * Revision 1.15  91/04/29  02:21:39  Espie
  66.  * Suppressed ``critical sections''.
  67.  *
  68.  * Revision 1.14  91/04/28  20:34:43  Espie
  69.  * Added fine speed control, definitely needs some cleanup now.
  70.  *
  71.  * Revision 1.13  91/04/27  20:48:26  Espie
  72.  * New dual speed tempo.
  73.  *
  74.  * Revision 1.12  91/04/27  16:44:17  Espie
  75.  * Slight changes.
  76.  *
  77.  * Revision 1.11  91/04/27  04:00:39  Espie
  78.  * Little as changed.
  79.  *
  80.  * Revision 1.10  91/04/26  16:30:36  Espie
  81.  * Now the interrupt routines times itself, so there
  82.  * are new fields to set up correctly.
  83.  *
  84.  * Revision 1.9  91/04/24  15:25:35  Espie
  85.  * Minor changes ??
  86.  *
  87.  * Revision 1.8  91/04/23  21:28:33  Espie
  88.  * New interrupt settings: since the player knows when not to play anything,
  89.  * it is no longer necessary to give a valid song to establish the interrupt.
  90.  * Also, the memory for interrupt and play structure is now dynamically allocated
  91.  * as public memory, which seems more reasonable.
  92.  *
  93.  * Revision 1.7  91/04/21  20:05:16  Espie
  94.  * Oversampling.
  95.  *
  96.  * Revision 1.6  91/04/21  12:11:40  Espie
  97.  * Stable version, known as bunch II.
  98.  * Also features ``right'' log description.
  99.  *
  100.  * Revision 1.5  91/04/20  18:14:04  Espie
  101.  * Added symbolic constants everywhere.
  102.  *
  103.  * Revision 1.4  91/04/19  13:21:27  Espie
  104.  * New interrupt setup, still needs to dynamically allocate
  105.  * interrupt structure, plus some symbolic constants.
  106.  *
  107.  * Revision 1.3  91/04/19  02:19:17  Espie
  108.  * Still many things to do. Concept of a ``play'' structure working.
  109.  * Timing ok.
  110.  *
  111.  * Revision 1.2  91/04/18  20:24:09  Espie
  112.  * Complete interrupt driver, speed is correct (small bug in play.c),
  113.  * setup is correct. Take care that you can't change is_Data after
  114.  * you've added the server.
  115.  *
  116.  * Revision 1.1  91/04/18  16:38:05  Espie
  117.  * Initial revision
  118.  *
  119.  */
  120.  
  121. #include <exec/types.h>
  122. #include <exec/execbase.h>
  123. #include <exec/memory.h>
  124. #include <hardware/cia.h>
  125. #include <custom/cleanup.h>
  126. #include <proto/exec.h>
  127. #include <proto/cia.h>
  128. #include <stdio.h>
  129. #include <dos/dos.h>
  130. #include <proto/exec.h>
  131. #include "song.h"
  132. #include "proto.h"
  133. #include "player.h"
  134. #include "public_play.h"
  135. #include "int_play.h"
  136.  
  137. extern struct ExecBase *SysBase;
  138.  
  139. #ifdef LATTICE
  140. #define FAR_SUPPORT __far
  141. #else
  142. #error
  143. #endif
  144. extern volatile struct CIA FAR_SUPPORT ciab;
  145.  
  146. struct BattMemBase *BattMemBase;
  147. LOCAL CLEAN int_clean;
  148.  
  149. /* this is the logical interface structure with the interrupt
  150.  * you send things to the interrupt through its data structure (play).
  151.  * If you specify it, the interrupt will signal you when something
  152.  * interesting happens (specifiy a task/signal mask...)
  153.  *
  154.  * In that case, you can check the play oflags to know what triggered
  155.  * the signal. Don't forget to reset it yourself if you want to know
  156.  * what's going on next time. Also, don't forget that the interrupt
  157.  * won't stop for you, i.e., while you're processing that signal,
  158.  * the interrupt might send other signals to you.
  159.  * As a general rule, unless you disable/enable, don't expect any
  160.  * field in the play structure to stay constant. That's generally not
  161.  * a problem.
  162.  */
  163. LOCAL struct play *play;
  164. LOCAL struct pub_play *public;
  165. LOCAL struct priv_play *private;
  166. LOCAL struct Interrupt *timerinterrupt;
  167.  
  168. LOCAL ULONG timerbase;
  169. LOCAL ULONG current_tempo = 256, current_effect = 256;
  170. LOCAL BOOL available = FALSE, running = FALSE;
  171.  
  172.  
  173. LOCAL void latch_tempo(void)
  174.         {
  175.                 Disable();
  176.                 public->timebase = timerbase*current_tempo/128;
  177.                 public->effectbase = timerbase*current_effect/128;
  178.                 private->tempo_change = TRUE;
  179.                 Enable();
  180.         }
  181.  
  182.  
  183. /* country dependency: the frequency of the timers is different
  184.  * when you change countries. The precise values are listed
  185.  * in the hardware manual.
  186.  */
  187. LOCAL void set_timerbase(void)
  188.         {
  189.                 switch(SysBase->PowerSupplyFrequency)
  190.                         {
  191.                                 case 50:
  192.                                         timerbase = 709379;
  193.                                         break;
  194.                                 case 60:
  195.                                         timerbase = 715909;
  196.                                         break;
  197.                                 default:
  198.                                         break;
  199.                         }
  200.         }
  201.  
  202.  
  203. LOCAL void timer_on(void)
  204.         {
  205.                 *private->control |= CIACRAF_START;
  206.         }
  207.  
  208.  
  209. LOCAL void timer_off(void)
  210.         {
  211.                 *private->control &= ~CIACRAF_START;
  212.         }
  213.  
  214.  
  215. /* if you want to modify play yourself, don't forget to Disable()/Enable()
  216.  * all the changes, so that the interrupt routine will always see something
  217.  * coherent. Don't forget to make it fast
  218.  */
  219.  
  220. /* sine table for vibrato command */
  221.  
  222. BYTE sine_table[32] =
  223.         {0,25,49,71,90,106,117,125,127,125,117,106,90,
  224.          71,49,25,0,-25,-49,-71,-90,-106,-117,-125,-127,
  225.          -125,-117,-106,-90,-71,-49,-25};
  226.  
  227.  
  228.  
  229. LOCAL void init_structures()
  230.         {
  231.         int i;
  232.                 play = AllocMem(sizeof(struct play), MEMF_PUBLIC | MEMF_CLEAR);
  233.                 if (play)
  234.                         ToClean2(FreeMem, play, sizeof(struct play));
  235.                 else
  236.                         mayPanic("Could not allocate data structure for replay");
  237.  
  238.                 public = &(play->public);
  239.                 private = &(play->private);
  240.  
  241.                 for (i = 0; i < 32; i++)
  242.                         play->sine_table[i] = sine_table[i];
  243.                 private->sine_table = play->sine_table;
  244.                 for (i = 0; i < NUMBER_TUNING; i++)
  245.                         {
  246.                                 play->period_table[i] = play->periods + NUMBER_NOTES * i;
  247.                         }
  248.  
  249.                 init_periods(play->period_table);
  250.                 private->period_table = play->period_table;
  251.                 for (i = 0; i < NUMBER_TRACKS; i++)
  252.                         private->track[i] = play->tracks + i;
  253.  
  254.                 private->channel_mask = play->channel_mask;
  255.                 private->setup = play->setup;
  256.                 private->state = init_player;
  257.  
  258.  
  259.         /* don't need that */
  260. /*              public->volume = 256;
  261.  */
  262.                 public->command = STOP;
  263.         /* done by the MEMF_CLEAR, but keep as comments that this is a good idea.
  264.                 public->resume = FALSE;
  265.                 public->info = NULL;
  266. */
  267.  
  268.  
  269.                 timerinterrupt = AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC|MEMF_CLEAR);
  270.                 if (timerinterrupt)
  271.                         ToClean2(FreeMem, timerinterrupt, sizeof(struct Interrupt));
  272.                 else
  273.                         mayPanic("Could not allocate interrupt structure");
  274.  
  275.                 timerinterrupt->is_Node.ln_Type = NT_INTERRUPT;
  276. /*              timerinterrupt->is_Node.ln_Pri = 0;
  277.  */
  278.                 timerinterrupt->is_Node.ln_Name = "player";
  279.                 timerinterrupt->is_Data = play;
  280.                 timerinterrupt->is_Code = &do_play;
  281.         }
  282.  
  283. LOCAL void open_cia(void)
  284.         {
  285.                 BattMemBase = OpenResource("ciab.resource");
  286.                 if (!BattMemBase)
  287.                         mayPanic("Could not open ciab resource");
  288.         }
  289.  
  290. LOCAL void init_interrupt(void)
  291.         {
  292.         int signal;
  293.                 set_timerbase();
  294.                 init_structures();
  295.                 open_cia();
  296.                 signal = AllocSignal(-1);
  297.                 if (signal == -1)
  298.                         mayPanic("No signals available");
  299.                 else
  300.                         ToClean(FreeSignal, signal);
  301.                 public->signal = 1<<signal;
  302.                 public->task = FindTask(0L);
  303.         }
  304.  
  305.  
  306. /* the install timer now puts everything back in the
  307.  * state it should be
  308.  */
  309. LOCAL void install_timer(void)
  310.         {
  311.         int old;
  312.                 int_clean = AllocClean(NIL);
  313.                 old = AddICRVector(BattMemBase, CIAICRB_TB, timerinterrupt);
  314.                 if (!old)
  315.                         {
  316.                                 ToClean3L(int_clean, RemICRVector, BattMemBase, CIAICRB_TB,
  317.                                                 timerinterrupt);
  318.                                 private->control = &(ciab.ciacrb);
  319.                                 private->latchlo = &(ciab.ciatblo);
  320.                                 private->latchhi = &(ciab.ciatbhi);
  321.                         }
  322.                 else
  323.                         {
  324.                                 old = AddICRVector(BattMemBase, CIAICRB_TA, timerinterrupt);
  325.                                 if (!old)
  326.                                         {
  327.                                                 ToClean3L(int_clean, RemICRVector, BattMemBase, CIAICRB_TA,
  328.                                                         timerinterrupt);
  329.                                                 private->control = &(ciab.ciacra);
  330.                                                 private->latchlo = &(ciab.ciatalo);
  331.                                                 private->latchhi = &(ciab.ciatahi);
  332.                                         }
  333.                                 else
  334.                                         mayPanic("Sorry, no timer available");
  335.                         }
  336.                 ToClean0L(int_clean, timer_off);
  337.                         /* keep the alarm running */
  338.                 *private->control &= CIACRBF_ALARM;
  339.                 latch_tempo();
  340.         }
  341.  
  342.  
  343. struct pub_play *obtain_player()
  344.         {
  345.                 init_interrupt();
  346.                 return public;
  347.         }
  348.  
  349. void start_timer(void)
  350.         {
  351.                 if (!available)
  352.                         {
  353.                                 install_timer();
  354.                                 timer_on();
  355.                                 available = TRUE;
  356.                         }
  357.         }
  358.  
  359. void stop_timer(void)
  360.         {
  361.                 if (available)
  362.                         {
  363.                                 timer_off();
  364.                                 CleanUp(int_clean);
  365.                                 public->resume = TRUE;
  366.                                 available = FALSE;
  367.                         }
  368.         }
  369.  
  370. /* ``standard'' frequency is 50Hz.
  371.  * tempo is in 256th.
  372.  */
  373. void set_tempo(int tempo, int effect)
  374.         {
  375.                 current_tempo = tempo;
  376.                 current_effect = effect;
  377.                 if (available)
  378.                         latch_tempo();
  379.         }
  380.  
  381. void set_volume(int new_value)
  382.         {
  383.                 public->volume = new_value;
  384.         }
  385.  
  386. void set_mode(int mode)
  387.         {
  388.                 public->mode = mode;
  389.         }
  390.  
  391. void setup_song(struct song *s)
  392.         {
  393.                 Disable();
  394.                 public->command = STOP;
  395.                 public->pattern = 0;
  396.                 public->position = 0;
  397.                 public->info = s->info;
  398.                 public->sample = s->samples;
  399.                 public->resume = FALSE;
  400.                 Enable();
  401.         }
  402.  
  403. void launch_play(int patt)
  404.         {
  405.                 if (public->info)
  406.                         {
  407.                                 Disable();
  408.                                 public->command = NEWPOS;
  409.                                 public->pattern = patt;
  410.                                 public->position = 0;
  411.                                 Enable();
  412.                         }
  413.         }
  414.