Ticket #8731: scummvm-timidity.patch

File scummvm-timidity.patch, 20.4 KB (added by SF/amdmi3, 16 years ago)

Updated patch

  • sound/mididrv.h

     
    7878        MD_ADLIB,
    7979        MD_PCSPK,
    8080        MD_PCJR,
    81         MD_TOWNS
     81        MD_TOWNS,
     82        MD_TIMIDITY
    8283};
    8384
    8485/**
     
    271272extern MidiDriver *MidiDriver_ADLIB_create(Audio::Mixer *mixer);
    272273extern MidiDriver *MidiDriver_WIN_create();
    273274extern MidiDriver *MidiDriver_SEQ_create();
     275extern MidiDriver *MidiDriver_TIMIDITY_create();
    274276extern MidiDriver *MidiDriver_QT_create();
    275277extern MidiDriver *MidiDriver_CORE_create();
    276278extern MidiDriver *MidiDriver_CoreMIDI_create();
  • sound/mididrv.cpp

     
    8484        {"pcspk", "PC Speaker", MD_PCSPK, MDT_PCSPK},
    8585        {"pcjr", "IBM PCjr", MD_PCJR, MDT_PCSPK},
    8686        {"towns", "FM Towns", MD_TOWNS, MDT_TOWNS},
     87#if defined(UNIX)
     88        {"timidity", "TiMidity", MD_TIMIDITY, MDT_MIDI},
     89#endif
    8790
    8891        {0, 0, MD_NULL, MDT_NONE}
    8992};
     
    251254#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__)
    252255        case MD_SEQ:       return MidiDriver_SEQ_create();
    253256#endif
     257#if defined(UNIX)
     258        case MD_TIMIDITY:  return MidiDriver_TIMIDITY_create();
     259#endif
    254260#if defined(IRIX)
    255261        case MD_DMEDIA:    return MidiDriver_DMEDIA_create();
    256262#endif
  • README

     
    4646 * 7.4 MIDI emulation
    4747 * 7.5 Native MIDI support
    4848 * 7.6 UNIX native and ALSA sequencer support
    49  * 7.7 Using compressed audio files (MP3, Ogg Vorbis, Flac)
    50  * 7.8 Output sample rate
     49 * 7.7 TiMidity++ MIDI server support
     50 * 7.8 Using compressed audio files (MP3, Ogg Vorbis, Flac)
     51 * 7.9 Output sample rate
    51528.0) Configuration Files
    52539.0) Compiling
    5354
     
    11221123                     a hardware MIDI synthesizer.
    11231124        qt         - Quicktime sound, for Macintosh users.
    11241125        seq        - Use /dev/sequencer for MIDI, *nix users. See below.
     1126        timidity   - Connect to TiMidity++ MIDI server. See below.
    11251127        windows    - Windows MIDI. Uses built-in sequencer, for Windows users
    11261128
    11271129To select a sound driver, select it in the Launcher, or pass its name
     
    12251227MIDI music with Adlib sound effects.
    12261228
    12271229
    1228 7.6.0) Playing sound with Sequencer MIDI:                        [UNIX ONLY]
    1229 ------ ----------------------------------
     12307.6) Playing sound with Sequencer MIDI:                          [UNIX ONLY]
     1231---- ----------------------------------
    12301232If your soundcard driver supports a sequencer, you may set the environment
    12311233variable "SCUMMVM_MIDI" to your sequencer device -- for example, to
    12321234/dev/sequencer
     
    12891291command as described earlier in this section.
    12901292
    12911293
    1292 7.7.0) Using MP3 files for CD audio:
     12947.7) Using TiMidity++ MIDI server:
     1295---- -----------------------------
     1296If you system lacks any MIDI sequencer, but you still want better MIDI quality
     1297than default Adlib emulation can offer, you can try TiMidity++ MIDI server. See
     1298http://timidity.sourceforge.net/ for download and install instructions.
     1299
     1300First, you need to start a daemon:
     1301
     1302timidity -ir 7777
     1303
     1304Now you can start scummvm and try selection TiMidity music output.  By default,
     1305it will connect to localhost:7777, but you can change host/port by defining
     1306"TIMIDITY_HOST" environment variable.
     1307
     1308
     13097.8) Using compressed audio files
     1310---- ----------------------------
     1311
     13127.8.0) Using MP3 files for CD audio:
    12931313------ -----------------------------
    12941314Use LAME or some other MP3 encoder to rip the cd audio tracks to files. Name
    12951315the files track1.mp3 track2.mp3 etc. ScummVM must be compiled with MAD support
     
    13001320  lame -t -q 0 -b 96 track1.wav track1.mp3
    13011321
    13021322
    1303 7.7.1) Using Ogg Vorbis files for CD audio:
     13237.8.1) Using Ogg Vorbis files for CD audio:
    13041324------ ------------------------------------
    13051325Use oggenc or some other vorbis encoder to encode the audio tracks to files.
    13061326Name the files track1.ogg track2.ogg etc. ScummVM must be compiled with vorbis
     
    13121332  oggenc -q 5 track1.wav
    13131333
    13141334
    1315 7.7.2) Using Flac files for CD audio:
     13357.8.2) Using Flac files for CD audio:
    13161336------ ------------------------------------
    13171337Use flac or some other flac encoder to encode the audio tracks to files.
    13181338Name the files track1.flac track2.flac etc. In your filesystem only allows
     
    13271347affect the encoding time and resulting filesize.
    13281348
    13291349
    1330 7.7.3) Compressing MONSTER.SOU with MP3:
     13507.8.3) Compressing MONSTER.SOU with MP3:
    13311351------ ---------------------------------
    13321352You need LAME, and our 'compress_scumm_sou' utility from the scummvm-tools
    13331353package to perform this task, and ScummVM must be compiled with MAD support.
     
    13381358to your game directory. You can safely remove the monster.sou file.
    13391359
    13401360
    1341 7.7.4) Compressing MONSTER.SOU with Ogg Vorbis:
     13617.8.4) Compressing MONSTER.SOU with Ogg Vorbis:
    13421362------ ----------------------------------------
    13431363As above, but ScummVM must be compiled with OGG support. Run:
    13441364
     
    13491369than MP3, so have a good book handy.
    13501370
    13511371
    1352 7.7.5) Compressing MONSTER.SOU with Flac:
     13727.8.5) Compressing MONSTER.SOU with Flac:
    13531373------ ----------------------------------------
    13541374As above, but ScummVM must be compiled with Flac support. Run:
    13551375
     
    13631383to read the encoder documentation before you use other values.
    13641384
    13651385
    1366 7.7.6) Compressing music/sfx/speech in AGOS games
     13867.8.6) Compressing music/sfx/speech in AGOS games
    13671387------ -----------------------------------------------------------------
    13681388Use our 'compress_agos' utility from the scummvm-tools package to perform this
    13691389task. You can choose between multiple target formats, but note that you can
     
    13981418file to your game directory. You can safely remove the old file.
    13991419
    14001420
    1401 7.7.7) Compressing speech/music in Broken Sword 1
     14217.8.7) Compressing speech/music in Broken Sword 1
    14021422------ ------------------------------------------
    14031423The 'compress_sword1' tool from the scummvm-tools package can encode music and
    14041424speech to MP3 as well as Ogg Vorbis.
     
    14171437Use "compress_sword1 --help" to get a full list of the options.
    14181438
    14191439
    1420 7.7.8) Compressing speech/music in Broken Sword 2
     14407.8.8) Compressing speech/music in Broken Sword 2
    14211441------ ------------------------------------------
    14221442Use our 'compress_sword2' utility from the scummvm-tools package to perform this
    14231443task. You can choose between multiple target formats, but note  that you can
     
    14421462nor will it work with the speech files from Broken Sword 1.
    14431463
    14441464
    1445 7.8) Output sample rate:
     14657.9) Output sample rate:
    14461466---- -------------------
    14471467The output sample rate tells ScummVM how many sound samples to play per channel
    14481468per second. There is much that could be said on this subject, but most of it
  • backends/midi/timidity.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 */
     24
     25/*
     26 * Output to TiMidity++ MIDI server support
     27 *                            by Dmitry Marakasov <amdmi3@amdmi3.ru>
     28 * based on:
     29 * - Raw output support (seq.cpp) by Michael Pearce
     30 * - Pseudo /dev/sequencer of TiMidity (timidity-io.c)
     31 *                                 by Masanao Izumo <mo@goice.co.jp>
     32 * - sys/soundcard.h by Hannu Savolainen (got from my FreeBSD
     33 *   distribution, for which it was modified by Luigi Rizzo)
     34 *
     35 */
     36
     37#if defined (UNIX)
     38
     39#include "sound/mpu401.h"
     40#include "common/util.h"
     41
     42#include <fcntl.h>
     43#include <unistd.h>
     44#include <stdio.h>
     45#include <string.h>
     46#include <sys/types.h>
     47#include <sys/socket.h>
     48#include <sys/param.h>
     49#include <netdb.h>              /* for gethostbyname */
     50#include <netinet/in.h>
     51#include <arpa/inet.h>
     52#include <stdarg.h>
     53#include <stdlib.h>
     54#include <errno.h>
     55
     56#define SEQ_MIDIPUTC 5
     57
     58#define TIMIDITY_LOW_DELAY
     59
     60#ifdef TIMIDITY_LOW_DELAY
     61#define BUF_LOW_SYNC    0.1
     62#define BUF_HIGH_SYNC   0.15
     63#else
     64#define BUF_LOW_SYNC    0.4
     65#define BUF_HIGH_SYNC   0.8
     66#endif
     67
     68/* default host & port */
     69#define DEFAULT_TIMIDITY_HOST "127.0.0.1"
     70#define DEFAULT_TIMIDITY_PORT 7777
     71
     72class MidiDriver_TIMIDITY : public MidiDriver_MPU401 {
     73public:
     74        MidiDriver_TIMIDITY();
     75
     76        int     open();
     77        void    close();
     78        void    send(uint32 b);
     79        void    sysEx(const byte *msg, uint16 length);
     80
     81private:
     82        /* standart routine to extract ip address from a string */
     83        in_addr_t       host_to_addr(const char* address);
     84
     85        /* creates a tcp connection to TiMidity server, returns filedesc (like open()) */
     86        int     connect_to_server(const char* hostname, unsigned short tcp_port);
     87
     88        /* send command to the server; printf-like; returns reply string */
     89        char    *timidity_ctl_command(const char *fmt, ...);
     90
     91        /* timidity data socket-related stuff */
     92        void    timidity_meta_seq(int p1, int p2, int p3);
     93        int     timidity_sync(int centsec);
     94        int     timidity_eot();
     95
     96        /* write() analogue for any midi data */
     97        void    timidity_write_data(const void *buf, size_t nbytes);
     98
     99        /* get single line of server reply on control connection */
     100        int     fdgets(char *buff, size_t buff_size);
     101
     102        /* teardown connection to server */
     103        void    teardown();
     104
     105        /* close (if needed) and nullify both control and data filedescs */
     106        void    close_all();
     107
     108private:
     109        bool    _isOpen;
     110        int     _device_num;
     111
     112        int     _control_fd;
     113        int     _data_fd;
     114
     115        /* buffer for partial data read from _control_fd - from timidity-io.c, see fdgets() */
     116        char    _controlbuffer[BUFSIZ];
     117        int     _controlbuffer_count;   /* beginning of read pointer */
     118        int     _controlbuffer_size;    /* end of read pointer */
     119};
     120
     121MidiDriver_TIMIDITY::MidiDriver_TIMIDITY() {
     122        _isOpen = false;
     123        _device_num = 0;
     124
     125        /* init fd's */
     126        _control_fd = _data_fd = -1;
     127
     128        /* init buffer for control connection */
     129        _controlbuffer_count = _controlbuffer_size = 0;
     130}
     131
     132int MidiDriver_TIMIDITY::open() {
     133        char    *res;
     134        char    timidity_host[MAXHOSTNAMELEN];
     135        int     timidity_port, data_port, i;
     136
     137        /* count ourselves open */
     138        if (_isOpen)
     139                return MERR_ALREADY_OPEN;
     140        _isOpen = true;
     141
     142        /* get server hostname; if not specified in env, use default */
     143        if ((res = getenv("TIMIDITY_HOST")) == NULL)
     144                strncpy(timidity_host, DEFAULT_TIMIDITY_HOST, MAXHOSTNAMELEN);
     145        else
     146                strncpy(timidity_host, res, sizeof(timidity_host));
     147
     148        timidity_host[sizeof(timidity_host) - 1] = '\0';
     149
     150        /* extract control port */
     151        if ((res = strrchr(timidity_host, ':')) != NULL) {
     152                *res++ = '\0';
     153                timidity_port = atoi(res);
     154        } else {
     155                timidity_port = DEFAULT_TIMIDITY_PORT;
     156        }
     157
     158        /*
     159         * create control connection to the server
     160         */
     161        if ((_control_fd = connect_to_server(timidity_host, timidity_port)) < 0) {
     162                warning("TiMidity: can't open control connection (host=%s, port=%d)", timidity_host, timidity_port);
     163                return -1;
     164        }
     165
     166        /* should read greeting issued by server upon connect:
     167         * "220 TiMidity++ v2.13.2 ready)" */
     168        res = timidity_ctl_command(NULL);
     169        if (atoi(res) != 220) {
     170                warning("TiMidity: bad response from server (host=%s, port=%d): %s", timidity_host, timidity_port, res);
     171                close_all();
     172                return -1;
     173        }
     174
     175        /*
     176         * setup buf and prepare data connection
     177         */
     178        /* should read: "200 OK" */
     179        res = timidity_ctl_command("SETBUF %f %f", BUF_LOW_SYNC, BUF_HIGH_SYNC);
     180        if (atoi(res) != 200)
     181                warning("TiMidity: bad reply for SETBUF command: %s", res);
     182
     183        /* should read something like "200 63017 is ready acceptable",
     184         * where 63017 is port for data connection */
     185        i = 1;
     186        if (*(char *)&i == 1)
     187                res = timidity_ctl_command("OPEN lsb");
     188        else
     189                res = timidity_ctl_command("OPEN msb");
     190
     191        if (atoi(res) != 200) {
     192                warning("TiMidity: bad reply for OPEN command: %s", res);
     193                close_all();
     194                return -1;
     195        }
     196
     197        /*
     198         * open data connection
     199         */
     200        data_port = atoi(res + 4);
     201        if ((_data_fd = connect_to_server(timidity_host, data_port)) < 0) {
     202                warning("TiMidity: can't open data connection (host=%s, port=%d)", timidity_host, data_port);
     203                close_all();
     204                return -1;
     205        }
     206
     207        /* should read message issued after connecting to data port:
     208         * "200 Ready data connection" */
     209        res = timidity_ctl_command(NULL);
     210        if (atoi(res) != 200) {
     211                fprintf(stderr, "Can't connect timidity: %s\t(host=%s, port=%d)\n", res, timidity_host, data_port);
     212                close_all();
     213                return -1;
     214        }
     215
     216        /*
     217         * From seq.cpp
     218         */
     219        if (getenv("SCUMMVM_MIDIPORT"))
     220                _device_num = atoi(getenv("SCUMMVM_MIDIPORT"));
     221
     222        return 0;
     223}
     224
     225void MidiDriver_TIMIDITY::close() {
     226        teardown();
     227
     228        MidiDriver_MPU401::close();
     229        _isOpen = false;
     230}
     231
     232void MidiDriver_TIMIDITY::close_all() {
     233        if (_control_fd >= 0)
     234                ::close(_control_fd);
     235
     236        if (_data_fd >= 0)
     237                ::close(_data_fd);
     238
     239        _control_fd = _data_fd = -1;
     240}
     241
     242void MidiDriver_TIMIDITY::teardown() {
     243        char *res;
     244
     245        /* teardown connection to server (see timidity-io.c) if it
     246         * is initialized */
     247        if (_data_fd >= 0 && _control_fd >= 0) {
     248                timidity_eot();
     249                timidity_sync(0);
     250
     251                /* scroll through all "302 Data connection is (already) closed"
     252                 * messages till we reach something like "200 Bye" */
     253                do {
     254                        res = timidity_ctl_command("QUIT");
     255                } while(*res && atoi(res) && atoi(res) != 302);
     256        }
     257
     258        /* now close and nullify both filedescs */
     259        close_all();
     260}
     261
     262in_addr_t MidiDriver_TIMIDITY::host_to_addr(const char* address) {
     263        in_addr_t addr;
     264        struct hostent *hp;
     265
     266        /* first check if IP address is given (like 127.0.0.1)*/
     267        if ((addr = inet_addr(address)) != INADDR_NONE)
     268                return addr;
     269
     270        /* if not, try to resolve a hostname */
     271        if ((hp = gethostbyname(address)) == NULL) {
     272                warning("TiMidity: unknown hostname: %s\n", address);
     273                return INADDR_NONE;
     274        }
     275
     276        memcpy(&addr, hp->h_addr, (int)sizeof(in_addr_t) <= hp->h_length ? sizeof(in_addr_t) : hp->h_length);
     277
     278        return addr;
     279}
     280
     281int MidiDriver_TIMIDITY::connect_to_server(const char* hostname, unsigned short tcp_port) {
     282        int fd;
     283        struct sockaddr_in in;
     284        unsigned int addr;
     285
     286        /* create socket */
     287        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     288                warning("TiMidity: socket(): %s", strerror(errno));
     289                return -1;
     290        }
     291
     292        /* connect */
     293        memset(&in, 0, sizeof(in));
     294        in.sin_family = AF_INET;
     295        in.sin_port   = htons(tcp_port);
     296        addr = host_to_addr(hostname);
     297        memcpy(&in.sin_addr, &addr, 4);
     298
     299        if (connect(fd, (struct sockaddr *)&in, sizeof(in)) < 0) {
     300                warning("TiMidity: connect(): %s", strerror(errno));
     301                return -1;
     302        }
     303
     304        return fd;
     305}
     306
     307char *MidiDriver_TIMIDITY::timidity_ctl_command(const char *fmt, ...) {
     308        /* XXX: I don't like this static buffer!!! */
     309        static char buff[BUFSIZ];
     310        int status, len;
     311        va_list ap;
     312
     313        if (fmt != NULL) {
     314                /* if argumends are present, write them to control connection */
     315                va_start(ap, fmt);
     316                len = vsnprintf(buff, BUFSIZ-1, fmt, ap); /* leave one byte for \n */
     317                va_end(ap);
     318
     319                /* add newline if needed */
     320                if(len > 0 && buff[len - 1] != '\n')
     321                        buff[len++] = '\n';
     322
     323                /* write command to control socket */
     324                write(_control_fd, buff, len);
     325        }
     326
     327        while(1) {
     328                /* read reply */
     329                if (fdgets(buff, sizeof(buff)) <= 0) {
     330                        strcpy(buff, "Read error\n");
     331                        break;
     332                }
     333
     334                /* report errors from server */
     335                status = atoi(buff);
     336                if (400 <= status && status <= 499) { /* Error of data stream */
     337                        warning("TiMidity: error from server: %s", buff);
     338                        continue;
     339                }
     340                break;
     341        }
     342
     343        return buff;
     344}
     345
     346void MidiDriver_TIMIDITY::timidity_meta_seq(int p1, int p2, int p3) {
     347        /* see _CHN_COMMON from soundcard.h; this is simplified
     348         * to just send seq to the server without any buffers,
     349         * delays and extra functions/macros */
     350        u_char seqbuf[8];
     351
     352        seqbuf[0] = 0x92;
     353        seqbuf[1] = 0;
     354        seqbuf[2] = 0xff;
     355        seqbuf[3] = 0x7f;
     356        seqbuf[4] = p1;
     357        seqbuf[5] = p2;
     358        *(short *)&seqbuf[6] = p3;
     359
     360        timidity_write_data(seqbuf, sizeof(seqbuf));
     361}
     362
     363int MidiDriver_TIMIDITY::timidity_sync(int centsec) {
     364        char *res;
     365        int status;
     366        unsigned long sleep_usec;
     367
     368        timidity_meta_seq(0x02, 0x00, centsec); /* Wait playout */
     369
     370        /* Wait "301 Sync OK" */
     371        do {
     372                res = timidity_ctl_command(NULL);
     373                status = atoi(res);
     374
     375                if(status != 301)
     376                        warning("TiMidity: error: SYNC: %s", res);
     377
     378        } while(status && status != 301);
     379
     380        if(status != 301)
     381                return -1; /* error */
     382
     383        sleep_usec = (unsigned long)(atof(res + 4) * 1000000);
     384
     385        if(sleep_usec > 0)
     386                usleep(sleep_usec);
     387
     388        return 0;
     389}
     390
     391int MidiDriver_TIMIDITY::timidity_eot(void) {
     392        timidity_meta_seq(0x00, 0x00, 0); /* End of playing */
     393        return timidity_sync(0);
     394}
     395
     396void MidiDriver_TIMIDITY::timidity_write_data(const void *buf, size_t nbytes) {
     397        /* nowhere to write... */
     398        if (_data_fd < 0)
     399                return;
     400
     401        /* write, and disable everything if write failed */
     402        /* TODO: add reconnect? */
     403        if (write(_data_fd, buf, nbytes) == -1) {
     404                warning("TiMidity: DATA WRITE FAILED (%s), DISABLING MUSIC OUTPUT", strerror(errno));
     405                close_all();
     406        }
     407}
     408
     409int MidiDriver_TIMIDITY::fdgets(char *buff, size_t buff_size) {
     410        int n, len, count, size;
     411        char *buff_endp = buff + buff_size - 1, *pbuff, *beg;
     412
     413        len = 0;
     414        count = _controlbuffer_count;
     415        size = _controlbuffer_size;
     416        pbuff = _controlbuffer;
     417        beg = buff;
     418        do {
     419                if (count == size) {
     420                        if ((n = read(_control_fd, pbuff, BUFSIZ)) <= 0) {
     421                                *buff = '\0';
     422                                if (n == 0) {
     423                                        _controlbuffer_count = _controlbuffer_size = 0;
     424                                        return buff - beg;
     425                                }
     426                                return -1; /* < 0 error */
     427                        }
     428                        count = _controlbuffer_count = 0;
     429                        size = _controlbuffer_size = n;
     430                }
     431                *buff++ = pbuff[count++];
     432        } while(*(buff - 1) != '\n' && buff != buff_endp);
     433
     434        *buff = '\0';
     435        _controlbuffer_count = count;
     436
     437        return buff - beg;
     438}
     439
     440void MidiDriver_TIMIDITY::send(uint32 b) {
     441        unsigned char buf[256];
     442        int position = 0;
     443
     444        switch (b & 0xF0) {
     445        case 0x80:
     446        case 0x90:
     447        case 0xA0:
     448        case 0xB0:
     449        case 0xE0:
     450                buf[position++] = SEQ_MIDIPUTC;
     451                buf[position++] = (unsigned char)b;
     452                buf[position++] = _device_num;
     453                buf[position++] = 0;
     454                buf[position++] = SEQ_MIDIPUTC;
     455                buf[position++] = (unsigned char)((b >> 8) & 0x7F);
     456                buf[position++] = _device_num;
     457                buf[position++] = 0;
     458                buf[position++] = SEQ_MIDIPUTC;
     459                buf[position++] = (unsigned char)((b >> 16) & 0x7F);
     460                buf[position++] = _device_num;
     461                buf[position++] = 0;
     462                break;
     463        case 0xC0:
     464        case 0xD0:
     465                buf[position++] = SEQ_MIDIPUTC;
     466                buf[position++] = (unsigned char)b;
     467                buf[position++] = _device_num;
     468                buf[position++] = 0;
     469                buf[position++] = SEQ_MIDIPUTC;
     470                buf[position++] = (unsigned char)((b >> 8) & 0x7F);
     471                buf[position++] = _device_num;
     472                buf[position++] = 0;
     473                break;
     474        default:
     475                warning("MidiDriver_TIMIDITY::send: unknown : %08x", (int)b);
     476                break;
     477        }
     478
     479        timidity_write_data(buf, position);
     480}
     481
     482void MidiDriver_TIMIDITY::sysEx(const byte *msg, uint16 length) {
     483        fprintf(stderr, "Timidity::sysEx\n");
     484        unsigned char buf[1024];
     485        int position = 0;
     486        const byte *chr = msg;
     487
     488        assert(length + 2 <= 256);
     489
     490        buf[position++] = SEQ_MIDIPUTC;
     491        buf[position++] = 0xF0;
     492        buf[position++] = _device_num;
     493        buf[position++] = 0;
     494        for (; length; --length, ++chr) {
     495                buf[position++] = SEQ_MIDIPUTC;
     496                buf[position++] = (unsigned char) *chr & 0x7F;
     497                buf[position++] = _device_num;
     498                buf[position++] = 0;
     499        }
     500        buf[position++] = SEQ_MIDIPUTC;
     501        buf[position++] = 0xF7;
     502        buf[position++] = _device_num;
     503        buf[position++] = 0;
     504
     505        timidity_write_data(buf, position);
     506}
     507
     508MidiDriver *MidiDriver_TIMIDITY_create() {
     509        return new MidiDriver_TIMIDITY();
     510}
     511
     512#endif // defined (UNIX)
  • backends/module.mk

     
    99        midi/morphos.o \
    1010        midi/quicktime.o \
    1111        midi/seq.o \
     12        midi/timidity.o \
    1213        midi/dmedia.o \
    1314        midi/windows.o \
    1415        plugins/dc/dc-provider.o \