diff options
Diffstat (limited to 'engines/sci/sfx/sfx_iterator.h')
-rw-r--r-- | engines/sci/sfx/sfx_iterator.h | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/engines/sci/sfx/sfx_iterator.h b/engines/sci/sfx/sfx_iterator.h new file mode 100644 index 0000000000..9dc1f3a3b3 --- /dev/null +++ b/engines/sci/sfx/sfx_iterator.h @@ -0,0 +1,350 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* Song iterator declarations */ + +#ifndef _SCI_SFX_ITERATOR_H_ +#define _SCI_SFX_ITERATOR_H_ + +#include "sci/sfx/sfx_pcm.h" + +namespace Sci { + +#define SI_FINISHED -1 /* Song finished playing */ +#define SI_LOOP -2 /* Song just looped */ +#define SI_ABSOLUTE_CUE -3 /* Found a song cue (absolute) */ +#define SI_RELATIVE_CUE -4 /* Found a song cue (relative) */ +#define SI_PCM -5 /* Found a PCM */ +#define SI_IGNORE -6 /* This event got edited out by the remapper */ +#define SI_MORPH -255 /* Song iterator requested self-morph. */ + +#define FADE_ACTION_NONE 0 +#define FADE_ACTION_FADE_AND_STOP 1 +#define FADE_ACTION_FADE_AND_CONT 2 + +typedef struct { + int ticks_per_step; + int final_volume; + int step_size; + int action; +} fade_params_t; + +#define SONG_ITERATOR_MESSAGE_ARGUMENTS_NR 2 + +/* Helper defs for messages */ +/* Base messages */ +#define _SIMSG_BASE 0 /* Any base decoder */ +#define _SIMSG_BASEMSG_SET_LOOPS 0 /* Set loops */ +#define _SIMSG_BASEMSG_CLONE 1 /* Clone object and data. Must provide the +** (possibly negative) number of ticks that have +** passed since the last delay time started being +** used */ +#define _SIMSG_BASEMSG_SET_PLAYMASK 2 /* Set the current playmask for filtering */ +#define _SIMSG_BASEMSG_SET_RHYTHM 3 /* Activate/deactivate rhythm channel */ +#define _SIMSG_BASEMSG_ACK_MORPH 4 /* Acknowledge self-morph */ +#define _SIMSG_BASEMSG_STOP 5 /* Stop iterator */ +#define _SIMSG_BASEMSG_PRINT 6 /* Print self to stderr, after printing param1 tabs */ +#define _SIMSG_BASEMSG_SET_HOLD 7 /* Set value of hold parameter to expect */ +#define _SIMSG_BASEMSG_SET_FADE 8 /* Set fade parameters */ + +/* "Plastic" (discardable) wrapper messages */ +#define _SIMSG_PLASTICWRAP 1 /* Any base decoder */ +#define _SIMSG_PLASTICWRAP_ACK_MORPH 4 /* Acknowledge self-morph */ + +/* Messages */ +#define SIMSG_SET_LOOPS(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_LOOPS,(x),0 +#define SIMSG_SET_PLAYMASK(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_PLAYMASK,(x),0 +#define SIMSG_SET_RHYTHM(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_RHYTHM,(x),0 +#define SIMSG_CLONE(x) _SIMSG_BASE,_SIMSG_BASEMSG_CLONE,(x),0 +#define SIMSG_ACK_MORPH _SIMSG_PLASTICWRAP,_SIMSG_PLASTICWRAP_ACK_MORPH,0,0 +#define SIMSG_STOP _SIMSG_BASE,_SIMSG_BASEMSG_STOP,0,0 +#define SIMSG_PRINT(indentation) _SIMSG_BASE,_SIMSG_BASEMSG_PRINT,(indentation),0 +#define SIMSG_SET_HOLD(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_HOLD,(x),0 +/*#define SIMSG_SET_FADE(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_FADE,(x),0*/ + +/* Message transmission macro: Takes song reference, message reference */ +#define SIMSG_SEND(o, m) songit_handle_message(&(o), songit_make_message((o)->ID, m)) +#define SIMSG_SEND_FADE(o, m) songit_handle_message(&(o), songit_make_ptr_message((o)->ID, _SIMSG_BASE, _SIMSG_BASEMSG_SET_FADE, m, 0)) + +/* Event listener interface */ +struct listener_t { + void (*notify)(void *self, void *notifier); + void *self; +}; + +typedef unsigned long songit_id_t; + +typedef struct { + songit_id_t ID; + unsigned int recipient; /* Type of iterator supposed to receive this */ + unsigned int type; + union { + unsigned int i; + void * p; + } args[SONG_ITERATOR_MESSAGE_ARGUMENTS_NR]; +} song_iterator_message_t; + +#define INHERITS_SONG_ITERATOR \ + songit_id_t ID; \ + guint16 channel_mask; \ + fade_params_t fade; \ + unsigned int flags; \ + int priority; \ + int (*next) (song_iterator_t *self, unsigned char *buf, int *buf_size); \ + sfx_pcm_feed_t * (*get_pcm_feed) (song_iterator_t *s); \ + song_iterator_t * (* handle_message)(song_iterator_t *self, song_iterator_message_t msg); \ + void (*init) (struct _song_iterator *self); \ + void (*cleanup) (struct _song_iterator *self); \ + int (*get_timepos) (struct _song_iterator *self); \ + listener_t death_listeners[SONGIT_MAX_LISTENERS]; \ + int death_listeners_nr \ + +#define SONGIT_MAX_LISTENERS 2 + +typedef struct _song_iterator { + + songit_id_t ID; + guint16 channel_mask; /* Bitmask of all channels this iterator will use */ + fade_params_t fade; + unsigned int flags; + int priority; + + int (*next)(struct _song_iterator *self, + unsigned char *buf, int *result); + /* Reads the next MIDI operation _or_ delta time + ** Parameters: (song_iterator_t *) self + ** (byte *) buf: The buffer to write to (needs to be able to + ** store at least 4 bytes) + ** Returns : (int) zero if a MIDI operation was written, SI_FINISHED + ** if the song has finished playing, SI_LOOP if looping + ** (after updating the loop variable), SI_CUE if we found + ** a cue, SI_PCM if a PCM was found, or the number of ticks + ** to wait before this function should be called next. + ** (int) *result: Number of bytes written to the buffer + ** (equals the number of bytes that need to be passed + ** to the lower layers) for 0, the cue value for SI_CUE, + ** or the number of loops remaining for SI_LOOP. + ** If SI_PCM is returned, get_pcm() may be used to retrieve the associated + ** PCM, but this must be done before any subsequent calls to next(). + */ + + sfx_pcm_feed_t * (*get_pcm_feed)(struct _song_iterator *self); + /* Checks for the presence of a pcm sample + ** Parameters: (song_iterator_t *) self + ** Returns : (sfx_pcm_feed_t *) NULL if no PCM data was found, a + ** PCM feed otherwise + */ + + + struct _song_iterator * + (* handle_message)(struct _song_iterator *self, song_iterator_message_t msg); + /* Handles a message to the song iterator + ** Parameters: (song_iterator_t *) self + ** (song_iterator_messag_t) msg: The message to handle + ** Returns : (song_iterator_t *) NULL if the message was not understood, + ** self if the message could be handled, or a new song iterator + ** if the current iterator had to be morphed (but the message could + ** still be handled) + ** This function is not supposed to be called directly; use + ** songit_handle_message() instead. It should not recurse, since songit_handle_message() + ** takes care of that and makes sure that its delegate received the message (and + ** was morphed) before self. + */ + + + void (*init)(struct _song_iterator *self); + /* Resets/initializes the sound iterator + ** Parameters: (song_iterator_t *) self + ** Returns : (void) + */ + + void (*cleanup)(struct _song_iterator *self); + /* Frees any content of the iterator structure + ** Parameters: (song_iterator_t *) self + ** Does not physically free(self) yet. May be NULL if nothing needs to be done. + ** Must not recurse on its delegate. + */ + + int (*get_timepos)(struct _song_iterator *self); + /* Gets the song position to store in a savegame + ** Parameters: (song_iterator_t *) self + */ + + /* Death listeners */ + /* These are not reset during initialisation */ + listener_t death_listeners[SONGIT_MAX_LISTENERS]; + int death_listeners_nr; + + /* See songit_* for the constructor and non-virtual member functions */ + +} song_iterator_t; + + +/* Song iterator flags */ +#define SONGIT_FLAG_CLONE (1 << 0) /* This flag is set for clones, which are exclusively used in song players. +** Thus, this flag distinguishes song iterators in the main thread from those +** in the song-player thread. */ + +void song_iterator_add_death_listener(song_iterator_t *it, + void *client, + void (*notify)(void *self, void *notifier)); +/* Adds a death listener to a song iterator +** Parameters: (song_iterator_t *) it: The iterator to add to +** (void *) client: The object wanting to be notified +** (void* x void* -> void) notify: The notification function +** to invoke +** Effects: Fatally terminates the program if no listener slots are +** available +** Death listeners are NOT cloned. +*/ + +void song_iterator_remove_death_listener(song_iterator_t *it, + void *client); +/* Removes a death listener from a song iterator +** Parameters: (song_iterator_t *) it: The iterator to modify +** (void *) client: The object no longer wanting to be notified +** Effects: Fatally terminates the program if the listener was not +** found +** Death listeners are NOT cloned. +*/ + +/********************************/ +/*-- Song iterator operations --*/ +/********************************/ + +#define SCI_SONG_ITERATOR_TYPE_SCI0 0 +#define SCI_SONG_ITERATOR_TYPE_SCI1 1 + +#define IT_READER_MASK_MIDI (1 << 0) +#define IT_READER_MASK_DELAY (1 << 1) +#define IT_READER_MASK_LOOP (1 << 2) +#define IT_READER_MASK_CUE (1 << 3) +#define IT_READER_MASK_PCM (1 << 4) +#define IT_READER_MAY_FREE (1 << 10) /* Free SI_FINISHED iterators */ +#define IT_READER_MAY_CLEAN (1 << 11) +/* MAY_CLEAN: May instantiate cleanup iterators +** (use for players; this closes open channels at the end of a song) */ + +#define IT_READER_MASK_ALL ( IT_READER_MASK_MIDI \ + | IT_READER_MASK_DELAY \ + | IT_READER_MASK_LOOP \ + | IT_READER_MASK_CUE \ + | IT_READER_MASK_PCM ) + +int songit_next(song_iterator_t **it, unsigned char *buf, int *result, int mask); +/* Convenience wrapper around it->next +** Parameters: (song_iterator_t **it) Reference to the iterator to access +** (byte *) buf: The buffer to write to (needs to be able to +** store at least 4 bytes) +** (int) mask: IT_READER_MASK options specifying the events to +** listen for +** Returns : (int) zero if a MIDI operation was written, SI_FINISHED +** if the song has finished playing, SI_LOOP if looping +** (after updating the loop variable), SI_CUE if we found +** a cue, SI_PCM if a PCM was found, or the number of ticks +** to wait before this function should be called next. +** (int) *result: Number of bytes written to the buffer +** (equals the number of bytes that need to be passed +** to the lower layers) for 0, the cue value for SI_CUE, +** or the number of loops remaining for SI_LOOP. +*/ + +song_iterator_t *songit_new(unsigned char *data, unsigned int size, int type, songit_id_t id); +/* Constructs a new song iterator object +** Parameters: (byte *) data: The song data to iterate over +** (unsigned int) size: Number of bytes in the song +** (int) type: One of the SCI_SONG_ITERATOR_TYPEs +** (songit_id_t) id: An ID for addressing the song iterator +** Returns : (song_iterator_t *) A newly allocated but uninitialized song +** iterator, or NULL if 'type' was invalid or unsupported +*/ + +song_iterator_t *songit_new_tee(song_iterator_t *left, song_iterator_t *right, int may_destroy); +/* Combines two iterators, returns the next event available from either +** Parameters: (song_iterator_t *) left: One of the iterators +** (song_iterator_t *) right: The other iterator +** (int) may_destroy: Whether completed song iterators may be +** destroyed +** Returns : (song_iterator_t *) A combined iterator, as suggested above +*/ + + +void songit_free(song_iterator_t *it); +/* Frees a song iterator and the song it wraps +** Parameters: (song_iterator_t *) it: The song iterator to free +** Returns : (void) +*/ + +song_iterator_message_t songit_make_message(songit_id_t id, + int recipient_class, int type, int a1, int a2); +/* Create a song iterator message +** Parameters: (songit_id_t) id: song ID the message is targetted to +** (int) recipient_class: Message recipient class +** (int) type: Message type +** (int x int) a1, a2: Arguments +** You should only use this with the SIMSG_* macros +*/ + +song_iterator_message_t songit_make_ptr_message(songit_id_t id, + int recipient_class, int type, void * a1, int a2); +/* Create a song iterator message, wherein the first parameter is a pointer +** Parameters: (songit_id_t) id: song ID the message is targetted to +** (int) recipient_class: Message recipient class +** (int) type: Message type +** (void* x int) a1, a2: Arguments +** You should only use this with the SIMSG_* macros +*/ + +int songit_handle_message(song_iterator_t **it_reg, song_iterator_message_t msg); +/* Handles a message to the song iterator +** Parameters: (song_iterator_t **): A reference to the variable storing the song iterator +** Returns : (int) Non-zero if the message was understood +** The song iterator may polymorph as result of msg, so a writeable reference is required. +*/ + + +song_iterator_t *songit_clone(song_iterator_t *it, int delta); +/* Clones a song iterator +** Parameters: (song_iterator_t *) it: The iterator to clone +** (int) delta: Number of ticks that still need to elapse until +** the next item should be read from the song iterator +** Returns : (song_iterator_t *) A shallow clone of 'it'. +** This performs a clone on the bottom-most part (containing the actual song data) _only_. +** The justification for requiring 'delta' to be passed in here is that this +** is typically maintained outside of the song iterator. +*/ + + +int sfx_play_iterator_pcm(song_iterator_t *it, unsigned long handle); +/* Plays a song iterator that found a PCM through a PCM device, if possible +** Parameters: (song_iterator_t *) it: The iterator to play +** (song_handle_t) handle: Debug handle +** Returns : (int) 0 if the effect will not be played, nonzero if it will +** This assumes that the last call to 'it->next()' returned SI_PCM. +*/ + +} // End of namespace Sci + +#endif |