home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio Version 4.94
/
audioversion4.94knowledgemediaresourcelibraryoctober1994.iso
/
amiga
/
utils
/
exp_iv
/
interrup.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-20
|
13KB
|
414 lines
/* interrupt.c */
/* set up a CIA interrupt to play the music
*/
/* $Author: Espie $
* $Date: 91/05/20 22:44:37 $
* $Revision: 1.32 $
* $Log: interrupt.c,v $
* Revision 1.32 91/05/20 22:44:37 Espie
* *** empty log message ***
*
* Revision 1.31 91/05/16 15:05:08 Espie
* Modified far stuff.
*
* Revision 1.30 91/05/12 19:55:31 Espie
* correct handling of resume.
*
* Revision 1.29 91/05/12 15:59:08 Espie
* Suppressed some unnecessary assignments... More cleanup in order.
*
* Revision 1.28 91/05/09 17:36:26 Espie
* Support for non standard speed modes.
*
* Revision 1.27 91/05/08 15:51:18 Espie
* Added set_volume command for slider.
*
* Revision 1.26 91/05/07 12:13:06 Espie
* *** empty log message ***
*
* Revision 1.25 91/05/06 23:38:32 Espie
* Changed some includes ???
*
* Revision 1.24 91/05/06 15:14:46 Espie
* Speed is now entirely the responsibility of the player itself.
*
* Revision 1.23 91/05/05 19:05:38 Espie
* Moved most of the player stuff which should be private
* to the player itself.
*
* Revision 1.22 91/05/05 15:38:21 Espie
* Play is now private/public...
*
* Revision 1.21 91/05/02 23:26:38 Espie
* Almost tested, reliable. Needs some cleanup.
*
* Revision 1.20 91/05/02 11:19:22 Espie
* Added some more tests... Not incredibly reliable.
*
* Revision 1.19 91/05/02 01:29:22 Espie
* Completely new interface, much safer.
* The hardware part is now completely isolated from the software part.
*
* Revision 1.18 91/04/30 00:35:35 Espie
* Stable version III.
*
* Revision 1.17 91/04/30 00:24:28 Espie
* Modified launch_play() slightly: now resets the speed.
*
* Revision 1.16 91/04/29 15:07:26 Espie
* Cleaned-up, now allocates cia timer on the fly.
* Important: always ask for audio first, because the system
* avoids deadlock in that case.
*
* Revision 1.15 91/04/29 02:21:39 Espie
* Suppressed ``critical sections''.
*
* Revision 1.14 91/04/28 20:34:43 Espie
* Added fine speed control, definitely needs some cleanup now.
*
* Revision 1.13 91/04/27 20:48:26 Espie
* New dual speed tempo.
*
* Revision 1.12 91/04/27 16:44:17 Espie
* Slight changes.
*
* Revision 1.11 91/04/27 04:00:39 Espie
* Little as changed.
*
* Revision 1.10 91/04/26 16:30:36 Espie
* Now the interrupt routines times itself, so there
* are new fields to set up correctly.
*
* Revision 1.9 91/04/24 15:25:35 Espie
* Minor changes ??
*
* Revision 1.8 91/04/23 21:28:33 Espie
* New interrupt settings: since the player knows when not to play anything,
* it is no longer necessary to give a valid song to establish the interrupt.
* Also, the memory for interrupt and play structure is now dynamically allocated
* as public memory, which seems more reasonable.
*
* Revision 1.7 91/04/21 20:05:16 Espie
* Oversampling.
*
* Revision 1.6 91/04/21 12:11:40 Espie
* Stable version, known as bunch II.
* Also features ``right'' log description.
*
* Revision 1.5 91/04/20 18:14:04 Espie
* Added symbolic constants everywhere.
*
* Revision 1.4 91/04/19 13:21:27 Espie
* New interrupt setup, still needs to dynamically allocate
* interrupt structure, plus some symbolic constants.
*
* Revision 1.3 91/04/19 02:19:17 Espie
* Still many things to do. Concept of a ``play'' structure working.
* Timing ok.
*
* Revision 1.2 91/04/18 20:24:09 Espie
* Complete interrupt driver, speed is correct (small bug in play.c),
* setup is correct. Take care that you can't change is_Data after
* you've added the server.
*
* Revision 1.1 91/04/18 16:38:05 Espie
* Initial revision
*
*/
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <hardware/cia.h>
#include <custom/cleanup.h>
#include <proto/exec.h>
#include <proto/cia.h>
#include <stdio.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include "song.h"
#include "proto.h"
#include "player.h"
#include "public_play.h"
#include "int_play.h"
extern struct ExecBase *SysBase;
#ifdef LATTICE
#define FAR_SUPPORT __far
#else
#error
#endif
extern volatile struct CIA FAR_SUPPORT ciab;
struct BattMemBase *BattMemBase;
LOCAL CLEAN int_clean;
/* this is the logical interface structure with the interrupt
* you send things to the interrupt through its data structure (play).
* If you specify it, the interrupt will signal you when something
* interesting happens (specifiy a task/signal mask...)
*
* In that case, you can check the play oflags to know what triggered
* the signal. Don't forget to reset it yourself if you want to know
* what's going on next time. Also, don't forget that the interrupt
* won't stop for you, i.e., while you're processing that signal,
* the interrupt might send other signals to you.
* As a general rule, unless you disable/enable, don't expect any
* field in the play structure to stay constant. That's generally not
* a problem.
*/
LOCAL struct play *play;
LOCAL struct pub_play *public;
LOCAL struct priv_play *private;
LOCAL struct Interrupt *timerinterrupt;
LOCAL ULONG timerbase;
LOCAL ULONG current_tempo = 256, current_effect = 256;
LOCAL BOOL available = FALSE, running = FALSE;
LOCAL void latch_tempo(void)
{
Disable();
public->timebase = timerbase*current_tempo/128;
public->effectbase = timerbase*current_effect/128;
private->tempo_change = TRUE;
Enable();
}
/* country dependency: the frequency of the timers is different
* when you change countries. The precise values are listed
* in the hardware manual.
*/
LOCAL void set_timerbase(void)
{
switch(SysBase->PowerSupplyFrequency)
{
case 50:
timerbase = 709379;
break;
case 60:
timerbase = 715909;
break;
default:
break;
}
}
LOCAL void timer_on(void)
{
*private->control |= CIACRAF_START;
}
LOCAL void timer_off(void)
{
*private->control &= ~CIACRAF_START;
}
/* if you want to modify play yourself, don't forget to Disable()/Enable()
* all the changes, so that the interrupt routine will always see something
* coherent. Don't forget to make it fast
*/
/* sine table for vibrato command */
BYTE sine_table[32] =
{0,25,49,71,90,106,117,125,127,125,117,106,90,
71,49,25,0,-25,-49,-71,-90,-106,-117,-125,-127,
-125,-117,-106,-90,-71,-49,-25};
LOCAL void init_structures()
{
int i;
play = AllocMem(sizeof(struct play), MEMF_PUBLIC | MEMF_CLEAR);
if (play)
ToClean2(FreeMem, play, sizeof(struct play));
else
mayPanic("Could not allocate data structure for replay");
public = &(play->public);
private = &(play->private);
for (i = 0; i < 32; i++)
play->sine_table[i] = sine_table[i];
private->sine_table = play->sine_table;
for (i = 0; i < NUMBER_TUNING; i++)
{
play->period_table[i] = play->periods + NUMBER_NOTES * i;
}
init_periods(play->period_table);
private->period_table = play->period_table;
for (i = 0; i < NUMBER_TRACKS; i++)
private->track[i] = play->tracks + i;
private->channel_mask = play->channel_mask;
private->setup = play->setup;
private->state = init_player;
/* don't need that */
/* public->volume = 256;
*/
public->command = STOP;
/* done by the MEMF_CLEAR, but keep as comments that this is a good idea.
public->resume = FALSE;
public->info = NULL;
*/
timerinterrupt = AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC|MEMF_CLEAR);
if (timerinterrupt)
ToClean2(FreeMem, timerinterrupt, sizeof(struct Interrupt));
else
mayPanic("Could not allocate interrupt structure");
timerinterrupt->is_Node.ln_Type = NT_INTERRUPT;
/* timerinterrupt->is_Node.ln_Pri = 0;
*/
timerinterrupt->is_Node.ln_Name = "player";
timerinterrupt->is_Data = play;
timerinterrupt->is_Code = &do_play;
}
LOCAL void open_cia(void)
{
BattMemBase = OpenResource("ciab.resource");
if (!BattMemBase)
mayPanic("Could not open ciab resource");
}
LOCAL void init_interrupt(void)
{
int signal;
set_timerbase();
init_structures();
open_cia();
signal = AllocSignal(-1);
if (signal == -1)
mayPanic("No signals available");
else
ToClean(FreeSignal, signal);
public->signal = 1<<signal;
public->task = FindTask(0L);
}
/* the install timer now puts everything back in the
* state it should be
*/
LOCAL void install_timer(void)
{
int old;
int_clean = AllocClean(NIL);
old = AddICRVector(BattMemBase, CIAICRB_TB, timerinterrupt);
if (!old)
{
ToClean3L(int_clean, RemICRVector, BattMemBase, CIAICRB_TB,
timerinterrupt);
private->control = &(ciab.ciacrb);
private->latchlo = &(ciab.ciatblo);
private->latchhi = &(ciab.ciatbhi);
}
else
{
old = AddICRVector(BattMemBase, CIAICRB_TA, timerinterrupt);
if (!old)
{
ToClean3L(int_clean, RemICRVector, BattMemBase, CIAICRB_TA,
timerinterrupt);
private->control = &(ciab.ciacra);
private->latchlo = &(ciab.ciatalo);
private->latchhi = &(ciab.ciatahi);
}
else
mayPanic("Sorry, no timer available");
}
ToClean0L(int_clean, timer_off);
/* keep the alarm running */
*private->control &= CIACRBF_ALARM;
latch_tempo();
}
struct pub_play *obtain_player()
{
init_interrupt();
return public;
}
void start_timer(void)
{
if (!available)
{
install_timer();
timer_on();
available = TRUE;
}
}
void stop_timer(void)
{
if (available)
{
timer_off();
CleanUp(int_clean);
public->resume = TRUE;
available = FALSE;
}
}
/* ``standard'' frequency is 50Hz.
* tempo is in 256th.
*/
void set_tempo(int tempo, int effect)
{
current_tempo = tempo;
current_effect = effect;
if (available)
latch_tempo();
}
void set_volume(int new_value)
{
public->volume = new_value;
}
void set_mode(int mode)
{
public->mode = mode;
}
void setup_song(struct song *s)
{
Disable();
public->command = STOP;
public->pattern = 0;
public->position = 0;
public->info = s->info;
public->sample = s->samples;
public->resume = FALSE;
Enable();
}
void launch_play(int patt)
{
if (public->info)
{
Disable();
public->command = NEWPOS;
public->pattern = patt;
public->position = 0;
Enable();
}
}