diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /lib/libOSSlib | |
download | oss4-upstream.tar.gz |
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'lib/libOSSlib')
-rw-r--r-- | lib/libOSSlib/.config | 2 | ||||
-rw-r--r-- | lib/libOSSlib/.nativemake | 0 | ||||
-rw-r--r-- | lib/libOSSlib/Makefile | 29 | ||||
-rw-r--r-- | lib/libOSSlib/Readme | 120 | ||||
-rw-r--r-- | lib/libOSSlib/compile.sh | 81 | ||||
-rw-r--r-- | lib/libOSSlib/gmidi.h | 259 | ||||
-rw-r--r-- | lib/libOSSlib/libmain.c | 200 | ||||
-rw-r--r-- | lib/libOSSlib/midiparser.c | 401 | ||||
-rw-r--r-- | lib/libOSSlib/midiparser.h | 1 | ||||
-rw-r--r-- | lib/libOSSlib/play_event.c | 273 |
10 files changed, 1366 insertions, 0 deletions
diff --git a/lib/libOSSlib/.config b/lib/libOSSlib/.config new file mode 100644 index 0000000..f34695c --- /dev/null +++ b/lib/libOSSlib/.config @@ -0,0 +1,2 @@ +mode=shlib +targetos=Linux diff --git a/lib/libOSSlib/.nativemake b/lib/libOSSlib/.nativemake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/libOSSlib/.nativemake diff --git a/lib/libOSSlib/Makefile b/lib/libOSSlib/Makefile new file mode 100644 index 0000000..98029f1 --- /dev/null +++ b/lib/libOSSlib/Makefile @@ -0,0 +1,29 @@ +OBJS=libmain.o midiparser.o play_event.o +INSTALLLIB=/lib +LDFLAGS=-shared -fPIC +CFLAGS=-O -fPIC +#LDFLAGS=-Bdynamic +AROPTS=rc +AR=ar + +all: + sh ./compile.sh $(INSTALLLIB) "$(CC)" "$(CFLAGS)" "$(MAKE)" + +install: all + cp libOSSlib.* $(INSTALLLIB) + cp drums.o3 std.o3 /etc + +static: libOSSlib.a + cp libOSSlib.a $(INSTALLLIB) + +libOSSlib.so: $(OBJS) + ${CC} $(LDFLAGS) -o libOSSlib.so $(OBJS) + +dep: + +clean: + rm -f *.o *.so x y z core *.a + +libOSSlib.a: $(OBJS) + $(AR) $(AROPTS) libOSSlib.a $(OBJS) + #-ranlib libOSSlib.a diff --git a/lib/libOSSlib/Readme b/lib/libOSSlib/Readme new file mode 100644 index 0000000..b975b78 --- /dev/null +++ b/lib/libOSSlib/Readme @@ -0,0 +1,120 @@ +About OSSlib +============ + +This version of OSSlib which supports patch caching for cards like GUS, OPL3 +and SoftOSS. This part of the library is only used by some older synthesizer +chips that are no longer available. Also the SoftOSS virtual synth is +compatible with it. + +Another part is the midiparser library. It's a simple callback based +system that translates a stream of MIDI bytes (for example from MIDI +keyboard) to events. + +This library is compatible with all OSS implementations including the freeware +implementations. + +Copying conditions +------------------ + +This library can be freely used in ANY applications that is compatible +with the OSS API. No parts of the code can be borroved to other purposes +without written permission by 4Front Technologies. + +Installing OSSlib +----------------- + +Execute make. If your operating system is recognized you will get +libOSSlib.so or libOSSlib.a depending on operating system. +If make complains about unknown operating system you should use +make libOSSlib.so or make libOSSlib.a to build it. + +Finally copy libOSSlib.* to /usr/lib + +Using OSSlib in programs +------------------------ + +OSSlib is intended to be used in programs using /dev/music but +it also works with /dev/sequencer too. This version of the library +contains only some basic patch caching functions to be used with +OPL3 and GUS (and SoftOSS as well). Support for other cards is still +missing. + +There are steps to be done when using OSSlib in a program: + +1) Change Makefile to use -DOSSLIB and -lOSSlib + +Version 3.8 of <sys/soundcard.h> has been designed to be compatible +with OSSlib when this OSSLIB is defined. You can also use +#ifdef OSSLIB in programs to cover the minor differences between +the OSSlib and non OSSlib versions. + +2) If the program defines segbuf_dump() routine, put it inside +#ifndef OSSLIB/#endif pair. This routine is included in OSSlib +and having the same routine inside the program conflicts with it. + +3) Add the following call to the program after /dev/music is opened. + +#ifdef OSSLIB + OSS_init(seqfd, 1024); +#endif + +In the above seqfd is the file descriptor of /dev/music and 1024 +is the size of the local buffer used for output events (1024 is +a good value). + +4) Add patch caching calls to the program. Patch caching should +be called as early as possible. It's recommended to load all +_required_ patches before starting the actual playback since +loading large patches from disk may introduce significant delays +to playback. + +There are two macros (in soundcard.h) to be used when loading +instruments: + +SEQ_LOAD_GMINSTR(dev#, instr#) loads an instrument (melodic) patch. +The first parameter is the synthesizer/device number (0 to N) and +the second parameter is the General MIDI instrument number (0 to 127). +Note that the numbering starts from #0 while many GM instrument +tables start from #1. + +SEQ_LOAD_GMDRUM(dev#, drum#) is similar than the above but it loads +an General MIDI percussive instrument. + +5) After the above steps your program is ready to start playing. + +Examples for using OSSlib and for playing MIDI data can be found +in ../mplay/* and ../gustest/midithru.c + +GUS support in OSSlib +--------------------- + +You will need the full GM patch set distributed with the Ultrasound +drivers for DOS. The default location where the library tries to +find the patches is /dos/ultrasnd/midi but you can change it by +editing guslib.c (the second line). Alternative patch sets +(such as midia) are available from the net. Another source is the MIDIA +library. + +Since non PnP GUS has only 1M of +RAM (at most) it's not possible to load the full patch set. When playing +lot of MIDI files in sequence it's possible that the menory becomes +full if the program doesn't reset the samples between files. + +OPL3 support in OSSlib +---------------------- + +OSSlib supports patch loading to OPL3 FM synth cards (older OPL2 cards +are not supported). The patch set is included in the std.o3 and drums.o3 +files distributed with this package. These files should be copied to /etc +(will be done by "make install"). These patch files are the same ones +included in Adagio/glib package by Greg Lee. They are also distributed +with playmidi. + +Using OSSlib with SoftOSS +------------------------- + +For instructions about using OSSLib with SoftOSS see the instructions +for GUS (above). + + +For more info about using OSSlib contact hannu@opensound.com diff --git a/lib/libOSSlib/compile.sh b/lib/libOSSlib/compile.sh new file mode 100644 index 0000000..0a03b1b --- /dev/null +++ b/lib/libOSSlib/compile.sh @@ -0,0 +1,81 @@ +#!/bin/sh +MAKE=$4 + +case `uname` in + +"Linux") + $MAKE libOSSlib.so + ;; + +"FreeBSD") + $MAKE libOSSlib.so + ;; + +"OSF1") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"NetBSD") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"OpenBSD") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"BSD/OS") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"AIX") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"HP-UX") + $MAKE libOSSlib.a CC=$2 CFLAGS=$3 + ;; + +"LynxOS") + $MAKE AROPTS=rcs libOSSlib.a CFLAGS="" + ;; + +"UNIX_SV") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"UnixWare") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"OpenUNIX") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"SCO_SV") + $MAKE libOSSlib.a INSTALLLIB="$1" CFLAGS="" + ;; + +"SunOS") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"PowerMAX_OS") + $MAKE libOSSlib.a CFLAGS="" + ;; +"DragonFly") + $MAKE libOSSlib.a CFLAGS="" + ;; + +"BeOS"|"Haiku") + $MAKE libOSSlib.a CFLAGS="" + ;; + +*) + echo Can\'t recognize your operating system '('`uname`')'. + echo;echo + echo use $MAKE libOSSlib.so or $MAKE libOSSlib.a to build OSSlib + exit 0 + +esac + +exit 0 diff --git a/lib/libOSSlib/gmidi.h b/lib/libOSSlib/gmidi.h new file mode 100644 index 0000000..bc196a9 --- /dev/null +++ b/lib/libOSSlib/gmidi.h @@ -0,0 +1,259 @@ +char patch_names[][9] = { + /* 0 */ "acpiano", + /* 1 */ "britepno", + /* 2 */ "synpiano", + /* 3 */ "honky", + /* 4 */ "epiano1", + /* 5 */ "epiano2", + /* 6 */ "hrpschrd", + /* 7 */ "clavinet", + /* 8 */ "celeste", + /* 9 */ "glocken", + /* 10 */ "musicbox", + /* 11 */ "vibes", + /* 12 */ "marimba", + /* 13 */ "xylophon", + /* 14 */ "tubebell", + /* 15 */ "santur", + /* 16 */ "homeorg", + /* 17 */ "percorg", + /* 18 */ "rockorg", + /* 19 */ "church", + /* 20 */ "reedorg", + /* 21 */ "accordn", + /* 22 */ "harmonca", + /* 23 */ "concrtna", + /* 24 */ "nyguitar", + /* 25 */ "acguitar", + /* 26 */ "jazzgtr", + /* 27 */ "cleangtr", + /* 28 */ "mutegtr", + /* 29 */ "odguitar", + /* 30 */ "distgtr", + /* 31 */ "gtrharm", + /* 32 */ "acbass", + /* 33 */ "fngrbass", + /* 34 */ "pickbass", + /* 35 */ "fretless", + /* 36 */ "slapbas1", + /* 37 */ "slapbas2", + /* 38 */ "synbass1", + /* 39 */ "synbass2", + /* 40 */ "violin", + /* 41 */ "viola", + /* 42 */ "cello", + /* 43 */ "contraba", + /* 44 */ "marcato", + /* 45 */ "pizzcato", + /* 46 */ "harp", + /* 47 */ "timpani", + /* 48 */ "marcato", + /* 49 */ "slowstr", + /* 50 */ "synstr1", + /* 51 */ "synstr2", + /* 52 */ "choir", + /* 53 */ "doo", + /* 54 */ "voices", + /* 55 */ "orchhit", + /* 56 */ "trumpet", + /* 57 */ "trombone", + /* 58 */ "tuba", + /* 59 */ "mutetrum", + /* 60 */ "frenchrn", + /* 61 */ "hitbrass", + /* 62 */ "synbras1", + /* 63 */ "synbras2", + /* 64 */ "sprnosax", + /* 65 */ "altosax", + /* 66 */ "tenorsax", + /* 67 */ "barisax", + /* 68 */ "oboe", + /* 69 */ "englhorn", + /* 70 */ "bassoon", + /* 71 */ "clarinet", + /* 72 */ "piccolo", + /* 73 */ "flute", + /* 74 */ "recorder", + /* 75 */ "woodflut", + /* 76 */ "bottle", + /* 77 */ "shakazul", + /* 78 */ "whistle", + /* 79 */ "ocarina", + /* 80 */ "sqrwave", + /* 81 */ "sawwave", + /* 82 */ "calliope", + /* 83 */ "chiflead", + /* 84 */ "voxlead", + /* 85 */ "voxlead", + /* 86 */ "lead5th", + /* 87 */ "basslead", + /* 88 */ "fantasia", + /* 89 */ "warmpad", + /* 90 */ "polysyn", + /* 91 */ "ghostie", + /* 92 */ "bowglass", + /* 93 */ "metalpad", + /* 94 */ "halopad", + /* 95 */ "sweeper", + /* 96 */ "aurora", + /* 97 */ "soundtrk", + /* 98 */ "crystal", + /* 99 */ "atmosphr", + /* 100 */ "freshair", + /* 101 */ "unicorn", + /* 102 */ "sweeper", + /* 103 */ "startrak", + /* 104 */ "sitar", + /* 105 */ "banjo", + /* 106 */ "shamisen", + /* 107 */ "koto", + /* 108 */ "kalimba", + /* 109 */ "bagpipes", + /* 110 */ "fiddle", + /* 111 */ "shannai", + /* 112 */ "carillon", + /* 113 */ "agogo", + /* 114 */ "steeldrm", + /* 115 */ "woodblk", + /* 116 */ "taiko", + /* 117 */ "toms", + /* 118 */ "syntom", + /* 119 */ "revcym", + /* 120 */ "fx-fret", + /* 121 */ "fx-blow", + /* 122 */ "seashore", + /* 123 */ "jungle", + /* 124 */ "telephon", + /* 125 */ "helicptr", + /* 126 */ "applause", + /* 127 */ "pistol", + + "", /* 128 = drum 0 */ + "", /* 129 = drum 1 */ + "", /* 130 = drum 2 */ + "", /* 131 = drum 3 */ + "", /* 132 = drum 4 */ + "", /* 133 = drum 5 */ + "", /* 134 = drum 6 */ + "", /* 135 = drum 7 */ + "", /* 136 = drum 8 */ + "", /* 137 = drum 9 */ + "", /* 138 = drum 10 */ + "", /* 139 = drum 11 */ + "", /* 140 = drum 12 */ + "", /* 141 = drum 13 */ + "", /* 142 = drum 14 */ + "", /* 143 = drum 15 */ + "", /* 144 = drum 16 */ + "", /* 145 = drum 17 */ + "", /* 146 = drum 18 */ + "", /* 147 = drum 19 */ + "", /* 148 = drum 20 */ + "", /* 149 = drum 21 */ + "", /* 150 = drum 22 */ + "", /* 151 = drum 23 */ + "", /* 152 = drum 24 */ + "", /* 153 = drum 25 */ + "", /* 154 = drum 26 */ + "highq", /* 155 = drum 27 */ + "slap", /* 156 = drum 28 */ + "scratch1", /* 157 = drum 29 */ + "scratch2", /* 158 = drum 30 */ + "sticks", /* 159 = drum 31 */ + "sqrclick", /* 160 = drum 32 */ + "metclick", /* 161 = drum 33 */ + "metbell", /* 162 = drum 34 */ + "kick1", /* 163 = drum 35 */ + "kick2", /* 164 = drum 36 */ + "stickrim", /* 165 = drum 37 */ + "snare1", /* 166 = drum 38 */ + "claps", /* 167 = drum 39 */ + "snare2", /* 168 = drum 40 */ + "tomlo2", /* 169 = drum 41 */ + "hihatcl", /* 170 = drum 42 */ + "tomlo1", /* 171 = drum 43 */ + "hihatpd", /* 172 = drum 44 */ + "tommid2", /* 173 = drum 45 */ + "hihatop", /* 174 = drum 46 */ + "tommid1", /* 175 = drum 47 */ + "tomhi2", /* 176 = drum 48 */ + "cymcrsh1", /* 177 = drum 49 */ + "tomhi1", /* 178 = drum 50 */ + "cymride1", /* 179 = drum 51 */ + "cymchina", /* 180 = drum 52 */ + "cymbell", /* 181 = drum 53 */ + "tamborin", /* 182 = drum 54 */ + "cymsplsh", /* 183 = drum 55 */ + "cowbell", /* 184 = drum 56 */ + "cymcrsh2", /* 185 = drum 57 */ + "vibslap", /* 186 = drum 58 */ + "cymride2", /* 187 = drum 59 */ + "bongohi", /* 188 = drum 60 */ + "bongolo", /* 189 = drum 61 */ + "congahi1", /* 190 = drum 62 */ + "congahi2", /* 191 = drum 63 */ + "congalo", /* 192 = drum 64 */ + "timbaleh", /* 193 = drum 65 */ + "timbalel", /* 194 = drum 66 */ + "agogohi", /* 195 = drum 67 */ + "agogolo", /* 196 = drum 68 */ + "cabasa", /* 197 = drum 69 */ + "maracas", /* 198 = drum 70 */ + "whistle1", /* 199 = drum 71 */ + "whistle2", /* 200 = drum 72 */ + "guiro1", /* 201 = drum 73 */ + "guiro2", /* 202 = drum 74 */ + "clave", /* 203 = drum 75 */ + "woodblk1", /* 204 = drum 76 */ + "woodblk2", /* 205 = drum 77 */ + "cuica1", /* 206 = drum 78 */ + "cuica2", /* 207 = drum 79 */ + "triangl1", /* 208 = drum 80 */ + "triangl2", /* 209 = drum 81 */ + "shaker", /* 210 = drum 82 */ + "jingles", /* 211 = drum 83 */ + "belltree", /* 212 = drum 84 */ + "castinet", /* 213 = drum 85 */ + "surdo1", /* 214 = drum 86 */ + "surdo2", /* 215 = drum 87 */ + "", /* 216 = drum 88 */ + "", /* 217 = drum 89 */ + "", /* 218 = drum 90 */ + "", /* 219 = drum 91 */ + "", /* 220 = drum 92 */ + "", /* 221 = drum 93 */ + "", /* 222 = drum 94 */ + "", /* 223 = drum 95 */ + "", /* 224 = drum 96 */ + "", /* 225 = drum 97 */ + "", /* 226 = drum 98 */ + "", /* 227 = drum 99 */ + "", /* 228 = drum 100 */ + "", /* 229 = drum 101 */ + "", /* 230 = drum 102 */ + "", /* 231 = drum 103 */ + "", /* 232 = drum 104 */ + "", /* 233 = drum 105 */ + "", /* 234 = drum 106 */ + "", /* 235 = drum 107 */ + "", /* 236 = drum 108 */ + "", /* 237 = drum 109 */ + "", /* 238 = drum 110 */ + "", /* 239 = drum 111 */ + "", /* 240 = drum 112 */ + "", /* 241 = drum 113 */ + "", /* 242 = drum 114 */ + "", /* 243 = drum 115 */ + "", /* 244 = drum 116 */ + "", /* 245 = drum 117 */ + "", /* 246 = drum 118 */ + "", /* 247 = drum 119 */ + "", /* 248 = drum 120 */ + "", /* 249 = drum 121 */ + "", /* 250 = drum 122 */ + "", /* 251 = drum 123 */ + "", /* 252 = drum 124 */ + "", /* 253 = drum 125 */ + "", /* 254 = drum 126 */ + "" /* 255 = drum 127 */ +}; diff --git a/lib/libOSSlib/libmain.c b/lib/libOSSlib/libmain.c new file mode 100644 index 0000000..d295874 --- /dev/null +++ b/lib/libOSSlib/libmain.c @@ -0,0 +1,200 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#define OSSLIB +#include "../../include/soundcard.h" + +int __seqfd = -1; +static int initialized = 0; + +extern void _dump_midi (void); /* From play_event.c */ + +unsigned char *_seqbuf; +int _seqbuflen = 0; +int _seqbufptr = 0; + +int synth_types[64] = { 0 }; + +#define ST_NONE 0 +#define ST_GUS 1 +#define ST_OPL 2 + +int nrsynths = 0; + +extern void play_event (unsigned char *ev); + +void +seqbuf_dump (void) +{ + int l = _seqbufptr; + + unsigned char *ev = _seqbuf; + + while (l >= 8) + { + play_event (ev); + l -= 8; + ev += 8; + } + + _seqbufptr = 0; + _dump_midi (); +} + +static int +oss_init_lib (void) +{ + if (_seqbuflen < 32 || _seqbuflen > 2048) + _seqbuflen = 2048; + + if ((_seqbuf = malloc (_seqbuflen)) == NULL) + return 3; + + initialized = 1; + return 0; /* OK */ +} + +int +OSS_init (int userfd, int buflen) +{ + if (_seqbuflen || _seqbuflen || __seqfd != -1 || initialized) + { + fprintf (stderr, "libOSS: OSS_init called too late\n"); + return 1; + } + + __seqfd = userfd; + + if (buflen < 32 || buflen > 2048) + { + fprintf (stderr, "libOSS: OSS_init called with invalid buflen\n"); + return 2; + } + + _seqbuflen = buflen; + + return oss_init_lib (); +} + +static void +sanity_check (int fd, unsigned char *buf, int buflen) +{ + if (__seqfd != fd) + if (__seqfd == -1) + __seqfd = fd; + else + { + fprintf (stderr, "OSSlib: seqfd is inconsistent\n"); + } + + if (buf != _seqbuf) + { + fprintf (stderr, "OSSlib: _seqbuf is inconsistent\n"); + } + + if (buflen != _seqbuflen) + { + fprintf (stderr, "OSSlib: _seqbuf is inconsistent\n"); + } + + if (!initialized) + if (oss_init_lib () != 0) + { + fprintf (stderr, "OSSlib: Library initialization failed\n"); + exit (-1); + } +} + +void +OSS_seqbuf_dump (int fd, unsigned char *buf, int buflen) +{ + seqbuf_dump (); +} + +void +OSS_seq_advbuf (int len, int fd, unsigned char *buf, int buflen) +{ + sanity_check (fd, buf, buflen); + _seqbufptr += len; +} + +void +OSS_seq_needbuf (int len, int fd, unsigned char *buf, int buflen) +{ + sanity_check (fd, buf, buflen); + + if ((_seqbufptr + len) > _seqbuflen) + { + seqbuf_dump (); + } +} + +void +OSS_patch_caching (int dev, int chn, int patch, int fd, unsigned char *buf, + int buflen) +{ +} + +void +OSS_drum_caching (int dev, int chn, int patch, int fd, unsigned char *buf, + int buflen) +{ +} + +void +OSS_write_patch (int fd, unsigned char *buf, int len) +{ + sanity_check (fd, _seqbuf, _seqbuflen); + + if (write (fd, buf, len) == -1) + { + perror ("OSS_write_patch"); + exit (-1); + } +} + +int +OSS_write_patch2 (int fd, unsigned char *buf, int len) +{ + sanity_check (fd, _seqbuf, _seqbuflen); + + return write (fd, buf, len); +} + +/* + * audio routines + */ + +int +osslib_open (const char *path, int flags, int dummy) +{ + return open (path, flags, dummy); +} + +void +osslib_close (int fd) +{ + close (fd); +} + +int +osslib_write (int fd, const void *buf, int count) +{ + return write (fd, buf, count); +} + +int +osslib_read (int fd, void *buf, int count) +{ + return read (fd, buf, count); +} + +int +osslib_ioctl (int fd, unsigned int request, void *arg) +{ + return ioctl (fd, request, arg); +} diff --git a/lib/libOSSlib/midiparser.c b/lib/libOSSlib/midiparser.c new file mode 100644 index 0000000..742e8f5 --- /dev/null +++ b/lib/libOSSlib/midiparser.c @@ -0,0 +1,401 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../../include/soundcard.h" +#include "midiparser.h" + +struct _mtc_state +{ + int prev_ix; + int state; + int offset; + oss_mtc_data_t mtc, mtc0; +}; + +typedef struct midi_input_info +{ /* MIDI input scanner variables */ +#define MI_MAX 64 + int m_busy; + unsigned char m_buf[MI_MAX]; + unsigned char m_prev_status; /* For running status */ + int m_ptr; +#define MST_INIT 0 +#define MST_DATA 1 +#define MST_SYSEX 2 + int m_state; + int m_left; + int m_f1_flag; +} midi_input_info_t; + +struct midiparser_common +{ + midi_input_info_t inc; + midiparser_callback_t callback; + midiparser_mtc_callback_t mtc_callback; + void *client_context; + struct _mtc_state mtc_state; +}; + +#define DBG(x) {} + +#define CALLBACK(cat, msg, ch, p1, p2, p3) \ + { \ + unsigned char arr[3];arr[0]=p1;arr[1]=p2;arr[2]=p3; \ + synth->callback(synth->client_context, cat, msg, ch, arr, 3); \ + } +#define CALLBACK_A(cat, msg, ch, parms, len) \ + synth->callback(synth->client_context, cat, msg, ch, parms, len) + +void +do_system_msg (midiparser_common_p synth, unsigned char *msg, int mlen) +{ + DBG (printf ("System msg %02x, %02x (%d)\n", msg[0], msg[1], mlen)); + CALLBACK_A (CAT_REALTIME, *msg, 0, msg, mlen); + return; +} + +static void +do_sysex_msg (midiparser_common_p synth, unsigned char *msg, int mlen) +{ + CALLBACK_A (CAT_SYSEX, 0, 0, msg, mlen); + return; +} + +static void +do_realtime_msg (midiparser_common_p synth, unsigned char data) +{ +} + +void +do_midi_msg (midiparser_common_p synth, unsigned char *msg, int mlen) +{ + switch (msg[0] & 0xf0) + { + case 0x90: + if (msg[2] != 0) + { + CALLBACK (CAT_VOICE, 0x90, msg[0] & 0x0f, msg[1], msg[2], 0); + break; + } + msg[2] = 64; + + case 0x80: + CALLBACK (CAT_VOICE, 0x80, msg[0] & 0x0f, msg[1], msg[2], 0); + break; + + case 0xA0: + CALLBACK (CAT_VOICE, 0xA0, msg[0] & 0x0f, msg[1], msg[2], 0); + break; + + case 0xB0: + CALLBACK (CAT_CHN, 0xB0, msg[0] & 0x0f, msg[1], msg[2], 0); + break; + + case 0xC0: + CALLBACK (CAT_CHN, 0xC0, msg[0] & 0x0f, msg[1], 0, 0); + break; + + case 0xD0: + CALLBACK (CAT_CHN, 0xD0, msg[0] & 0x0f, msg[1], 0, 0); + break; + + case 0xE0: + CALLBACK (CAT_VOICE, 0xE0, msg[0] & 0x0f, msg[1], msg[2], 0); + break; + + case 0xf0: /* System common messages */ + do_system_msg (synth, msg, mlen); + break; + + default: + ; + } +} + +static void +send_mtc (midiparser_common_p synth, struct _mtc_state *st) +{ + oss_mtc_data_t mtc; + + memcpy (&mtc, &st->mtc, sizeof (mtc)); + + mtc.qframes += st->offset; + mtc.frames += mtc.qframes / 4; + mtc.qframes %= 4; + + if (mtc.time_code_type == 0) + mtc.time_code_type = 30; + mtc.seconds += mtc.frames / mtc.time_code_type; /* TODO: Handle drop frames */ + mtc.frames %= mtc.time_code_type; + + mtc.minutes += mtc.seconds / 60; + mtc.seconds %= 60; + + mtc.hours += mtc.minutes / 60; + mtc.minutes %= 60; + +#if 0 + printf ("%2d:%02d:%02d %02d.%d %2dFPS\n", + mtc.hours, mtc.minutes, + mtc.seconds, mtc.frames, mtc.qframes, mtc.time_code_type); +#endif + + synth->mtc_callback (synth->client_context, &mtc); +} + +void +mtc_message (midiparser_common_p synth, struct _mtc_state *st, + unsigned char b) +{ + static char frame_types[4] = { 24, 25, 29, 30 }; + int ix, data; + int previx; + + ix = b >> 4; + data = b & 0x0f; + + previx = (st->prev_ix + 1) % 8; + + if (ix == previx) + st->mtc0.direction = st->mtc.direction = MTC_DIR_FORWARD; + else if (ix == st->prev_ix) + st->mtc0.direction = st->mtc.direction = MTC_DIR_STOPPED; + else + st->mtc0.direction = st->mtc.direction = MTC_DIR_BACKWARD; + st->prev_ix = ix; + + if (st->state == 0) + { + if (ix != 0) /* Not the beginning of the sequence yet */ + return; + st->state = 1; + st->offset = -1; + } + + switch (ix) + { + case 0: /* Frame count LS nibble */ + st->mtc0.qframes = 0; + st->mtc0.frames = data; + break; + + case 1: /* Frame count MS nibble */ + st->mtc0.frames |= data << 4; + break; + + case 2: /* Seconds count LS nibble */ + st->mtc0.seconds = data; + break; + + case 3: /* Seconds count MS nibble */ + st->mtc0.seconds |= data << 4; + break; + + case 4: /* Minutes count LS nibble */ + st->mtc0.minutes = data; + break; + + case 5: /* Minutes count MS nibble */ + st->mtc0.minutes |= data << 4; + break; + + case 6: /* Hours count LS nibble */ + st->mtc0.hours = data; + break; + + case 7: /* Hours count MS nibble */ + st->mtc0.hours |= data << 4; + st->mtc0.time_code_type = frame_types[(st->mtc0.hours >> 5) & 0x03]; + st->mtc0.hours &= 0x1f; + memcpy (&st->mtc, &st->mtc0, sizeof (st->mtc)); + break; + } + + if (ix == 7) + st->offset = 7; + else + st->offset++; + send_mtc (synth, st); +} + +static void +handle_midi_input (midiparser_common_p synth, midi_input_info_t * inc, + unsigned char data) +{ + extern int seq_actsense_enable; + extern int seq_rt_enable; + + static unsigned char len_tab[] = /* # of data bytes following a status + */ + { + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ + }; + /* printf("%02x (%d) ", data, inc->m_state); */ + + if (data == 0xfe) /* Active sensing */ + { + return; + } + + if (data >= 0xf8) /* Real time message */ + { + do_realtime_msg (synth, data); + CALLBACK (CAT_REALTIME, data, 0, 0, 0, 0); + return; + } + + if (data == 0xf1) /* MTC quarter frame (1st byte) */ + { + inc->m_f1_flag = 1; + return; + } + + if (inc->m_f1_flag) /* MTC quarter frame (2nd byte) */ + { + inc->m_f1_flag = 0; + + if (synth->mtc_callback != NULL) + { + mtc_message (synth, &synth->mtc_state, data); + return; + } + CALLBACK (CAT_MTC, 0xf1, 0, data, 0, 0); + return; + } + + switch (inc->m_state) + { + case MST_INIT: + if (data & 0x80) /* MIDI status byte */ + { + if ((data & 0xf0) == 0xf0) /* Common message */ + { + switch (data) + { + case 0xf0: /* Sysex */ + inc->m_state = MST_SYSEX; + inc->m_ptr = 1; + inc->m_left = MI_MAX; + inc->m_buf[0] = data; + break; /* Sysex */ + + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* Song select */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 1; + inc->m_buf[0] = data; + break; + + case 0xf2: /* Song position pointer */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 2; + inc->m_buf[0] = data; + break; + + default: /* Other common messages */ + inc->m_buf[0] = data; + inc->m_ptr = 1; + do_midi_msg (synth, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + inc->m_left = 0; + } + } + else + { + /* Channel messages */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = len_tab[(data >> 4) - 8]; + inc->m_buf[0] = inc->m_prev_status = data; + } + } + else /* Running status */ if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ + { + inc->m_state = MST_DATA; + inc->m_ptr = 2; + inc->m_left = len_tab[(inc->m_prev_status >> 4) - 8] - 1; + inc->m_buf[0] = inc->m_prev_status; + inc->m_buf[1] = data; + } + break; /* MST_INIT */ + + case MST_DATA: + inc->m_buf[inc->m_ptr++] = data; + if (--inc->m_left <= 0) + { + inc->m_state = MST_INIT; + do_midi_msg (synth, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } + break; /* MST_DATA */ + + case MST_SYSEX: + inc->m_buf[inc->m_ptr++] = data; + if (data == 0xf7) /* Sysex end */ + { + do_sysex_msg (synth, inc->m_buf, inc->m_ptr); + inc->m_state = MST_INIT; + inc->m_left = 0; + inc->m_ptr = 0; + + } + else if (inc->m_ptr >= MI_MAX) /* Overflow protection */ + { + do_sysex_msg (synth, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } + + break; /* MST_SYSEX */ + + default: + inc->m_state = MST_INIT; + } +} + +midiparser_common_p +midiparser_create (midiparser_callback_t callback, void *context) +{ + midiparser_common_p synth; + + if ((synth = malloc (sizeof (*synth))) == NULL) + return NULL; + + memset (synth, 0, sizeof (*synth)); + + synth->callback = callback; + synth->client_context = context; + synth->mtc_state.prev_ix = -1; + + return synth; +} + +void +midiparser_mtc_callback (midiparser_common_p common, + midiparser_mtc_callback_t callback) +{ + common->mtc_callback = callback; +} + +void +midiparser_input (midiparser_common_p synth, unsigned char data) +{ + handle_midi_input (synth, &synth->inc, data); +} + +void +midiparser_input_buf (midiparser_common_p synth, unsigned char *data, int len) +{ + int i; + + for (i = 0; i < len; i++) + handle_midi_input (synth, &synth->inc, data[i]); +} diff --git a/lib/libOSSlib/midiparser.h b/lib/libOSSlib/midiparser.h new file mode 100644 index 0000000..20aac3a --- /dev/null +++ b/lib/libOSSlib/midiparser.h @@ -0,0 +1 @@ +#include "../../kernel/framework/include/midiparser.h" diff --git a/lib/libOSSlib/play_event.c b/lib/libOSSlib/play_event.c new file mode 100644 index 0000000..62687ef --- /dev/null +++ b/lib/libOSSlib/play_event.c @@ -0,0 +1,273 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include "../../include/soundcard.h" +#include <sys/time.h> + +#undef DEBUG + +extern int __seqfd; + +static midi_packet_t midi_packet; + +static unsigned char *midibuf = &midi_packet.payload[0]; +static int mp = 0; + +oss_midi_time_t current_tick = 0; + +static int timer_started = 0; + +void +OSS_set_timebase (int tb) +{ +/* TODO? */ +} + +#if 1 +#define _write write +#else +static size_t +_write (int fildes, void *b, size_t nbyte) +{ + midi_packet_header_t *hdr = b; + unsigned char *buf; + int l = nbyte; + + + buf = (unsigned char *) b + sizeof (*hdr); + + if (hdr->magic == MIDI_HDR_MAGIC) /* Timed mode write */ + { + l -= sizeof (*hdr); + + switch (hdr->event_type) + { + case MIDI_EV_WRITE: + printf ("%9lu: MIDI_EV_WRITE: ", hdr->time); + break; + case MIDI_EV_TEMPO: + printf ("%9lu: MIDI_EV_TEMPO: ", hdr->time); + break; + case MIDI_EV_ECHO: + printf ("%9lu: MIDI_EV_ECHO: ", hdr->time); + break; + case MIDI_EV_START: + printf ("%9lu: MIDI_EV_START: ", hdr->time); + break; + case MIDI_EV_STOP: + printf ("%9lu: MIDI_EV_STOP: ", hdr->time); + break; + default: + printf ("%9lu: MIDI_EV_%d: ", hdr->time, hdr->event_type); + break; + } + + if (hdr->options & MIDI_OPT_TIMED) + printf ("TIMED "); + + if (l > 0) + { + int i; + + printf ("%d bytes (", l); + + for (i = 0; i < l; i++) + printf ("%02x ", buf[i]); + printf (")"); + } + + printf ("\n"); + } + + return write (fildes, b, nbyte); +} +#endif + +static void +start_timer (void) +{ +#ifndef DEBUG + midi_packet_header_t hdr; + + hdr.magic = MIDI_HDR_MAGIC; + hdr.event_type = MIDI_EV_START; + hdr.options = MIDI_OPT_NONE; + hdr.time = 0; + hdr.parm = 0; + if (_write (__seqfd, &hdr, sizeof (hdr)) != sizeof (hdr)) + { + perror ("Write start timer"); + exit (-1); + } + + timer_started = 1; + printf ("Timer started\n"); +#endif +} + +void +_dump_midi (void) +{ + if (mp > 0) + { + if (!timer_started) + start_timer (); + midi_packet.hdr.magic = MIDI_HDR_MAGIC; + midi_packet.hdr.options = MIDI_OPT_TIMED; + midi_packet.hdr.event_type = MIDI_EV_WRITE; + midi_packet.hdr.parm = 0; + midi_packet.hdr.time = current_tick; + +#ifdef DEBUG + if (write (1, &midi_packet.payload[0], mp) == -1) +#else + if (_write (__seqfd, &midi_packet, sizeof (midi_packet_header_t) + mp) + == -1) +#endif + { + perror ("MIDI write"); + exit (-1); + } + mp = 0; + } +} + +static void +oss_do_timing (unsigned char *ev) +{ + unsigned int parm = *(unsigned int *) &ev[4]; + midi_packet_header_t hdr; + + oss_midi_time_t tick; + + _dump_midi (); + + switch (ev[1]) + { + case TMR_TEMPO: +#ifndef DEBUG + if (!timer_started) + start_timer (); + hdr.magic = MIDI_HDR_MAGIC; + hdr.event_type = MIDI_EV_TEMPO; + hdr.options = MIDI_OPT_TIMED; + hdr.time = current_tick; + hdr.parm = parm; + if (_write (__seqfd, &hdr, sizeof (hdr)) != sizeof (hdr)) + { + perror ("Write tempo"); + exit (-1); + } +#endif + break; + + case TMR_WAIT_REL: + tick = current_tick + parm; + + current_tick = tick; + break; + + case TMR_WAIT_ABS: + tick = parm; + current_tick = tick; + break; + } + +} + +static void +out_midi3 (unsigned char a, unsigned char b, unsigned char c) +{ + if (mp > 950) + _dump_midi (); + midibuf[mp++] = a; + midibuf[mp++] = b; + midibuf[mp++] = c; +/* printf("Out %02x %02x %02x\n", a, b, c); */ +} + +static void +out_midi2 (unsigned char a, unsigned char b) +{ + if (mp > 950) + _dump_midi (); + midibuf[mp++] = a; + midibuf[mp++] = b; +/* printf("Out %02x %02x\n", a, b); */ +} + +void +play_event (unsigned char *ev) +{ + int i; + + switch (ev[0]) + { + case EV_TIMING: + oss_do_timing (ev); + return; + break; + + case EV_SEQ_LOCAL: + break; + + case EV_CHN_COMMON: + switch (ev[2]) + { + case MIDI_PGM_CHANGE: + /* printf("PGM change %02x %d\n", ev[2]|ev[3], ev[4]); */ + out_midi2 (ev[2] | ev[3], ev[4]); + break; + + case MIDI_CHN_PRESSURE: + out_midi2 (ev[2] | ev[3], ev[4]); + break; + + case MIDI_CTL_CHANGE: + out_midi3 (ev[2] | ev[3], ev[4], *(short *) &ev[6]); + break; + + default: + out_midi3 (ev[2] | ev[3], ev[4], *(short *) &ev[6]); + } + return; + break; + + case EV_CHN_VOICE: + out_midi3 (ev[2] | ev[3], ev[4], ev[5]); + return; + break; + + case EV_SYSEX: + { + int i, l; + l = 8; + for (i = 2; i < 8; i++) + if (ev[i] == 0xff) + { + l = i; + break; + } + if (mp > 950) + _dump_midi (); + for (i = 2; i < l; i++) + midibuf[mp++] = ev[i]; + } + return; + break; + + case EV_SYSTEM: + printf ("EV_SYSTEM: "); + break; + + default: + printf ("Unknown event %d: ", ev[0]); + + } + + for (i = 0; i < 8; i++) + printf ("%02x ", ev[i]); + printf ("\n"); +} |