aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sfx/softseq/SN76496.c
diff options
context:
space:
mode:
authorJordi Vilalta Prat2009-02-15 06:10:59 +0000
committerJordi Vilalta Prat2009-02-15 06:10:59 +0000
commitfa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch)
treece87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/sfx/softseq/SN76496.c
parent7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff)
downloadscummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.gz
scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.bz2
scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.zip
Import the SCI engine sources from the FreeSCI Glutton branch (it doesn't compile yet)
svn-id: r38192
Diffstat (limited to 'engines/sci/sfx/softseq/SN76496.c')
-rw-r--r--engines/sci/sfx/softseq/SN76496.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/engines/sci/sfx/softseq/SN76496.c b/engines/sci/sfx/softseq/SN76496.c
new file mode 100644
index 0000000000..cb32b89f0c
--- /dev/null
+++ b/engines/sci/sfx/softseq/SN76496.c
@@ -0,0 +1,248 @@
+/***************************************************************************
+ SN76496.c Copyright (C) 2004 Christoph Reichenbach
+
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public Licence as
+ published by the Free Software Foundaton; either version 2 of the
+ Licence, or (at your option) any later version.
+
+ It is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ merchantibility or fitness for a particular purpose. See the
+ GNU General Public Licence for more details.
+
+ You should have received a copy of the GNU General Public Licence
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+
+ Please contact the maintainer for any program-related bug reports or
+ inquiries.
+
+ Current Maintainer:
+
+ Christoph Reichenbach (CR) <jameson@linuxgames.com>
+
+***************************************************************************/
+/* Tandy/PCJr sequencer for FreeSCI */
+
+#include "../softseq.h"
+#include <sci_midi.h>
+
+#define FREQUENCY 44100
+#define CHANNELS_NR 3
+#define VOLUME_SHIFT 3
+
+static int global_volume = 100; /* Base volume */
+static int volumes[CHANNELS_NR] = { 100, 100, 100 };
+static int notes[CHANNELS_NR] = {0, 0, 0}; /* Current halftone, or 0 if off */
+static int freq_count[CHANNELS_NR] = {0, 0, 0};
+static int channel_assigner = 0;
+static int channels_assigned = 0;
+static int chan_nrs[CHANNELS_NR] = {-1, -1, -1};
+
+extern sfx_softseq_t sfx_softseq_pcspeaker;
+/* Forward-declare the sequencer we are defining here */
+
+
+static int
+SN76496_set_option(sfx_softseq_t *self, char *name, char *value)
+{
+ return SFX_ERROR;
+}
+
+static int
+SN76496_init(sfx_softseq_t *self, byte *patch, int patch_len, byte *patch2,
+ int patch2_len)
+{
+ return SFX_OK;
+}
+
+static void
+SN76496_exit(sfx_softseq_t *self)
+{
+}
+
+static void
+SN76496_event(sfx_softseq_t *self, byte command, int argc, byte *argv)
+{
+ int i;
+ int chan = -1;
+#if 0
+ fprintf(stderr, "Note [%02x : %02x %02x]\n", command, argc?argv[0] : 0, (argc > 1)? argv[1] : 0);
+#endif
+ if ((command & 0xe0) == 0x80) {
+ int chan_nr = command & 0xf;
+
+ /* First, test for channel having been assigned already */
+ if (channels_assigned & (1 << chan_nr)) {
+ /* Already assigned this channel number: */
+ for (i = 0; i < CHANNELS_NR; i++)
+ if (chan_nrs[i] == chan_nr) {
+ chan = i;
+ break;
+ }
+ } else {
+ /* Assign new channel round-robin */
+
+ /* Mark channel as unused: */
+ if (chan_nrs[channel_assigner] >= 0)
+ channels_assigned &= ~(1 << chan_nrs[channel_assigner]);
+
+ /* Remember channel: */
+ chan_nrs[channel_assigner] = chan_nr;
+ /* Mark channel as used */
+ channels_assigned |= (1 << chan_nrs[channel_assigner]);
+
+ /* Save channel for use later in this call: */
+ chan = channel_assigner;
+ /* Round-ropin iterate channel assigner: */
+ channel_assigner = (channel_assigner + 1) % CHANNELS_NR;
+ }
+ }
+#if 0
+ fprintf(stderr, " --> %d [%04x], {%d,%d,%d}@%d\n", chan,
+ channels_assigned, chan_nrs[0],chan_nrs[1],chan_nrs[2],channel_assigner);
+#endif
+
+ switch (command & 0xf0) {
+
+ case 0x80:
+ if (argv[0] == notes[chan])
+ notes[chan] = 0;
+ break;
+
+ case 0x90:
+ if (!argv[1]) {
+ if (argv[chan] == notes[chan])
+ notes[chan] = 0;
+ } else {
+ notes[chan] = argv[0];
+ volumes[chan] = argv[1];
+ }
+ break;
+
+ case 0xb0:
+ if (argv[1] == SCI_MIDI_CHANNEL_NOTES_OFF)
+ notes[chan] = 0;
+ break;
+
+
+ default:
+#if DEBUG
+ fprintf(stderr, "[SFX:PCM-PC] Unused MIDI command %02x %02x %02x\n", command, argc?argv[0] : 0, (argc > 1)? argv[1] : 0);
+#endif
+ break; /* ignore */
+ }
+}
+
+#define BASE_NOTE 129 /* A10 */
+#define BASE_OCTAVE 10 /* A10, as I said */
+
+static int
+freq_table[12] = { /* A4 is 440Hz, halftone map is x |-> ** 2^(x/12) */
+ 28160, /* A10 */
+ 29834,
+ 31608,
+ 33488,
+ 35479,
+ 37589,
+ 39824,
+ 42192,
+ 44701,
+ 47359,
+ 50175,
+ 53159
+};
+
+static inline int
+get_freq(int note)
+{
+ int halftone_delta = note - BASE_NOTE;
+ int oct_diff = ((halftone_delta + BASE_OCTAVE * 12) / 12) - BASE_OCTAVE;
+ int halftone_index = (halftone_delta + (12*100)) % 12 ;
+ int freq = (!note)? 0 : freq_table[halftone_index] / (1 << (-oct_diff));
+
+ return freq;
+}
+
+
+void
+SN76496_poll(sfx_softseq_t *self, byte *dest, int len)
+{
+ gint16 *buf = (gint16 *) dest;
+ int i;
+ int chan;
+ int freq[CHANNELS_NR];
+
+ for (chan = 0; chan < CHANNELS_NR; chan++)
+ freq[chan] = get_freq(notes[chan]);
+
+ for (i = 0; i < len; i++) {
+ int result = 0;
+
+ for (chan = 0; chan < CHANNELS_NR; chan++)
+ if (notes[chan]) {
+ int volume = (global_volume * volumes[chan])
+ >> VOLUME_SHIFT;
+
+ freq_count[chan] += freq[chan];
+ while (freq_count[chan] >= (FREQUENCY << 1))
+ freq_count[chan] -= (FREQUENCY << 1);
+
+ if (freq_count[chan] - freq[chan] < 0) {
+ /* Unclean rising edge */
+ int l = volume << 1;
+ result += -volume + (l*freq_count[chan])/freq[chan];
+ } else if (freq_count[chan] >= FREQUENCY
+ && freq_count[chan] - freq[chan] < FREQUENCY) {
+ /* Unclean falling edge */
+ int l = volume << 1;
+ result += volume - (l*(freq_count[chan] - FREQUENCY))/freq[chan];
+ } else {
+ if (freq_count[chan] < FREQUENCY)
+ result += volume;
+ else
+ result += -volume;
+ }
+ }
+ buf[i] = result;
+ }
+
+}
+
+void
+SN76496_allstop(sfx_softseq_t *self)
+{
+ int i;
+ for (i = 0; i < CHANNELS_NR; i++)
+ notes[i] = 0;
+}
+
+void
+SN76496_volume(sfx_softseq_t *self, int new_volume)
+{
+ global_volume = new_volume;
+}
+
+
+sfx_softseq_t sfx_softseq_SN76496 = {
+ "SN76496",
+ "0.1",
+ SN76496_set_option,
+ SN76496_init,
+ SN76496_exit,
+ SN76496_volume,
+ SN76496_event,
+ SN76496_poll,
+ SN76496_allstop,
+ NULL,
+ SFX_SEQ_PATCHFILE_NONE,
+ SFX_SEQ_PATCHFILE_NONE,
+ 0x10, /* Tandy/PCJr channels */
+ 0, /* No rhythm channel */
+ 3, /* # of voices */
+ {FREQUENCY, SFX_PCM_MONO, SFX_PCM_FORMAT_S16_NATIVE}
+};