2009-02-17 15:07:44 +00:00
/* 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 $
*
*/
2009-02-15 06:10:59 +00:00
/* Song iterators */
# include <stdio.h>
2009-02-21 14:11:41 +00:00
# include "common/util.h"
2009-02-15 08:34:13 +00:00
# include "sci/include/sfx_iterator_internal.h"
# include "sci/include/sfx_player.h"
# include "sci/include/resource.h"
# include "sci/include/sci_memory.h"
2009-02-15 06:10:59 +00:00
2009-02-21 10:23:36 +00:00
namespace Sci {
2009-02-15 06:10:59 +00:00
static const int MIDI_cmdlen [ 16 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
2009-02-15 22:34:41 +00:00
2 , 2 , 2 , 2 , 1 , 1 , 2 , 0
} ;
2009-02-15 06:10:59 +00:00
/*#define DEBUG_DECODING*/
/*#define DEBUG_VERBOSE*/
2009-02-21 16:20:53 +00:00
void print_tabs_id ( int nr , songit_id_t id ) {
2009-02-15 06:10:59 +00:00
while ( nr - - > 0 )
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " \t " ) ;
2009-02-15 06:10:59 +00:00
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [%08lx] " , id ) ;
2009-02-15 06:10:59 +00:00
}
# ifndef HAVE_MEMCHR
static void *
2009-02-15 22:34:41 +00:00
memchr ( void * _data , int c , int n ) {
2009-02-15 06:10:59 +00:00
unsigned char * data = ( unsigned char * ) _data ;
while ( n & & ! ( * data = = c ) ) {
+ + data ;
- - n ;
}
if ( n )
return data ;
else
return NULL ;
}
# endif
2009-02-21 16:20:53 +00:00
static void _common_init ( base_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
self - > fade . action = FADE_ACTION_NONE ;
self - > resetflag = 0 ;
self - > loops = 0 ;
self - > priority = 0 ;
}
/************************************/
/*-- SCI0 iterator implementation --*/
/************************************/
# define SCI0_MIDI_OFFSET 33
# define SCI0_END_OF_SONG 0xfc /* proprietary MIDI command */
# define SCI0_PCM_SAMPLE_RATE_OFFSET 0x0e
# define SCI0_PCM_SIZE_OFFSET 0x20
# define SCI0_PCM_DATA_OFFSET 0x2c
# define CHECK_FOR_END_ABSOLUTE(offset) \
if ( offset > self - > size ) { \
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX " Reached end of song without terminator (%x/%x) at %d! \n " , offset , self - > size , __LINE__ ) ; \
2009-02-15 06:10:59 +00:00
return SI_FINISHED ; \
}
# define CHECK_FOR_END(offset_augment) \
if ( ( channel - > offset + ( offset_augment ) ) > channel - > end ) { \
channel - > state = SI_STATE_FINISHED ; \
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX " Reached end of track %d without terminator (%x+%x/%x) at %d! \n " , channel - > id , channel - > offset , offset_augment , channel - > end , __LINE__ ) ; \
2009-02-15 06:10:59 +00:00
return SI_FINISHED ; \
}
2009-02-21 16:20:53 +00:00
static inline int _parse_ticks ( byte * data , int * offset_p , int size ) {
2009-02-15 06:10:59 +00:00
int ticks = 0 ;
int tempticks ;
int offset = 0 ;
do {
tempticks = data [ offset + + ] ;
2009-02-15 22:34:41 +00:00
ticks + = ( tempticks = = SCI_MIDI_TIME_EXPANSION_PREFIX ) ?
SCI_MIDI_TIME_EXPANSION_LENGTH : tempticks ;
2009-02-15 06:10:59 +00:00
} while ( tempticks = = SCI_MIDI_TIME_EXPANSION_PREFIX
2009-02-15 22:34:41 +00:00
& & offset < size ) ;
2009-02-15 06:10:59 +00:00
if ( offset_p )
* offset_p = offset ;
return ticks ;
}
2009-02-21 16:20:53 +00:00
static int _sci0_read_next_command ( sci0_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
unsigned char * buf , int * result ) ;
2009-02-15 06:10:59 +00:00
2009-02-21 16:20:53 +00:00
static int _sci0_get_pcm_data ( sci0_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
sfx_pcm_config_t * format ,
int * xoffset ,
unsigned int * xsize ) ;
2009-02-15 06:10:59 +00:00
# define PARSE_FLAG_LOOPS_UNLIMITED (1 << 0) /* Unlimited # of loops? */
# define PARSE_FLAG_PARAMETRIC_CUE (1 << 1) /* Assume that cues take an additional "cue value" argument */
/* This implements a difference between SCI0 and SCI1 cues. */
2009-02-21 16:20:53 +00:00
void _reset_synth_channels ( base_song_iterator_t * self , song_iterator_channel_t * channel ) {
2009-02-15 06:10:59 +00:00
int i ;
byte buf [ 5 ] ;
tell_synth_func * tell = sfx_get_player_tell_func ( ) ;
2009-02-15 22:34:41 +00:00
for ( i = 0 ; i < MIDI_CHANNELS ; i + + ) {
if ( channel - > saw_notes & ( 1 < < i ) ) {
2009-02-15 06:10:59 +00:00
buf [ 0 ] = 0xe0 | i ; /* Pitch bend */
buf [ 1 ] = 0x80 ; /* Wheel center */
buf [ 2 ] = 0x40 ;
if ( tell )
tell ( 3 , buf ) ;
/* TODO: Reset other controls? */
}
}
}
2009-02-21 16:20:53 +00:00
static int _parse_sci_midi_command ( base_song_iterator_t * self , unsigned char * buf , int * result ,
2009-02-15 22:34:41 +00:00
song_iterator_channel_t * channel ,
int flags ) {
2009-02-15 06:10:59 +00:00
unsigned char cmd ;
int paramsleft ;
int midi_op ;
int midi_channel ;
channel - > state = SI_STATE_DELTA_TIME ;
cmd = self - > data [ channel - > offset + + ] ;
if ( ! ( cmd & 0x80 ) ) {
/* 'Running status' mode */
channel - > offset - - ;
cmd = channel - > last_cmd ;
}
2009-02-15 22:34:41 +00:00
if ( cmd = = 0xfe ) {
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " song iterator subsystem: Corrupted sound resource detected. \n " ) ;
2009-02-15 06:10:59 +00:00
return SI_FINISHED ;
}
midi_op = cmd > > 4 ;
midi_channel = cmd & 0xf ;
paramsleft = MIDI_cmdlen [ midi_op ] ;
channel - > saw_notes | = 1 < < midi_channel ;
#if 0
2009-02-15 22:34:41 +00:00
if ( 1 ) {
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [IT]: off=%x, cmd=%02x, takes %d args " ,
2009-02-15 22:34:41 +00:00
channel - > offset - 1 , cmd , paramsleft ) ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [%02x %02x <%02x> %02x %02x %02x] \n " ,
2009-02-15 22:34:41 +00:00
self - > data [ channel - > offset - 3 ] ,
self - > data [ channel - > offset - 2 ] ,
self - > data [ channel - > offset - 1 ] ,
self - > data [ channel - > offset ] ,
self - > data [ channel - > offset + 1 ] ,
self - > data [ channel - > offset + 2 ] ) ;
}
2009-02-15 06:10:59 +00:00
# endif
buf [ 0 ] = cmd ;
CHECK_FOR_END ( paramsleft ) ;
memcpy ( buf + 1 , self - > data + channel - > offset , paramsleft ) ;
* result = 1 + paramsleft ;
channel - > offset + = paramsleft ;
channel - > last_cmd = cmd ;
/* Are we supposed to play this channel? */
if (
/* First, exclude "global" properties-- such as cues-- from consideration */
2009-02-15 22:34:41 +00:00
( midi_op < 0xf
& & ! ( cmd = = SCI_MIDI_SET_SIGNAL )
& & ! ( SCI_MIDI_CONTROLLER ( cmd )
& & buf [ 1 ] = = SCI_MIDI_CUMULATIVE_CUE ) )
2009-02-15 06:10:59 +00:00
/* Next, check if the channel is allowed */
2009-02-15 22:34:41 +00:00
& & ( ! ( ( 1 < < midi_channel ) & channel - > playmask ) ) )
2009-02-15 06:10:59 +00:00
return /* Execute next command */
2009-02-15 22:34:41 +00:00
self - > next ( ( song_iterator_t * ) self , buf , result ) ;
2009-02-15 06:10:59 +00:00
if ( cmd = = SCI_MIDI_EOT ) {
/* End of track? */
_reset_synth_channels ( self , channel ) ;
2009-02-21 14:11:41 +00:00
/* fprintf(stderr, "eot; loops = %d, notesplayed=%d\n", self->loops, channel->notes_played);*/
2009-02-15 06:10:59 +00:00
if ( self - > loops > 1 /* && channel->notes_played*/ ) {
/* If allowed, decrement the number of loops */
if ( ! ( flags & PARSE_FLAG_LOOPS_UNLIMITED ) )
* result = - - self - > loops ;
# ifdef DEBUG_DECODING
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " %s L%d: (%p):%d Looping " , __FILE__ , __LINE__ , self , channel - > id ) ;
2009-02-15 06:10:59 +00:00
if ( flags & PARSE_FLAG_LOOPS_UNLIMITED )
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " (indef.) " ) ;
2009-02-15 06:10:59 +00:00
else
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " (%d) " , self - > loops ) ;
fprintf ( stderr , " %x -> %x \n " ,
2009-02-15 22:34:41 +00:00
channel - > offset , channel - > loop_offset ) ;
2009-02-15 06:10:59 +00:00
# endif
channel - > offset = channel - > loop_offset ;
channel - > notes_played = 0 ;
channel - > state = SI_STATE_DELTA_TIME ;
channel - > total_timepos = channel - > loop_timepos ;
channel - > last_cmd = 0xfe ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " Looping song iterator %08lx. \n " , self - > ID ) ;
2009-02-15 06:10:59 +00:00
return SI_LOOP ;
} else {
channel - > state = SI_STATE_FINISHED ;
# ifdef DEBUG_DECODING
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " %s L%d: (%p):%d EOT because "
2009-02-15 22:34:41 +00:00
" %d notes, %d loops \n " ,
__FILE__ , __LINE__ , self , channel - > id ,
channel - > notes_played , self - > loops ) ;
2009-02-15 06:10:59 +00:00
# endif
return SI_FINISHED ;
}
} else if ( cmd = = SCI_MIDI_SET_SIGNAL ) {
if ( buf [ 1 ] = = SCI_MIDI_SET_SIGNAL_LOOP ) {
channel - > loop_offset = channel - > offset ;
channel - > loop_timepos = channel - > total_timepos ;
return /* Execute next command */
2009-02-15 22:34:41 +00:00
self - > next ( ( song_iterator_t * ) self , buf , result ) ;
2009-02-15 06:10:59 +00:00
} else {
/* Used to be conditional <= 127 */
* result = buf [ 1 ] ; /* Absolute cue */
return SI_ABSOLUTE_CUE ;
}
} else if ( SCI_MIDI_CONTROLLER ( cmd ) ) {
switch ( buf [ 1 ] ) {
case SCI_MIDI_CUMULATIVE_CUE :
if ( flags & PARSE_FLAG_PARAMETRIC_CUE )
self - > ccc + = buf [ 2 ] ;
else { /* No parameter to CC */
self - > ccc + + ;
2009-02-15 22:34:41 +00:00
/* channel->offset--; */
2009-02-15 06:10:59 +00:00
}
* result = self - > ccc ;
return SI_RELATIVE_CUE ;
case SCI_MIDI_RESET_ON_SUSPEND :
self - > resetflag = buf [ 2 ] ;
break ;
case SCI_MIDI_SET_POLYPHONY :
self - > polyphony [ midi_channel ] = buf [ 2 ] ;
#if 0
{
2009-02-15 22:34:41 +00:00
int i ;
int voices = 0 ;
for ( i = 0 ; i < ( ( sci1_song_iterator_t * ) self ) - > channels_nr ; i + + ) {
voices + = self - > polyphony [ i ] ;
}
sciprintf ( " SET_POLYPHONY(%d, %d) for a total of %d voices \n " , midi_channel , buf [ 2 ] , voices ) ;
sciprintf ( " [iterator-1] DEBUG: Polyphony = [ " ) ;
for ( i = 0 ; i < ( ( sci1_song_iterator_t * ) self ) - > channels_nr ; i + + )
sciprintf ( " %d " , self - > polyphony [ i ] ) ;
sciprintf ( " ] \n " ) ;
sciprintf ( " [iterator-1] DEBUG: Importance = [ " ) ;
for ( i = 0 ; i < ( ( sci1_song_iterator_t * ) self ) - > channels_nr ; i + + )
sciprintf ( " %d " , self - > importance [ i ] ) ;
sciprintf ( " ] \n " ) ;
2009-02-15 06:10:59 +00:00
}
# endif
break ;
case SCI_MIDI_SET_REVERB :
break ;
case SCI_MIDI_CHANNEL_MUTE :
sciprintf ( " CHANNEL_MUTE(%d, %d) \n " , midi_channel , buf [ 2 ] ) ;
break ;
2009-02-15 22:34:41 +00:00
case SCI_MIDI_HOLD : {
2009-02-15 06:10:59 +00:00
// Safe cast: This controller is only used in SCI1
sci1_song_iterator_t * self1 = ( sci1_song_iterator_t * ) self ;
2009-02-15 22:34:41 +00:00
if ( buf [ 2 ] = = self1 - > hold ) {
2009-02-15 06:10:59 +00:00
channel - > offset = channel - > initial_offset ;
channel - > notes_played = 0 ;
channel - > state = SI_STATE_COMMAND ;
channel - > total_timepos = 0 ;
2009-02-15 22:34:41 +00:00
self1 - > channels_looped = self1 - > active_channels - 1 ;
2009-02-15 06:10:59 +00:00
return SI_LOOP ;
}
break ;
}
case 0x04 : /* UNKNOWN NYI (happens in LSL2 gameshow) */
case 0x46 : /* UNKNOWN NYI (happens in LSL3 binoculars) */
case 0x61 : /* UNKNOWN NYI (special for adlib? Iceman) */
case 0x73 : /* UNKNOWN NYI (happens in Hoyle) */
case 0xd1 : /* UNKNOWN NYI (happens in KQ4 when riding the unicorn) */
return /* Execute next command */
2009-02-15 22:34:41 +00:00
self - > next ( ( song_iterator_t * ) self , buf , result ) ;
2009-02-15 06:10:59 +00:00
case 0x01 : /* modulation */
case 0x07 : /* volume */
case 0x0a : /* panpot */
case 0x0b : /* expression */
case 0x40 : /* hold */
case 0x79 : /* reset all */
/* No special treatment neccessary */
break ;
}
return 0 ;
} else {
if ( ( cmd & 0xf0 ) = = 0x90 ) /* note on? */
channel - > notes_played + + ;
/* Process as normal MIDI operation */
return 0 ;
}
}
2009-02-21 16:20:53 +00:00
static int _sci_midi_process_state ( base_song_iterator_t * self , unsigned char * buf , int * result ,
2009-02-15 22:34:41 +00:00
song_iterator_channel_t * channel ,
int flags ) {
2009-02-15 06:10:59 +00:00
CHECK_FOR_END ( 0 ) ;
switch ( channel - > state ) {
case SI_STATE_PCM : {
if ( * ( self - > data + channel - > offset ) = = 0
2009-02-15 22:34:41 +00:00
& & * ( self - > data + channel - > offset + 1 ) = = SCI_MIDI_EOT )
2009-02-15 06:10:59 +00:00
/* Fake one extra tick to trick the interpreter into not killing the song iterator right away */
channel - > state = SI_STATE_PCM_MAGIC_DELTA ;
else
channel - > state = SI_STATE_DELTA_TIME ;
return SI_PCM ;
}
case SI_STATE_PCM_MAGIC_DELTA : {
sfx_pcm_config_t format ;
int offset ;
unsigned int size ;
int delay ;
if ( _sci0_get_pcm_data ( ( sci0_song_iterator_t * ) self , & format , & offset , & size ) )
return SI_FINISHED ; /* 'tis broken */
channel - > state = SI_STATE_FINISHED ;
delay = ( size * 50 + format . rate - 1 ) / format . rate ; /* number of ticks to completion*/
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " delaying %d ticks \n " , delay ) ;
2009-02-15 06:10:59 +00:00
return delay ;
}
case SI_STATE_UNINITIALISED :
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX " Attempt to read command from uninitialized iterator! \n " ) ;
2009-02-15 06:10:59 +00:00
self - > init ( ( song_iterator_t * ) self ) ;
return self - > next ( ( song_iterator_t * ) self , buf , result ) ;
case SI_STATE_FINISHED :
return SI_FINISHED ;
case SI_STATE_DELTA_TIME : {
int offset ;
int ticks = _parse_ticks ( self - > data + channel - > offset ,
2009-02-15 22:34:41 +00:00
& offset ,
self - > size - channel - > offset ) ;
2009-02-15 06:10:59 +00:00
channel - > offset + = offset ;
channel - > delay + = ticks ;
channel - > timepos_increment = ticks ;
CHECK_FOR_END ( 0 ) ;
channel - > state = SI_STATE_COMMAND ;
if ( ticks )
return ticks ;
}
2009-02-15 22:34:41 +00:00
/* continute otherwise... */
2009-02-15 06:10:59 +00:00
case SI_STATE_COMMAND : {
int retval ;
channel - > total_timepos + = channel - > timepos_increment ;
channel - > timepos_increment = 0 ;
retval = _parse_sci_midi_command ( self , buf , result ,
2009-02-15 22:34:41 +00:00
channel , flags ) ;
2009-02-15 06:10:59 +00:00
if ( retval = = SI_FINISHED ) {
if ( self - > active_channels )
- - ( self - > active_channels ) ;
# ifdef DEBUG_DECODING
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " %s L%d: (%p):%d Finished channel, %d channels left \n " ,
2009-02-15 22:34:41 +00:00
__FILE__ , __LINE__ , self , channel - > id ,
self - > active_channels ) ;
2009-02-15 06:10:59 +00:00
# endif
/* If we still have channels left... */
if ( self - > active_channels ) {
return self - > next ( ( song_iterator_t * ) self , buf , result ) ;
}
/* Otherwise, we have reached the end */
self - > loops = 0 ;
}
return retval ;
}
default :
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX " Invalid iterator state %d! \n " ,
2009-02-15 22:34:41 +00:00
channel - > state ) ;
2009-02-15 06:10:59 +00:00
BREAKPOINT ( ) ;
return SI_FINISHED ;
}
}
2009-02-21 16:20:53 +00:00
static inline int _sci_midi_process ( base_song_iterator_t * self , unsigned char * buf , int * result ,
song_iterator_channel_t * channel , int flags ) {
2009-02-15 06:10:59 +00:00
return _sci_midi_process_state ( self , buf , result ,
2009-02-15 22:34:41 +00:00
channel ,
flags ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
static int _sci0_read_next_command ( sci0_song_iterator_t * self , unsigned char * buf , int * result ) {
2009-02-15 06:10:59 +00:00
return _sci_midi_process ( ( base_song_iterator_t * ) self , buf , result ,
2009-02-15 22:34:41 +00:00
& ( self - > channel ) ,
PARSE_FLAG_PARAMETRIC_CUE ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
static inline int _sci0_header_magic_p ( unsigned char * data , int offset , int size ) {
2009-02-15 06:10:59 +00:00
if ( offset + 0x10 > size )
return 0 ;
return
2009-02-15 22:34:41 +00:00
( data [ offset ] = = 0x1a )
& & ( data [ offset + 1 ] = = 0x00 )
& & ( data [ offset + 2 ] = = 0x01 )
& & ( data [ offset + 3 ] = = 0x00 ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
static int _sci0_get_pcm_data ( sci0_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
sfx_pcm_config_t * format ,
int * xoffset ,
unsigned int * xsize ) {
2009-02-15 06:10:59 +00:00
int tries = 2 ;
int found_it = 0 ;
unsigned char * pcm_data ;
int size ;
unsigned int offset = SCI0_MIDI_OFFSET ;
if ( self - > data [ 0 ] ! = 2 )
return 1 ;
/* No such luck */
while ( ( tries - - ) & & ( offset < self - > size ) & & ( ! found_it ) ) {
/* Search through the garbage manually */
unsigned char * fc = ( unsigned char * ) memchr ( self - > data + offset ,
2009-02-15 22:34:41 +00:00
SCI0_END_OF_SONG ,
self - > size - offset ) ;
2009-02-15 06:10:59 +00:00
if ( ! fc ) {
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX " Warning: Playing unterminated "
" song! \n " ) ;
2009-02-15 06:10:59 +00:00
return 1 ;
}
/* add one to move it past the END_OF_SONG marker */
offset = fc - self - > data + 1 ;
if ( _sci0_header_magic_p ( self - > data , offset , self - > size ) )
found_it = 1 ;
}
if ( ! found_it ) {
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX
2009-02-15 22:34:41 +00:00
" Warning: Song indicates presence of PCM, but "
" none found (finally at offset %04x) \n " , offset ) ;
2009-02-15 06:10:59 +00:00
return 1 ;
}
pcm_data = self - > data + offset ;
size = getUInt16 ( pcm_data + SCI0_PCM_SIZE_OFFSET ) ;
/* Two of the format parameters are fixed by design: */
format - > format = SFX_PCM_FORMAT_U8 ;
format - > stereo = SFX_PCM_MONO ;
format - > rate = getUInt16 ( pcm_data + SCI0_PCM_SAMPLE_RATE_OFFSET ) ;
if ( offset + SCI0_PCM_DATA_OFFSET + size ! = self - > size ) {
int d = offset + SCI0_PCM_DATA_OFFSET + size - self - > size ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX
2009-02-15 22:34:41 +00:00
" Warning: PCM advertizes %d bytes of data, but %d "
2009-02-21 14:11:41 +00:00
" bytes are trailing in the resource! \n " ,
2009-02-15 22:34:41 +00:00
size , self - > size - ( offset + SCI0_PCM_DATA_OFFSET ) ) ;
2009-02-15 06:10:59 +00:00
if ( d > 0 )
size - = d ; /* Fix this */
}
* xoffset = offset ;
* xsize = size ;
return 0 ;
2009-02-15 22:34:41 +00:00
}
2009-02-15 06:10:59 +00:00
2009-02-21 16:20:53 +00:00
static sfx_pcm_feed_t * _sci0_check_pcm ( sci0_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
sfx_pcm_config_t format ;
int offset ;
unsigned int size ;
if ( _sci0_get_pcm_data ( self , & format , & offset , & size ) )
return NULL ;
self - > channel . state
2009-02-15 22:34:41 +00:00
= SI_STATE_FINISHED ; /* Don't play both PCM and music */
2009-02-15 06:10:59 +00:00
return sfx_iterator_make_feed ( self - > data ,
2009-02-15 22:34:41 +00:00
offset + SCI0_PCM_DATA_OFFSET ,
size ,
format ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
static song_iterator_t * _sci0_handle_message ( sci0_song_iterator_t * self , song_iterator_message_t msg ) {
2009-02-15 06:10:59 +00:00
if ( msg . recipient = = _SIMSG_BASE ) {
switch ( msg . type ) {
case _SIMSG_BASEMSG_PRINT :
print_tabs_id ( msg . args [ 0 ] . i , self - > ID ) ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " SCI0: dev=%d, active-chan=%d, size=%d, loops=%d \n " ,
2009-02-15 22:34:41 +00:00
self - > device_id , self - > active_channels , self - > size ,
self - > loops ) ;
2009-02-15 06:10:59 +00:00
break ;
case _SIMSG_BASEMSG_SET_LOOPS :
self - > loops = msg . args [ 0 ] . i ;
break ;
case _SIMSG_BASEMSG_CLONE : {
int tsize = sizeof ( sci0_song_iterator_t ) ;
base_song_iterator_t * mem = ( base_song_iterator_t * ) sci_malloc ( tsize ) ;
memcpy ( mem , self , tsize ) ;
sci_refcount_incref ( mem - > data ) ;
# ifdef DEBUG_VERBOSE
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " ** CLONE INCREF for new %p from %p at %p \n " , mem , self , mem - > data ) ;
2009-02-15 06:10:59 +00:00
# endif
return ( struct _song_iterator * ) mem ; /* Assume caller has another copy of this */
}
case _SIMSG_BASEMSG_STOP : {
songit_id_t sought_id = msg . ID ;
if ( sought_id = = self - > ID )
self - > channel . state = SI_STATE_FINISHED ;
break ;
}
case _SIMSG_BASEMSG_SET_PLAYMASK : {
int i ;
self - > device_id = msg . args [ 0 ] . i ;
/* Set all but the rhytm channel mask bits */
self - > channel . playmask & = ~ ( 1 < < MIDI_RHYTHM_CHANNEL ) ;
for ( i = 0 ; i < MIDI_CHANNELS ; i + + )
if ( self - > data [ 2 + ( i < < 1 ) ] & self - > device_id
2009-02-15 22:34:41 +00:00
& & i ! = MIDI_RHYTHM_CHANNEL )
2009-02-15 06:10:59 +00:00
self - > channel . playmask | = ( 1 < < i ) ;
}
2009-02-15 22:34:41 +00:00
break ;
2009-02-15 06:10:59 +00:00
case _SIMSG_BASEMSG_SET_RHYTHM :
self - > channel . playmask & = ~ ( 1 < < MIDI_RHYTHM_CHANNEL ) ;
if ( msg . args [ 0 ] . i )
self - > channel . playmask | = ( 1 < < MIDI_RHYTHM_CHANNEL ) ;
break ;
2009-02-15 22:34:41 +00:00
case _SIMSG_BASEMSG_SET_FADE : {
2009-02-15 06:10:59 +00:00
fade_params_t * fp = ( fade_params_t * ) msg . args [ 0 ] . p ;
self - > fade . action = fp - > action ;
self - > fade . final_volume = fp - > final_volume ;
self - > fade . ticks_per_step = fp - > ticks_per_step ;
self - > fade . step_size = fp - > step_size ;
break ;
}
default :
return NULL ;
}
return ( song_iterator_t * ) self ;
}
return NULL ;
}
2009-02-21 16:20:53 +00:00
static int _sci0_get_timepos ( sci0_song_iterator_t * self ) {
2009-02-15 22:34:41 +00:00
return self - > channel . total_timepos ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
static void _base_init_channel ( song_iterator_channel_t * channel , int id , int offset ,
2009-02-15 22:34:41 +00:00
int end ) {
2009-02-15 06:10:59 +00:00
channel - > playmask = PLAYMASK_NONE ; /* Disable all channels */
channel - > id = id ;
channel - > notes_played = 0 ;
channel - > state = SI_STATE_DELTA_TIME ;
channel - > loop_timepos = 0 ;
channel - > total_timepos = 0 ;
channel - > timepos_increment = 0 ;
channel - > delay = 0 ; /* Only used for more than one channel */
channel - > last_cmd = 0xfe ;
channel - > offset
2009-02-15 22:34:41 +00:00
= channel - > loop_offset
= channel - > initial_offset
= offset ;
2009-02-15 06:10:59 +00:00
channel - > end = end ;
channel - > saw_notes = 0 ;
}
2009-02-21 16:20:53 +00:00
static void _sci0_init ( sci0_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
_common_init ( ( base_song_iterator_t * ) self ) ;
self - > ccc = 0 ; /* Reset cumulative cue counter */
self - > active_channels = 1 ;
_base_init_channel ( & ( self - > channel ) , 0 , SCI0_MIDI_OFFSET , self - > size ) ;
2009-02-15 22:34:41 +00:00
_reset_synth_channels ( ( base_song_iterator_t * ) self ,
& ( self - > channel ) ) ;
2009-02-15 06:10:59 +00:00
self - > delay_remaining = 0 ;
if ( self - > data [ 0 ] = = 2 ) /* Do we have an embedded PCM? */
self - > channel . state = SI_STATE_PCM ;
}
2009-02-21 16:20:53 +00:00
static void _sci0_cleanup ( sci0_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
# ifdef DEBUG_VERBOSE
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " ** FREEING it %p: data at %p \n " , self , self - > data ) ;
2009-02-15 06:10:59 +00:00
# endif
if ( self - > data )
sci_refcount_decref ( self - > data ) ;
self - > data = NULL ;
}
/***************************/
/*-- SCI1 song iterators --*/
/***************************/
# define SCI01_INVALID_DEVICE 0xff
/* First index determines whether DSP output is supported */
static int sci0_to_sci1_device_map [ ] [ 2 ] = {
{ 0x06 , 0x0c } , /* MT-32 */
{ 0xff , 0xff } , /* YM FB-01 */
{ 0x00 , 0x00 } , /* CMS/Game Blaster-- we assume OPL/2 here... */
{ 0xff , 0xff } , /* Casio MT540/CT460 */
{ 0x13 , 0x13 } , /* Tandy 3-voice */
{ 0x12 , 0x12 } , /* PC speaker */
{ 0xff , 0xff } ,
{ 0xff , 0xff } ,
} ; /* Maps bit number to device ID */
# define SONGDATA(x) self->data[offset + (x)]
# define SCI1_CHANDATA(off) self->data[channel->offset + (off)]
2009-02-21 16:20:53 +00:00
static int _sci1_sample_init ( sci1_song_iterator_t * self , int offset ) {
2009-02-15 06:10:59 +00:00
sci1_sample_t * sample , * * seekerp ;
int rate ;
int length ;
int begin ;
int end ;
2009-02-15 16:45:39 +00:00
CHECK_FOR_END_ABSOLUTE ( ( unsigned int ) offset + 10 ) ;
2009-02-15 06:10:59 +00:00
if ( self - > data [ offset + 1 ] ! = 0 )
sciprintf ( " [iterator-1] In sample at offset 0x04x: Byte #1 is %02x instead of zero \n " ,
2009-02-15 22:34:41 +00:00
self - > data [ offset + 1 ] ) ;
2009-02-15 06:10:59 +00:00
rate = getInt16 ( self - > data + offset + 2 ) ;
length = getUInt16 ( self - > data + offset + 4 ) ;
begin = getInt16 ( self - > data + offset + 6 ) ;
end = getInt16 ( self - > data + offset + 8 ) ;
2009-02-15 16:45:39 +00:00
CHECK_FOR_END_ABSOLUTE ( ( unsigned int ) ( offset + 10 + length ) ) ;
2009-02-15 06:10:59 +00:00
sample = ( sci1_sample_t * ) sci_malloc ( sizeof ( sci1_sample_t ) ) ;
sample - > delta = begin ;
sample - > size = length ;
sample - > data = self - > data + offset + 10 ;
# ifdef DEBUG_VERBOSE
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [SAMPLE] %x/%x/%x/%x l=%x \n " ,
2009-02-15 22:34:41 +00:00
offset + 10 , begin , end , self - > size , length ) ;
2009-02-15 06:10:59 +00:00
# endif
sample - > format . format = SFX_PCM_FORMAT_U8 ;
sample - > format . stereo = SFX_PCM_MONO ;
sample - > format . rate = rate ;
sample - > announced = 0 ;
/* Perform insertion sort */
seekerp = & ( self - > next_sample ) ;
while ( * seekerp & & ( * seekerp ) - > delta < begin )
seekerp = & ( ( * seekerp ) - > next ) ;
sample - > next = * seekerp ;
* seekerp = sample ;
return 0 ; /* Everything's fine */
}
2009-02-21 16:20:53 +00:00
static int _sci1_song_init ( sci1_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
sci1_sample_t * seeker ;
int last_time ;
2009-02-15 14:26:33 +00:00
unsigned int offset = 0 ;
2009-02-15 06:10:59 +00:00
self - > channels_nr = 0 ;
self - > next_sample = 0 ;
// self->device_id = 0x0c;
2009-02-15 22:34:41 +00:00
if ( SONGDATA ( 0 ) = = 0xf0 ) {
2009-02-15 06:10:59 +00:00
self - > priority = SONGDATA ( 1 ) ;
offset + = 8 ;
}
while ( SONGDATA ( 0 ) ! = 0xff
2009-02-15 22:34:41 +00:00
& & SONGDATA ( 0 ) ! = self - > device_id ) {
2009-02-15 06:10:59 +00:00
offset + + ;
CHECK_FOR_END_ABSOLUTE ( offset + 1 ) ;
while ( SONGDATA ( 0 ) ! = 0xff ) {
CHECK_FOR_END_ABSOLUTE ( offset + 7 ) ;
offset + = 6 ;
}
offset + + ;
}
if ( SONGDATA ( 0 ) = = 0xff ) {
sciprintf ( " [iterator-1] Song does not support "
2009-02-15 22:34:41 +00:00
" hardware 0x%02x \n " ,
self - > device_id ) ;
2009-02-15 06:10:59 +00:00
return 1 ;
}
offset + + ;
while ( SONGDATA ( 0 ) ! = 0xff ) { /* End of list? */
2009-02-15 10:29:34 +00:00
unsigned int track_offset ;
2009-02-15 06:10:59 +00:00
int end ;
offset + = 2 ;
CHECK_FOR_END_ABSOLUTE ( offset + 4 ) ;
track_offset = getUInt16 ( self - > data + offset ) ;
end = getUInt16 ( self - > data + offset + 2 ) ;
CHECK_FOR_END_ABSOLUTE ( track_offset - 1 ) ;
if ( self - > data [ track_offset ] = = 0xfe ) {
if ( _sci1_sample_init ( self , track_offset ) )
return 1 ; /* Error */
} else {
/* Regular MIDI channel */
if ( self - > channels_nr > = MIDI_CHANNELS ) {
sciprintf ( " [iterator-1] Warning: Song has more than %d channels, cutting them off \n " ,
2009-02-15 22:34:41 +00:00
MIDI_CHANNELS ) ;
2009-02-15 06:10:59 +00:00
break ; /* Scan for remaining samples */
} else {
int channel_nr
2009-02-15 22:34:41 +00:00
= self - > data [ track_offset ] & 0xf ;
2009-02-15 06:10:59 +00:00
song_iterator_channel_t * channel =
2009-02-15 22:34:41 +00:00
& ( self - > channels [ self - > channels_nr + + ] ) ;
2009-02-15 06:10:59 +00:00
if ( self - > data [ track_offset ] & 0xf0 )
2009-02-15 22:34:41 +00:00
printf ( " Channel %d has mapping bits %02x \n " ,
2009-02-15 06:10:59 +00:00
channel_nr , self - > data [ track_offset ] & 0xf0 ) ;
_base_init_channel ( channel ,
2009-02-15 22:34:41 +00:00
channel_nr ,
/* Skip over header bytes: */
track_offset + 2 ,
track_offset + end ) ;
_reset_synth_channels ( ( base_song_iterator_t * ) self ,
channel ) ;
2009-02-15 06:10:59 +00:00
self - > polyphony [ self - > channels_nr - 1 ]
2009-02-15 22:34:41 +00:00
= SCI1_CHANDATA ( - 1 ) ;
self - > importance [ self - > channels_nr - 1 ]
= self - > polyphony [ self - > channels_nr - 1 ] > > 4 ;
2009-02-15 06:10:59 +00:00
self - > polyphony [ self - > channels_nr - 1 ] & = 15 ;
2009-02-15 22:34:41 +00:00
2009-02-15 06:10:59 +00:00
channel - > playmask = ~ 0 ; /* Enable all */
self - > channel_mask | = ( 1 < < channel_nr ) ;
CHECK_FOR_END_ABSOLUTE ( offset + end ) ;
}
}
offset + = 4 ;
CHECK_FOR_END_ABSOLUTE ( offset ) ;
}
/* Now ensure that sapmle deltas are relative to the previous sample */
seeker = self - > next_sample ;
last_time = 0 ;
self - > active_channels = self - > channels_nr ;
self - > channels_looped = 0 ;
while ( seeker ) {
int prev_last_time = last_time ;
sciprintf ( " [iterator-1] Detected sample: %d Hz, %d bytes at time %d \n " ,
2009-02-15 22:34:41 +00:00
seeker - > format . rate , seeker - > size , seeker - > delta ) ;
2009-02-15 06:10:59 +00:00
last_time = seeker - > delta ;
seeker - > delta - = prev_last_time ;
seeker = seeker - > next ;
}
return 0 ; /* Success */
}
# undef SONGDATA
2009-02-21 16:20:53 +00:00
static inline int _sci1_get_smallest_delta ( sci1_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
int i , d = - 1 ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( self - > channels [ i ] . state = = SI_STATE_COMMAND
2009-02-15 22:34:41 +00:00
& & ( d = = - 1 | | self - > channels [ i ] . delay < d ) )
2009-02-15 06:10:59 +00:00
d = self - > channels [ i ] . delay ;
if ( self - > next_sample & & self - > next_sample - > delta < d )
return self - > next_sample - > delta ;
else
return d ;
}
2009-02-21 16:20:53 +00:00
static inline void _sci1_update_delta ( sci1_song_iterator_t * self , int delta ) {
2009-02-15 06:10:59 +00:00
int i ;
if ( self - > next_sample )
self - > next_sample - > delta - = delta ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( self - > channels [ i ] . state = = SI_STATE_COMMAND )
self - > channels [ i ] . delay - = delta ;
}
2009-02-21 16:20:53 +00:00
static inline int _sci1_no_delta_time ( sci1_song_iterator_t * self ) { /* Checks that none of the channels is waiting for its delta to be read */
2009-02-15 06:10:59 +00:00
int i ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( self - > channels [ i ] . state = = SI_STATE_DELTA_TIME )
2009-02-15 22:34:41 +00:00
return 0 ;
2009-02-15 06:10:59 +00:00
return 1 ;
}
2009-02-15 14:26:33 +00:00
#if 0
// Unreferenced - removed
2009-02-21 16:20:53 +00:00
static void _sci1_dump_state ( sci1_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
int i ;
sciprintf ( " -- [%p] ------------------------ \n " , self ) ;
for ( i = 0 ; i < self - > channels_nr ; i + + ) {
int j ;
sciprintf ( " %d(s%02d): d-%d: \t (%x/%x) " ,
2009-02-15 22:34:41 +00:00
self - > channels [ i ] . id ,
self - > channels [ i ] . state ,
self - > channels [ i ] . delay ,
self - > channels [ i ] . offset ,
self - > channels [ i ] . end ) ;
2009-02-15 06:10:59 +00:00
for ( j = - 3 ; j < 9 ; j + + ) {
if ( j = = 0 )
sciprintf ( " > " ) ;
else
sciprintf ( " " ) ;
2009-02-15 22:34:41 +00:00
sciprintf ( " %02x " , self - > data [ self - > channels [ i ] . offset + j ] ) ;
2009-02-15 06:10:59 +00:00
if ( j = = 0 )
sciprintf ( " < " ) ;
else
sciprintf ( " " ) ;
}
sciprintf ( " \n " ) ;
}
if ( self - > next_sample ) {
sciprintf ( " \t [sample %d] \n " ,
2009-02-15 22:34:41 +00:00
self - > next_sample - > delta ) ;
2009-02-15 06:10:59 +00:00
}
sciprintf ( " ------------------------------------------ \n " ) ;
}
2009-02-15 14:26:33 +00:00
# endif
2009-02-15 06:10:59 +00:00
# define COMMAND_INDEX_NONE -1
# define COMMAND_INDEX_PCM -2
2009-02-21 16:20:53 +00:00
static inline int _sci1_command_index ( sci1_song_iterator_t * self ) {
/* Determine the channel # of the next active event, or -1 */
2009-02-15 06:10:59 +00:00
int i ;
int base_delay = 0x7ffffff ;
int best_chan = COMMAND_INDEX_NONE ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( ( self - > channels [ i ] . state ! = SI_STATE_PENDING )
2009-02-15 22:34:41 +00:00
& & ( self - > channels [ i ] . state ! = SI_STATE_FINISHED ) ) {
2009-02-15 06:10:59 +00:00
if ( ( self - > channels [ i ] . state = = SI_STATE_DELTA_TIME )
2009-02-15 22:34:41 +00:00
& & ( self - > channels [ i ] . delay = = 0 ) )
2009-02-15 06:10:59 +00:00
return i ;
/* First, read all unknown delta times */
if ( self - > channels [ i ] . delay < base_delay ) {
best_chan = i ;
base_delay = self - > channels [ i ] . delay ;
}
}
if ( self - > next_sample & & base_delay > = self - > next_sample - > delta )
return COMMAND_INDEX_PCM ;
return best_chan ;
}
2009-02-21 16:20:53 +00:00
static sfx_pcm_feed_t * _sci1_get_pcm ( sci1_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
if ( self - > next_sample
2009-02-15 22:34:41 +00:00
& & self - > next_sample - > delta < = 0 ) {
2009-02-15 06:10:59 +00:00
sci1_sample_t * sample = self - > next_sample ;
sfx_pcm_feed_t * feed
2009-02-15 22:34:41 +00:00
= sfx_iterator_make_feed ( self - > data ,
sample - > data - self - > data ,
sample - > size ,
sample - > format ) ;
2009-02-15 06:10:59 +00:00
self - > next_sample = self - > next_sample - > next ;
2009-02-17 13:51:52 +00:00
free ( sample ) ;
2009-02-15 06:10:59 +00:00
return feed ;
} else
return NULL ;
}
2009-02-21 16:20:53 +00:00
static int _sci1_process_next_command ( sci1_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
unsigned char * buf , int * result ) {
2009-02-15 06:10:59 +00:00
int retval = - 42 ; /* Shouldn't happen, but gcc doesn't agree */
int chan ;
if ( ! self - > initialised ) {
sciprintf ( " [iterator-1] DEBUG: Initialising for %d \n " ,
2009-02-15 22:34:41 +00:00
self - > device_id ) ;
2009-02-15 06:10:59 +00:00
self - > initialised = 1 ;
if ( _sci1_song_init ( self ) )
return SI_FINISHED ;
}
if ( self - > delay_remaining ) {
int delay = self - > delay_remaining ;
self - > delay_remaining = 0 ;
return delay ;
}
do {
chan = _sci1_command_index ( self ) ;
if ( chan = = COMMAND_INDEX_NONE ) {
return SI_FINISHED ;
}
if ( chan = = COMMAND_INDEX_PCM ) {
if ( self - > next_sample - > announced ) {
/* Already announced; let's discard it */
sfx_pcm_feed_t * feed
2009-02-15 22:34:41 +00:00
= _sci1_get_pcm ( self ) ;
2009-02-15 06:10:59 +00:00
feed - > destroy ( feed ) ;
} else {
int delay = self - > next_sample - > delta ;
if ( delay ) {
_sci1_update_delta ( self , delay ) ;
return delay ;
}
/* otherwise we're touching a PCM */
self - > next_sample - > announced = 1 ;
return SI_PCM ;
}
} else { /* Not a PCM */
2009-02-15 22:34:41 +00:00
retval = _sci_midi_process ( ( base_song_iterator_t * ) self ,
buf , result ,
& ( self - > channels [ chan ] ) ,
PARSE_FLAG_LOOPS_UNLIMITED ) ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
if ( retval = = SI_LOOP ) {
self - > channels_looped + + ;
self - > channels [ chan ] . state = SI_STATE_PENDING ;
self - > channels [ chan ] . delay = 0 ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
if ( self - > channels_looped = = self - > active_channels ) {
int i ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
/* Everyone's ready: Let's loop */
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( self - > channels [ i ] . state
= = SI_STATE_PENDING )
self - > channels [ i ] . state
2009-02-15 06:10:59 +00:00
= SI_STATE_DELTA_TIME ;
2009-02-15 22:34:41 +00:00
self - > channels_looped = 0 ;
return SI_LOOP ;
}
} else if ( retval = = SI_FINISHED ) {
2009-02-15 06:10:59 +00:00
# ifdef DEBUG
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " FINISHED some channel \n " ) ;
2009-02-15 06:10:59 +00:00
# endif
2009-02-15 22:34:41 +00:00
} else if ( retval > 0 ) {
int sd ;
sd = _sci1_get_smallest_delta ( self ) ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
if ( _sci1_no_delta_time ( self ) & & sd ) {
/* No other channel is ready */
_sci1_update_delta ( self , sd ) ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
/* Only from here do we return delta times */
return sd ;
}
2009-02-15 06:10:59 +00:00
}
} /* Not a PCM */
} while ( retval > 0 ) ; /* All delays must be processed separately */
return retval ;
}
static struct _song_iterator *
2009-02-15 22:34:41 +00:00
_sci1_handle_message ( sci1_song_iterator_t * self ,
song_iterator_message_t msg ) {
2009-02-15 06:10:59 +00:00
if ( msg . recipient = = _SIMSG_BASE ) { /* May extend this in the future */
switch ( msg . type ) {
case _SIMSG_BASEMSG_PRINT : {
int playmask = 0 ;
int i ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
playmask | = self - > channels [ i ] . playmask ;
print_tabs_id ( msg . args [ 0 ] . i , self - > ID ) ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " SCI1: chan-nr=%d, playmask=%04x \n " ,
2009-02-15 22:34:41 +00:00
self - > channels_nr , playmask ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-15 22:34:41 +00:00
break ;
2009-02-15 06:10:59 +00:00
case _SIMSG_BASEMSG_CLONE : {
int tsize = sizeof ( sci1_song_iterator_t ) ;
sci1_song_iterator_t * mem = ( sci1_song_iterator_t * ) sci_malloc ( tsize ) ;
sci1_sample_t * * samplep ;
int delta = msg . args [ 0 ] . i ; /* Delay until next step */
memcpy ( mem , self , tsize ) ;
samplep = & ( mem - > next_sample ) ;
sci_refcount_incref ( mem - > data ) ;
mem - > delay_remaining + = delta ;
/* Clone chain of samples */
while ( * samplep ) {
sci1_sample_t * newsample
2009-02-15 22:34:41 +00:00
= ( sci1_sample_t * ) sci_malloc ( sizeof ( sci1_sample_t ) ) ;
2009-02-15 06:10:59 +00:00
memcpy ( newsample , * samplep ,
sizeof ( sci1_sample_t ) ) ;
* samplep = newsample ;
samplep = & ( newsample - > next ) ;
}
return ( struct _song_iterator * ) mem ; /* Assume caller has another copy of this */
}
case _SIMSG_BASEMSG_STOP : {
songit_id_t sought_id = msg . ID ;
int i ;
if ( sought_id = = self - > ID ) {
self - > ID = 0 ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
self - > channels [ i ] . state = SI_STATE_FINISHED ;
}
break ;
}
2009-02-15 22:34:41 +00:00
case _SIMSG_BASEMSG_SET_PLAYMASK :
if ( msg . ID = = self - > ID ) {
self - > channel_mask = 0 ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
self - > device_id
2009-02-15 06:10:59 +00:00
= sci0_to_sci1_device_map
2009-02-15 22:34:41 +00:00
[ sci_ffs ( msg . args [ 0 ] . i & 0xff ) - 1 ]
[ sfx_pcm_available ( ) ]
;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
if ( self - > device_id = = 0xff ) {
sciprintf ( " [iterator-1] Warning: Device %d(%d) not supported " ,
msg . args [ 0 ] . i & 0xff , sfx_pcm_available ( ) ) ;
}
if ( self - > initialised ) {
int i ;
int toffset = - 1 ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( self - > channels [ i ] . state ! = SI_STATE_FINISHED
& & self - > channels [ i ] . total_timepos > toffset ) {
toffset = self - > channels [ i ] . total_timepos
+ self - > channels [ i ] . timepos_increment
- self - > channels [ i ] . delay ;
}
/* Find an active channel so that we can
* * get the correct time offset */
_sci1_song_init ( self ) ;
toffset - = self - > delay_remaining ;
self - > delay_remaining = 0 ;
if ( toffset > 0 )
return new_fast_forward_iterator ( ( song_iterator_t * ) self ,
toffset ) ;
} else {
_sci1_song_init ( self ) ;
self - > initialised = 1 ;
}
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
break ;
2009-02-15 06:10:59 +00:00
}
case _SIMSG_BASEMSG_SET_LOOPS :
if ( msg . ID = = self - > ID )
2009-02-15 22:34:41 +00:00
self - > loops = ( msg . args [ 0 ] . i > 32767 ) ? 99 : 0 ;
2009-02-15 06:10:59 +00:00
/* 99 is arbitrary, but we can't use '1' because of
* * the way we ' re testing in the decoding section . */
break ;
case _SIMSG_BASEMSG_SET_HOLD :
self - > hold = msg . args [ 0 ] . i ;
break ;
case _SIMSG_BASEMSG_SET_RHYTHM :
/* Ignore */
break ;
2009-02-15 22:34:41 +00:00
case _SIMSG_BASEMSG_SET_FADE : {
2009-02-15 06:10:59 +00:00
fade_params_t * fp = ( fade_params_t * ) msg . args [ 0 ] . p ;
self - > fade . action = fp - > action ;
self - > fade . final_volume = fp - > final_volume ;
self - > fade . ticks_per_step = fp - > ticks_per_step ;
self - > fade . step_size = fp - > step_size ;
break ;
}
default :
2009-02-21 14:11:41 +00:00
fprintf ( stderr , SIPFX " Unsupported command %d to "
2009-02-15 22:34:41 +00:00
" SCI1 iterator " , msg . type ) ;
2009-02-15 06:10:59 +00:00
}
return ( song_iterator_t * ) self ;
}
return NULL ;
}
2009-02-21 16:20:53 +00:00
static int _sci1_read_next_command ( sci1_song_iterator_t * self , unsigned char * buf , int * result ) {
2009-02-15 06:10:59 +00:00
return _sci1_process_next_command ( self , buf , result ) ;
}
2009-02-21 16:20:53 +00:00
static void _sci1_init ( sci1_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
_common_init ( ( base_song_iterator_t * ) self ) ;
self - > ccc = 127 ;
self - > device_id = 0x00 ; /* Default to Sound Blaster/Adlib for purposes
* * of cue computation */
self - > next_sample = NULL ;
self - > channels_nr = 0 ;
self - > initialised = 0 ;
self - > delay_remaining = 0 ;
self - > loops = 0 ;
self - > hold = 0 ;
memset ( self - > polyphony , 0 , sizeof ( self - > polyphony ) ) ;
memset ( self - > importance , 0 , sizeof ( self - > importance ) ) ;
}
2009-02-21 16:20:53 +00:00
static void _sci1_cleanup ( sci1_song_iterator_t * it ) {
2009-02-15 06:10:59 +00:00
sci1_sample_t * sample_seeker = it - > next_sample ;
while ( sample_seeker ) {
sci1_sample_t * old_sample = sample_seeker ;
sample_seeker = sample_seeker - > next ;
2009-02-17 13:51:52 +00:00
free ( old_sample ) ;
2009-02-15 06:10:59 +00:00
}
_sci0_cleanup ( ( sci0_song_iterator_t * ) it ) ;
}
2009-02-21 16:20:53 +00:00
static int _sci1_get_timepos ( sci1_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
int max = 0 ;
int i ;
for ( i = 0 ; i < self - > channels_nr ; i + + )
if ( self - > channels [ i ] . total_timepos > max )
max = self - > channels [ i ] . total_timepos ;
return max ;
}
/*****************************/
/*-- Cleanup song iterator --*/
/*****************************/
2009-02-21 16:20:53 +00:00
static void _cleanup_iterator_init ( song_iterator_t * it ) {
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
static song_iterator_t * _cleanup_iterator_handle_message ( song_iterator_t * i , song_iterator_message_t msg ) {
2009-02-15 06:10:59 +00:00
if ( msg . recipient = = _SIMSG_BASEMSG_PRINT
2009-02-15 22:34:41 +00:00
& & msg . type = = _SIMSG_BASEMSG_PRINT ) {
2009-02-15 06:10:59 +00:00
print_tabs_id ( msg . args [ 0 ] . i , i - > ID ) ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " CLEANUP \n " ) ;
2009-02-15 06:10:59 +00:00
}
return NULL ;
}
2009-02-21 16:20:53 +00:00
static int _cleanup_iterator_next ( song_iterator_t * self , unsigned char * buf , int * result ) {
2009-02-15 06:10:59 +00:00
/* Task: Return channel-notes-off for each channel */
if ( self - > channel_mask ) {
int bs = sci_ffs ( self - > channel_mask ) - 1 ;
self - > channel_mask & = ~ ( 1 < < bs ) ;
buf [ 0 ] = 0xb0 | bs ; /* Controller */
buf [ 1 ] = SCI_MIDI_CHANNEL_NOTES_OFF ;
buf [ 2 ] = 0 ; /* Hmm... */
* result = 3 ;
return 0 ;
} else
return SI_FINISHED ;
}
2009-02-21 16:20:53 +00:00
song_iterator_t * new_cleanup_iterator ( unsigned int channels ) {
2009-02-15 06:10:59 +00:00
song_iterator_t * it = ( song_iterator_t * ) sci_malloc ( sizeof ( song_iterator_t ) ) ;
it - > channel_mask = channels ;
it - > ID = 17 ;
it - > flags = 0 ;
it - > death_listeners_nr = 0 ;
it - > cleanup = NULL ;
it - > get_pcm_feed = NULL ;
it - > init = _cleanup_iterator_init ;
it - > handle_message = _cleanup_iterator_handle_message ;
it - > get_timepos = NULL ;
it - > next = _cleanup_iterator_next ;
return it ;
}
/**********************************/
/*-- Fast-forward song iterator --*/
/**********************************/
2009-02-21 16:20:53 +00:00
static int _ff_read_next_command ( fast_forward_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
byte * buf , int * result ) {
2009-02-15 06:10:59 +00:00
int rv ;
if ( self - > delta < = 0 )
return SI_MORPH ; /* Did our duty */
while ( 1 ) {
rv = self - > delegate - > next ( self - > delegate , buf , result ) ;
if ( rv > 0 ) {
/* Subtract from the delta we want to wait */
self - > delta - = rv ;
/* Done */
if ( self - > delta < 0 )
return - self - > delta ;
}
if ( rv < = 0 )
return rv ;
}
}
2009-02-21 16:20:53 +00:00
static sfx_pcm_feed_t * _ff_check_pcm ( fast_forward_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
return self - > delegate - > get_pcm_feed ( self - > delegate ) ;
}
2009-02-21 16:20:53 +00:00
static song_iterator_t * _ff_handle_message ( fast_forward_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
song_iterator_message_t msg ) {
2009-02-15 06:10:59 +00:00
if ( msg . recipient = = _SIMSG_PLASTICWRAP )
switch ( msg . type ) {
case _SIMSG_PLASTICWRAP_ACK_MORPH :
if ( self - > delta < = 0 ) {
song_iterator_t * it = self - > delegate ;
2009-02-17 13:51:52 +00:00
free ( self ) ;
2009-02-15 06:10:59 +00:00
return it ;
}
break ;
default :
BREAKPOINT ( ) ;
}
else if ( msg . recipient = = _SIMSG_BASE ) {
switch ( msg . type ) {
case _SIMSG_BASEMSG_CLONE : {
int tsize = sizeof ( fast_forward_song_iterator_t ) ;
fast_forward_song_iterator_t * clone = ( fast_forward_song_iterator_t * ) sci_malloc ( tsize ) ;
memcpy ( clone , self , tsize ) ;
songit_handle_message ( & clone - > delegate , msg ) ;
return ( song_iterator_t * ) clone ;
}
case _SIMSG_BASEMSG_PRINT :
print_tabs_id ( msg . args [ 0 ] . i , self - > ID ) ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " PLASTICWRAP: \n " ) ;
2009-02-15 06:10:59 +00:00
msg . args [ 0 ] . i + + ;
songit_handle_message ( & ( self - > delegate ) , msg ) ;
break ;
default :
songit_handle_message ( & ( self - > delegate ) , msg ) ;
}
} else
songit_handle_message ( & ( self - > delegate ) , msg ) ;
return NULL ;
}
2009-02-21 16:20:53 +00:00
static void _ff_init ( fast_forward_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
return ;
}
2009-02-21 16:20:53 +00:00
static int _ff_get_timepos ( fast_forward_song_iterator_t * self ) {
2009-02-15 06:10:59 +00:00
return self - > delegate - > get_timepos ( self - > delegate ) ;
}
2009-02-21 16:20:53 +00:00
song_iterator_t * new_fast_forward_iterator ( song_iterator_t * capsit , int delta ) {
2009-02-15 06:10:59 +00:00
fast_forward_song_iterator_t * it =
2009-02-15 22:34:41 +00:00
( fast_forward_song_iterator_t * ) sci_malloc ( sizeof ( fast_forward_song_iterator_t ) ) ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
if ( capsit = = NULL ) {
free ( it ) ;
return NULL ;
2009-02-15 06:10:59 +00:00
}
it - > ID = 0 ;
it - > delegate = capsit ;
it - > delta = delta ;
it - > death_listeners_nr = 0 ;
it - > next = ( int ( * ) ( song_iterator_t * , unsigned char * , int * ) )
2009-02-15 22:34:41 +00:00
_ff_read_next_command ;
it - > get_pcm_feed = ( sfx_pcm_feed_t * ( * ) ( song_iterator_t * ) )
_ff_check_pcm ;
it - > handle_message = ( song_iterator_t * ( * ) ( song_iterator_t * ,
song_iterator_message_t ) )
_ff_handle_message ;
2009-02-15 06:10:59 +00:00
it - > get_timepos = ( int ( * ) ( song_iterator_t * ) ) _ff_get_timepos ;
it - > init = ( void ( * ) ( song_iterator_t * ) )
2009-02-15 22:34:41 +00:00
_ff_init ;
2009-02-15 06:10:59 +00:00
it - > cleanup = NULL ;
it - > channel_mask = capsit - > channel_mask ;
2009-02-15 22:34:41 +00:00
2009-02-15 06:10:59 +00:00
return ( song_iterator_t * ) it ;
}
/********************/
/*-- Tee iterator --*/
/********************/
2009-02-21 16:20:53 +00:00
static int _tee_read_next_command ( tee_song_iterator_t * it , unsigned char * buf ,
2009-02-15 22:34:41 +00:00
int * result ) {
2009-02-15 06:10:59 +00:00
static int ready_masks [ 2 ] = { TEE_LEFT_READY , TEE_RIGHT_READY } ;
static int active_masks [ 2 ] = { TEE_LEFT_ACTIVE , TEE_RIGHT_ACTIVE } ;
static int pcm_masks [ 2 ] = { TEE_LEFT_PCM , TEE_RIGHT_PCM } ;
int i ;
int retid ;
# ifdef DEBUG_TEE_ITERATOR
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [Tee] %02x \n " , it - > status ) ;
2009-02-15 06:10:59 +00:00
# endif
if ( ! ( it - > status & ( TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE ) ) )
/* None is active? */
return SI_FINISHED ;
if ( it - > morph_deferred = = TEE_MORPH_READY )
return SI_MORPH ;
if ( ( it - > status & ( TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE ) )
2009-02-15 22:34:41 +00:00
! = ( TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE ) ) {
2009-02-15 06:10:59 +00:00
/* Not all are is active? */
2009-02-15 14:26:33 +00:00
int which = 0 ;
2009-02-15 06:10:59 +00:00
# ifdef DEBUG_TEE_ITERATOR
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " \t Requesting transformation... \n " ) ;
2009-02-15 06:10:59 +00:00
# endif
if ( it - > status & TEE_LEFT_ACTIVE )
which = TEE_LEFT ;
else if ( it - > status & TEE_RIGHT_ACTIVE )
which = TEE_RIGHT ;
memcpy ( buf , it - > children [ which ] . buf , MAX_BUF_SIZE ) ;
* result = it - > children [ which ] . result ;
it - > morph_deferred = TEE_MORPH_READY ;
return it - > children [ which ] . retval ;
}
/* First, check for unreported PCMs */
for ( i = TEE_LEFT ; i < = TEE_RIGHT ; i + + )
if ( ( it - > status & ( ready_masks [ i ] | pcm_masks [ i ] ) )
2009-02-15 22:34:41 +00:00
= = ( ready_masks [ i ] | pcm_masks [ i ] ) ) {
2009-02-15 06:10:59 +00:00
it - > status & = ~ ready_masks [ i ] ;
return SI_PCM ;
}
for ( i = TEE_LEFT ; i < = TEE_RIGHT ; i + + )
if ( ! ( it - > status & ready_masks [ i ] ) ) {
/* Buffers aren't ready yet */
it - > children [ i ] . retval =
2009-02-15 22:34:41 +00:00
songit_next ( & ( it - > children [ i ] . it ) ,
it - > children [ i ] . buf ,
& ( it - > children [ i ] . result ) ,
IT_READER_MASK_ALL
| IT_READER_MAY_FREE
| IT_READER_MAY_CLEAN ) ;
2009-02-15 06:10:59 +00:00
it - > status | = ready_masks [ i ] ;
# ifdef DEBUG_TEE_ITERATOR
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " \t Must check %d: %d \n " , i ,
2009-02-15 22:34:41 +00:00
it - > children [ i ] . retval ) ;
2009-02-15 06:10:59 +00:00
# endif
if ( it - > children [ i ] . retval = = SI_ABSOLUTE_CUE | |
2009-02-15 22:34:41 +00:00
it - > children [ i ] . retval = = SI_RELATIVE_CUE )
return it - > children [ i ] . retval ;
2009-02-15 06:10:59 +00:00
if ( it - > children [ i ] . retval = = SI_FINISHED ) {
it - > status & = ~ active_masks [ i ] ;
/* Recurse to complete */
# ifdef DEBUG_TEE_ITERATOR
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " \t Child %d signalled completion, recursing w/ status %02x \n " , i , it - > status ) ;
2009-02-15 06:10:59 +00:00
# endif
return _tee_read_next_command ( it , buf , result ) ;
} else if ( it - > children [ i ] . retval = = SI_PCM ) {
it - > status | = pcm_masks [ i ] ;
it - > status & = ~ ready_masks [ i ] ;
return SI_PCM ;
}
}
/* We've already handled PCM, MORPH and FINISHED, CUEs & LOOP remain */
retid = TEE_LEFT ;
if ( ( it - > children [ TEE_LEFT ] . retval > 0 )
2009-02-15 22:34:41 +00:00
/* Asked to delay */
& & ( it - > children [ TEE_RIGHT ] . retval < = it - > children [ TEE_LEFT ] . retval ) )
2009-02-15 06:10:59 +00:00
/* Is not delaying or not delaying as much */
retid = TEE_RIGHT ;
# ifdef DEBUG_TEE_ITERATOR
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " \t l:%d / r:%d / chose %d \n " ,
2009-02-15 22:34:41 +00:00
it - > children [ TEE_LEFT ] . retval , it - > children [ TEE_RIGHT ] . retval , retid ) ;
2009-02-15 06:10:59 +00:00
# endif
#if 0
if ( it - > children [ retid ] . retval = = 0 ) {
/* Perform remapping, if neccessary */
byte * buf = it - > children [ retid ] . buf ;
if ( * buf ! = SCI_MIDI_SET_SIGNAL
2009-02-15 22:34:41 +00:00
& & * buf < 0xf0 ) { /* Not a generic command */
2009-02-15 06:10:59 +00:00
int chan = * buf & 0xf ;
int op = * buf & 0xf0 ;
chan = it - > children [ retid ] . channel_remap [ chan ] ;
* buf = chan | op ;
}
}
# endif
/* Adjust delta times */
if ( it - > children [ retid ] . retval > 0
2009-02-15 22:34:41 +00:00
& & it - > children [ 1 - retid ] . retval > 0 ) {
2009-02-15 06:10:59 +00:00
if ( it - > children [ 1 - retid ] . retval
2009-02-15 22:34:41 +00:00
= = it - > children [ retid ] . retval )
2009-02-15 06:10:59 +00:00
/* If both children wait the same amount of time,
* * we have to re - fetch commands from both */
it - > status & = ~ ready_masks [ 1 - retid ] ;
else
/* If they don't, we can/must re-use the other
* * child ' s delay time */
it - > children [ 1 - retid ] . retval
2009-02-15 22:34:41 +00:00
- = it - > children [ retid ] . retval ;
2009-02-15 06:10:59 +00:00
}
it - > status & = ~ ready_masks [ retid ] ;
memcpy ( buf , it - > children [ retid ] . buf , MAX_BUF_SIZE ) ;
* result = it - > children [ retid ] . result ;
return it - > children [ retid ] . retval ;
}
2009-02-21 16:20:53 +00:00
static sfx_pcm_feed_t * _tee_check_pcm ( tee_song_iterator_t * it ) {
2009-02-15 06:10:59 +00:00
static int pcm_masks [ 2 ] = { TEE_LEFT_PCM , TEE_RIGHT_PCM } ;
int i ;
for ( i = TEE_LEFT ; i < = TEE_RIGHT ; i + + )
if ( it - > status & pcm_masks [ i ] ) {
it - > status & = ~ pcm_masks [ i ] ;
return it - > children [ i ] . it - >
2009-02-15 22:34:41 +00:00
get_pcm_feed ( it - > children [ i ] . it ) ;
2009-02-15 06:10:59 +00:00
}
return NULL ; /* No iterator */
}
2009-02-21 16:20:53 +00:00
static song_iterator_t * _tee_handle_message ( tee_song_iterator_t * self , song_iterator_message_t msg ) {
2009-02-15 06:10:59 +00:00
if ( msg . recipient = = _SIMSG_BASE ) {
switch ( msg . type ) {
case _SIMSG_BASEMSG_PRINT :
print_tabs_id ( msg . args [ 0 ] . i , self - > ID ) ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " TEE: \n " ) ;
2009-02-15 06:10:59 +00:00
msg . args [ 0 ] . i + + ;
break ; /* And continue with our children */
case _SIMSG_BASEMSG_CLONE : {
tee_song_iterator_t * newit
2009-02-15 22:34:41 +00:00
= ( tee_song_iterator_t * ) sci_malloc ( sizeof ( tee_song_iterator_t ) ) ;
2009-02-15 06:10:59 +00:00
memcpy ( newit , self , sizeof ( tee_song_iterator_t ) ) ;
if ( newit - > children [ TEE_LEFT ] . it )
newit - > children [ TEE_LEFT ] . it =
2009-02-15 22:34:41 +00:00
songit_clone ( newit - > children [ TEE_LEFT ] . it , msg . args [ 0 ] . i ) ;
2009-02-15 06:10:59 +00:00
if ( newit - > children [ TEE_RIGHT ] . it )
newit - > children [ TEE_RIGHT ] . it =
2009-02-15 22:34:41 +00:00
songit_clone ( newit - > children [ TEE_RIGHT ] . it , msg . args [ 0 ] . i ) ;
2009-02-15 06:10:59 +00:00
return ( song_iterator_t * ) newit ;
}
default :
break ;
}
}
if ( msg . recipient = = _SIMSG_PLASTICWRAP ) {
song_iterator_t * old_it ;
switch ( msg . type ) {
case _SIMSG_PLASTICWRAP_ACK_MORPH :
if ( ! ( self - > status & ( TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE ) ) ) {
songit_free ( ( song_iterator_t * ) self ) ;
return NULL ;
} else if ( ! ( self - > status & TEE_LEFT_ACTIVE ) ) {
if ( self - > may_destroy )
songit_free ( self - > children [ TEE_LEFT ] . it ) ;
old_it = self - > children [ TEE_RIGHT ] . it ;
2009-02-17 13:51:52 +00:00
free ( self ) ;
2009-02-15 06:10:59 +00:00
return old_it ;
} else if ( ! ( self - > status & TEE_RIGHT_ACTIVE ) ) {
if ( self - > may_destroy )
songit_free ( self - > children [ TEE_RIGHT ] . it ) ;
old_it = self - > children [ TEE_LEFT ] . it ;
2009-02-17 13:51:52 +00:00
free ( self ) ;
2009-02-15 06:10:59 +00:00
return old_it ;
} else {
sciprintf ( " [tee-iterator] WARNING: "
2009-02-15 22:34:41 +00:00
" Morphing without need \n " ) ;
2009-02-15 06:10:59 +00:00
return ( song_iterator_t * ) self ;
}
default :
BREAKPOINT ( ) ;
}
}
if ( self - > children [ TEE_LEFT ] . it )
songit_handle_message ( & ( self - > children [ TEE_LEFT ] . it ) , msg ) ;
if ( self - > children [ TEE_RIGHT ] . it )
songit_handle_message ( & ( self - > children [ TEE_RIGHT ] . it ) , msg ) ;
return NULL ;
}
2009-02-21 16:20:53 +00:00
static void _tee_init ( tee_song_iterator_t * it ) {
2009-02-15 06:10:59 +00:00
it - > status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE ;
it - > children [ TEE_LEFT ] . it - > init ( it - > children [ TEE_LEFT ] . it ) ;
it - > children [ TEE_RIGHT ] . it - > init ( it - > children [ TEE_RIGHT ] . it ) ;
}
2009-02-15 14:26:33 +00:00
#if 0
// Unreferenced - removed
2009-02-21 16:20:53 +00:00
static void _tee_free ( tee_song_iterator_t * it ) {
2009-02-15 06:10:59 +00:00
int i ;
for ( i = TEE_LEFT ; i < = TEE_RIGHT ; i + + )
if ( it - > children [ i ] . it & & it - > may_destroy )
songit_free ( it - > children [ i ] . it ) ;
}
2009-02-15 14:26:33 +00:00
# endif
2009-02-15 06:10:59 +00:00
2009-02-21 16:20:53 +00:00
static void songit_tee_death_notification ( tee_song_iterator_t * self ,
2009-02-15 22:34:41 +00:00
song_iterator_t * corpse ) {
2009-02-15 06:10:59 +00:00
if ( corpse = = self - > children [ TEE_LEFT ] . it ) {
self - > status & = ~ TEE_LEFT_ACTIVE ;
self - > children [ TEE_LEFT ] . it = NULL ;
} else if ( corpse = = self - > children [ TEE_RIGHT ] . it ) {
self - > status & = ~ TEE_RIGHT_ACTIVE ;
self - > children [ TEE_RIGHT ] . it = NULL ;
} else {
BREAKPOINT ( ) ;
}
}
2009-02-21 16:20:53 +00:00
song_iterator_t * songit_new_tee ( song_iterator_t * left , song_iterator_t * right , int may_destroy ) {
2009-02-15 06:10:59 +00:00
int i ;
int firstfree = 1 ; /* First free channel */
int incomplete_map = 0 ;
tee_song_iterator_t * it = ( tee_song_iterator_t * ) sci_malloc ( sizeof ( tee_song_iterator_t ) ) ;
it - > ID = 0 ;
it - > morph_deferred = TEE_MORPH_NONE ;
it - > status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE ;
it - > may_destroy = may_destroy ;
it - > children [ TEE_LEFT ] . it = left ;
it - > children [ TEE_RIGHT ] . it = right ;
it - > death_listeners_nr = 0 ;
/* By default, don't remap */
for ( i = 0 ; i < 16 ; i + + )
it - > children [ TEE_LEFT ] . channel_remap [ i ]
2009-02-15 22:34:41 +00:00
= it - > children [ TEE_RIGHT ] . channel_remap [ i ] = i ;
2009-02-15 06:10:59 +00:00
/* Default to lhs channels */
it - > channel_mask = left - > channel_mask ;
for ( i = 0 ; i < 16 ; i + + )
if ( it - > channel_mask & ( 1 < < i ) & right - > channel_mask
2009-02-15 22:34:41 +00:00
& & ( i ! = MIDI_RHYTHM_CHANNEL ) /* Share rhythm */ ) { /*conflict*/
2009-02-15 06:10:59 +00:00
while ( ( firstfree = = MIDI_RHYTHM_CHANNEL )
2009-02-15 22:34:41 +00:00
/* Either if it's the rhythm channel or if it's taken */
| | ( firstfree < MIDI_CHANNELS
& & ( ( 1 < < firstfree ) & it - > channel_mask ) ) )
2009-02-15 06:10:59 +00:00
+ + firstfree ;
if ( firstfree = = MIDI_CHANNELS ) {
incomplete_map = 1 ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [songit-tee <%08lx,%08lx>] "
2009-02-15 22:34:41 +00:00
" Could not remap right channel #%d: "
" Out of channels \n " ,
left - > ID , right - > ID , i ) ;
2009-02-15 06:10:59 +00:00
} else {
it - > children [ TEE_RIGHT ] . channel_remap [ i ]
2009-02-15 22:34:41 +00:00
= firstfree ;
2009-02-15 06:10:59 +00:00
it - > channel_mask | = ( 1 < < firstfree ) ;
}
}
# ifdef DEBUG_TEE_ITERATOR
if ( incomplete_map ) {
int c ;
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [songit-tee <%08lx,%08lx>] Channels: "
2009-02-15 22:34:41 +00:00
" %04x <- %04x | %04x \n " ,
left - > ID , right - > ID ,
it - > channel_mask ,
left - > channel_mask , right - > channel_mask ) ;
for ( c = 0 ; c < 2 ; c + + )
for ( i = 0 ; i < 16 ; i + + )
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " map [%d][%d] -> %d \n " ,
2009-02-15 22:34:41 +00:00
c , i , it - > children [ c ] . channel_remap [ i ] ) ;
2009-02-15 06:10:59 +00:00
}
# endif
it - > next = ( int ( * ) ( song_iterator_t * , unsigned char * , int * ) )
2009-02-15 22:34:41 +00:00
_tee_read_next_command ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
it - > get_pcm_feed = ( sfx_pcm_feed_t * ( * ) ( song_iterator_t * ) )
_tee_check_pcm ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:34:41 +00:00
it - > handle_message = ( song_iterator_t * ( * ) ( song_iterator_t * ,
song_iterator_message_t ) )
_tee_handle_message ;
2009-02-15 06:10:59 +00:00
it - > init = ( void ( * ) ( song_iterator_t * ) )
2009-02-15 22:34:41 +00:00
_tee_init ;
2009-02-15 06:10:59 +00:00
it - > get_timepos = NULL ;
song_iterator_add_death_listener ( ( song_iterator_t * ) it ,
2009-02-15 22:34:41 +00:00
left , ( void ( * ) ( void * , void * ) )
songit_tee_death_notification ) ;
2009-02-15 06:10:59 +00:00
song_iterator_add_death_listener ( ( song_iterator_t * ) it ,
2009-02-15 22:34:41 +00:00
right , ( void ( * ) ( void * , void * ) )
songit_tee_death_notification ) ;
2009-02-15 06:10:59 +00:00
it - > cleanup = NULL ;
return ( song_iterator_t * ) it ;
}
/*************************************/
/*-- General purpose functionality --*/
/*************************************/
2009-02-21 16:20:53 +00:00
int songit_next ( song_iterator_t * * it , unsigned char * buf , int * result , int mask ) {
2009-02-15 06:10:59 +00:00
int retval ;
if ( ! * it )
return SI_FINISHED ;
do {
retval = ( * it ) - > next ( * it , buf , result ) ;
if ( retval = = SI_MORPH ) {
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " Morphing %p (stored at %p) \n " , ( void * ) * it , ( void * ) it ) ;
2009-02-15 06:10:59 +00:00
if ( ! SIMSG_SEND ( ( * it ) , SIMSG_ACK_MORPH ) ) {
BREAKPOINT ( ) ;
2009-02-21 14:11:41 +00:00
} else fprintf ( stderr , " SI_MORPH successful \n " ) ;
2009-02-15 06:10:59 +00:00
}
if ( retval = = SI_FINISHED )
2009-02-21 14:11:41 +00:00
fprintf ( stderr , " [song-iterator] Song finished. mask = %04x, cm=%04x \n " ,
2009-02-15 22:34:41 +00:00
mask , ( * it ) - > channel_mask ) ;
2009-02-15 06:10:59 +00:00
if ( retval = = SI_FINISHED
2009-02-15 22:34:41 +00:00
& & ( mask & IT_READER_MAY_CLEAN )
& & ( * it ) - > channel_mask ) { /* This last test will fail
2009-02-15 06:10:59 +00:00
* * with a terminated
* * cleanup iterator */
int channel_mask = ( * it ) - > channel_mask ;
if ( mask & IT_READER_MAY_FREE )
songit_free ( * it ) ;
* it = new_cleanup_iterator ( channel_mask ) ;
retval = - 9999 ; /* Continue */
}
2009-02-15 22:34:41 +00:00
} while ( ! ( /* Until one of the following holds */
( retval > 0 & & ( mask & IT_READER_MASK_DELAY ) )
| | ( retval = = 0 & & ( mask & IT_READER_MASK_MIDI ) )
| | ( retval = = SI_LOOP & & ( mask & IT_READER_MASK_LOOP ) )
| | ( retval = = SI_ABSOLUTE_CUE & &
( mask & IT_READER_MASK_CUE ) )
| | ( retval = = SI_RELATIVE_CUE & &
( mask & IT_READER_MASK_CUE ) )
| | ( retval = = SI_PCM & & ( mask & IT_READER_MASK_PCM ) )
| | ( retval = = SI_FINISHED )
) ) ;
2009-02-15 06:10:59 +00:00
if ( retval = = SI_FINISHED
2009-02-15 22:34:41 +00:00
& & ( mask & IT_READER_MAY_FREE ) ) {
2009-02-15 06:10:59 +00:00
songit_free ( * it ) ;
* it = NULL ;
}
return retval ;
}
2009-02-21 16:20:53 +00:00
song_iterator_t * songit_new ( unsigned char * data , unsigned int size , int type , songit_id_t id ) {
2009-02-15 06:10:59 +00:00
base_song_iterator_t * it ;
int i ;
if ( ! data | | size < 22 ) {
2009-02-20 23:19:47 +00:00
warning ( SIPFX " Attempt to instantiate song iterator for null "
" song data " ) ;
2009-02-15 06:10:59 +00:00
return NULL ;
}
switch ( type ) {
2009-02-15 22:34:41 +00:00
case SCI_SONG_ITERATOR_TYPE_SCI0 :
/**-- Playing SCI0 sound resources --**/
it = ( base_song_iterator_t * ) sci_malloc ( sizeof ( sci0_song_iterator_t ) ) ;
it - > channel_mask = 0xffff ; /* Allocate all channels by default */
for ( i = 0 ; i < MIDI_CHANNELS ; i + + )
it - > polyphony [ i ] = data [ 1 + ( i < < 1 ) ] ;
it - > next = ( int ( * ) ( song_iterator_t * , unsigned char * , int * ) )
_sci0_read_next_command ;
it - > get_pcm_feed = ( sfx_pcm_feed_t * ( * ) ( song_iterator_t * ) )
_sci0_check_pcm ;
it - > handle_message = ( song_iterator_t * ( * ) ( song_iterator_t * , song_iterator_message_t ) )
_sci0_handle_message ;
it - > init = ( void ( * ) ( song_iterator_t * ) ) _sci0_init ;
it - > cleanup = ( void ( * ) ( song_iterator_t * ) ) _sci0_cleanup ;
( ( sci0_song_iterator_t * ) it ) - > channel . state
= SI_STATE_UNINITIALISED ;
it - > get_timepos = ( int ( * ) ( song_iterator_t * ) ) _sci0_get_timepos ;
break ;
case SCI_SONG_ITERATOR_TYPE_SCI1 :
/**-- SCI01 or later sound resource --**/
it = ( base_song_iterator_t * ) sci_malloc ( sizeof ( sci1_song_iterator_t ) ) ;
it - > channel_mask = 0 ; /* Defer channel allocation */
for ( i = 0 ; i < MIDI_CHANNELS ; i + + )
it - > polyphony [ i ] = 0 ; /* Unknown */
it - > next = ( int ( * ) ( song_iterator_t * , unsigned char * , int * ) )
_sci1_read_next_command ;
it - > get_pcm_feed = ( sfx_pcm_feed_t * ( * ) ( song_iterator_t * ) )
_sci1_get_pcm ;
it - > handle_message = ( song_iterator_t * ( * ) ( song_iterator_t * , song_iterator_message_t ) )
_sci1_handle_message ;
it - > init = ( void ( * ) ( song_iterator_t * ) ) _sci1_init ;
it - > cleanup = ( void ( * ) ( song_iterator_t * ) ) _sci1_cleanup ;
it - > get_timepos = ( int ( * ) ( song_iterator_t * ) ) _sci1_get_timepos ;
break ;
default :
/**-- Invalid/unsupported sound resources --**/
2009-02-20 23:19:47 +00:00
warning ( SIPFX " Attempt to instantiate invalid/unknown "
2009-02-15 22:34:41 +00:00
" song iterator type %d \n " , type ) ;
return NULL ;
2009-02-15 06:10:59 +00:00
}
it - > ID = id ;
it - > death_listeners_nr = 0 ;
it - > data = ( unsigned char * ) sci_refcount_memdup ( data , size ) ;
it - > size = size ;
it - > init ( ( song_iterator_t * ) it ) ;
return ( song_iterator_t * ) it ;
}
2009-02-21 16:20:53 +00:00
void songit_free ( song_iterator_t * it ) {
2009-02-15 06:10:59 +00:00
if ( it ) {
int i ;
if ( it - > cleanup )
it - > cleanup ( it ) ;
for ( i = 0 ; i < it - > death_listeners_nr ; i + + )
it - > death_listeners [ i ] . notify ( it - > death_listeners [ i ] . self , it ) ;
2009-02-17 13:51:52 +00:00
free ( it ) ;
2009-02-15 06:10:59 +00:00
}
}
2009-02-21 16:20:53 +00:00
song_iterator_message_t songit_make_message ( songit_id_t id , int recipient , int type , int a1 , int a2 ) {
2009-02-15 06:10:59 +00:00
song_iterator_message_t rv ;
rv . ID = id ;
rv . recipient = recipient ;
rv . type = type ;
rv . args [ 0 ] . i = a1 ;
rv . args [ 1 ] . i = a2 ;
return rv ;
}
2009-02-21 16:20:53 +00:00
song_iterator_message_t songit_make_ptr_message ( songit_id_t id , int recipient , int type , void * a1 , int a2 ) {
2009-02-15 06:10:59 +00:00
song_iterator_message_t rv ;
rv . ID = id ;
rv . recipient = recipient ;
rv . type = type ;
rv . args [ 0 ] . p = a1 ;
rv . args [ 1 ] . i = a2 ;
return rv ;
}
2009-02-21 16:20:53 +00:00
int songit_handle_message ( song_iterator_t * * it_reg_p , song_iterator_message_t msg ) {
2009-02-15 06:10:59 +00:00
song_iterator_t * it = * it_reg_p ;
song_iterator_t * newit ;
newit = it - > handle_message ( it , msg ) ;
if ( ! newit )
return 0 ; /* Couldn't handle */
* it_reg_p = newit ; /* Might have self-morphed */
return 1 ;
}
2009-02-21 16:20:53 +00:00
song_iterator_t * songit_clone ( song_iterator_t * it , int delta ) {
2009-02-15 06:10:59 +00:00
SIMSG_SEND ( it , SIMSG_CLONE ( delta ) ) ;
it - > death_listeners_nr = 0 ;
it - > flags | = SONGIT_FLAG_CLONE ;
return it ;
}
2009-02-21 16:20:53 +00:00
void song_iterator_add_death_listener ( song_iterator_t * it ,
2009-02-15 22:34:41 +00:00
void * client ,
void ( * notify ) ( void * self , void * notifier ) ) {
2009-02-15 06:10:59 +00:00
if ( it - > death_listeners_nr > = SONGIT_MAX_LISTENERS ) {
2009-02-21 18:16:17 +00:00
error ( " FATAL: Too many death listeners for song iterator " ) ;
2009-02-15 06:10:59 +00:00
}
it - > death_listeners [ it - > death_listeners_nr ] . notify = notify ;
it - > death_listeners [ it - > death_listeners_nr ] . self = client ;
it - > death_listeners_nr + + ;
}
2009-02-21 16:20:53 +00:00
void song_iterator_remove_death_listener ( song_iterator_t * it ,
2009-02-15 22:34:41 +00:00
void * client ) {
2009-02-15 06:10:59 +00:00
int i ;
for ( i = 0 ; i < it - > death_listeners_nr ; i + + ) {
if ( it - > death_listeners [ i ] . self = = client ) {
- - it - > death_listeners_nr ;
/* Overwrite, if this wasn't the last one */
2009-02-15 22:34:41 +00:00
if ( i + 1 < it - > death_listeners_nr )
2009-02-15 06:10:59 +00:00
it - > death_listeners [ i ]
2009-02-15 22:34:41 +00:00
= it - > death_listeners [ it - > death_listeners_nr ] ;
2009-02-15 06:10:59 +00:00
return ;
}
}
2009-02-21 18:16:17 +00:00
error ( " FATAL: Could not remove death listener from song iterator \n " ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 16:20:53 +00:00
song_iterator_t * sfx_iterator_combine ( song_iterator_t * it1 , song_iterator_t * it2 ) {
2009-02-15 06:10:59 +00:00
if ( it1 = = NULL )
return it2 ;
if ( it2 = = NULL )
return it1 ;
/* Both are non-NULL: */
return songit_new_tee ( it1 , it2 , 1 ) ; /* 'may destroy' */
}
2009-02-21 10:23:36 +00:00
} // End of namespace Sci