OSDN Git Service

MIDI output mode
authorShohei Urabe <root@mput.dip.jp>
Wed, 13 Dec 2006 23:22:56 +0000 (23:22 +0000)
committerShohei Urabe <root@mput.dip.jp>
Wed, 13 Dec 2006 23:22:56 +0000 (23:22 +0000)
34 files changed:
ChangeLog
configure.in
interface/alsaseq_c.c
interface/server_c.c
timidity/Makefile.am
timidity/aRts_a.c
timidity/aiff_a.c
timidity/alsa_a.c
timidity/ao_a.c
timidity/au_a.c
timidity/audriv_a.c
timidity/bsd20_a.c
timidity/controls.c
timidity/controls.h
timidity/esd_a.c
timidity/flac_a.c
timidity/gogo_a.c
timidity/hpux_a.c
timidity/hpux_d_a.c
timidity/midi_a.c [new file with mode: 0644]
timidity/modmid_a.c
timidity/oss_a.c
timidity/output.c
timidity/output.h
timidity/playmidi.c
timidity/portaudio_a.c
timidity/raw_a.c
timidity/readmidi.c
timidity/readmidi.h
timidity/speex_a.c
timidity/sun_a.c
timidity/vorbis_a.c
timidity/w32_a.c
timidity/wave_a.c

index 1686bf0..356ad60 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2006-12-14  Stas Sergeev <stsp@aknet.ru>
 
        * interface/server_c.c: extend midi protocol.
+       * timidity/midi_a.c: new file.
 
 2006-12-13  URABE Shyouhei  <shyouhei@ruby-lang.org>
 
index 8831a83..0e25a97 100644 (file)
@@ -585,12 +585,16 @@ if test "x$VCPP" = xyes || test "x$BORLANDC" = xyes || test "x$WATCOM_C" = xyes;
 fi
 
 AC_CHECK_FUNC(getopt_long,
-        AC_DEFINE([HAVE_GETOPT_LONG],1,[Define to 1 if you have `getopt_long function'])
+        AC_DEFINE([HAVE_GETOPT_LONG],1,[Define to 1 if you have `getopt_long' function])
         tm_cv_needgetopt="no",
         tm_cv_needgetopt="yes")
 AM_CONDITIONAL([NEEDGETOPT], test "x$tm_cv_needgetopt" = "xyes")
 
-# Checks on cygnus and MYSYS
+AC_CHECK_FUNC(open_memstream, [
+        AC_DEFINE([HAVE_OPEN_MEMSTREAM],1,[Define to 1 if you have `open_memstream' function])
+        ])
+
+# Checks on cygnus and MSYS
 if test "x$MSYS" = xyes ; then
   case "$ac_cv_header_dirent_dirent_h$ac_cv_header_dirent_sys_ndir_h$ac_cv_header_dirent_sys_dir_h$ac_cv_header_dirent_ndir_h" in
   *yes*)
@@ -1062,19 +1066,35 @@ dnl aRts of KDE
 AC_MSG_CHECKING(enable_audio=arts)
 if test "x$au_enable_arts" = xyes; then
   AC_MSG_RESULT([yes, configuring aRts])
-  KEEPCFLAGS=$CFLAGS
-  KEEPLIBS=$LIBS
-  KEEPLDFLAGS=$LDFLAGS
-  AM_PATH_ARTS()
-  CFLAGS=$KEEPCFLAGS
-  LIBS=$KEEPLIBS
-  LDFLAGS=$KEEPLDFLAGS
-  if test "x$no_arts" = x; then
+  dnl **** Check for aRts Sound Server ****
+  AC_PATH_PROG(ARTSCCONFIG, artsc-config)
+  if test x$ARTSCCONFIG != x -a x$ARTSCCONFIG != x'"$ARTSCCONFIG"';
+  then
+    ARTSC_CFLAGS=""
+    for i in `$ARTSCCONFIG --cflags`
+    do
+      case "$i" in
+        -I*) ARTSC_CFLAGS="$ARTSC_CFLAGS $i";;
+      esac
+    done
+    ARTSC_LIBS=`$ARTSCCONFIG --libs`
+    save_CFLAGS="$CFLAGS"
+    CFLAGS="$CFLAGS $ARTSC_CFLAGS"
+    AC_TRY_COMPILE([#include <artsc.h>],[arts_stream_t stream;],
+        [AC_SUBST(ARTSLIBS, $ARTSC_LIBS)
+         AC_SUBST(ARTSINCL, $ARTSC_CFLAGS)
+         AC_DEFINE(HAVE_ARTS, 1, [Define if you have ARTS sound server])
+        have_arts="yes"
+         ])
+    CFLAGS="$save_CFLAGS"
+  fi
+
+  if test "$have_arts" = "yes"; then
     dnl AC_MSG_RESULT(aRts: Enabled)
     EXTRADEFS="$EXTRADEFS -DAU_ARTS"
     SYSEXTRAS="$SYSEXTRAS aRts_a.c"
-    EXTRACT_CPPFLAGS(CPPFLAGS,CFLAGS,$ARTS_CFLAGS)
-    LIBS="$LIBS $ARTS_LIBS"
+    EXTRACT_CPPFLAGS(CPPFLAGS,CFLAGS,$ARTSC_CFLAGS)
+    LIBS="$LIBS $ARTSC_LIBS"
   else
     AC_MSG_WARN(aRts: Couldn't configure)
   fi
@@ -1156,8 +1176,8 @@ dnl ogg's vorbis
 AC_MSG_CHECKING(enable_audio=vorbis)
 if test "x$au_enable_vorbis" = xyes; then
   AC_MSG_RESULT([yes, configuring vorbis])
-  AM_PATH_OGG([
-    AM_PATH_VORBIS([
+  XIPH_PATH_OGG([
+    XIPH_PATH_VORBIS([
       have_vorbis=yes
       SYSEXTRAS="$SYSEXTRAS vorbis_a.c"
       EXTRADEFS="$EXTRADEFS -DAU_VORBIS $OGG_CFLAGS $VORBIS_CFLAGS"
index 61ba631..99cc499 100644 (file)
@@ -390,8 +390,6 @@ static int ctl_pass_playing_list(int n, char *args[])
        j += note_key_offset, j -= floor(j / 12.0) * 12;
        current_freq_table = j;
 
-       play_mode->close_output();
-
        if (ctl.flags & CTLF_DAEMONIZE)
        {
                int pid = fork();
@@ -560,9 +558,9 @@ static void server_reset(void)
 
 static int start_sequencer(struct seq_context *ctxp)
 {
-       if (play_mode->open_output() < 0) {
+       if (play_mode->acntl(PM_REQ_PLAY_START, NULL) < 0) {
                ctl.cmsg(CMSG_FATAL, VERB_NORMAL,
-                        "Couldn't open %s (`%c')",
+                        "Couldn't start %s (`%c')",
                         play_mode->id_name, play_mode->id_character);
                return 0;
        }
@@ -592,7 +590,7 @@ static void stop_sequencer(struct seq_context *ctxp)
                snd_seq_stop_queue(ctxp->handle, ctxp->queue, NULL);
                snd_seq_drain_output(ctxp->handle);
        }
-       play_mode->close_output();
+       play_mode->acntl(PM_REQ_PLAY_END, NULL);
        free_instruments(0);
        free_global_mblock();
        ctxp->used = 0;
index dd4765f..c3d9dd5 100644 (file)
@@ -405,7 +405,6 @@ static int ctl_pass_playing_list(int n, char *args[])
     alarm(0);
     signal(SIGALRM, sig_timeout);
 
-    play_mode->close_output();
     while(1)
     {
        socklen_t addrlen;
@@ -427,18 +426,18 @@ static int ctl_pass_playing_list(int n, char *args[])
        }
        else control_fd = 0;
 
-       if(play_mode->open_output() < 0)
+       if (play_mode->acntl(PM_REQ_PLAY_START, NULL) < 0)
        {
            ctl.cmsg(CMSG_FATAL, VERB_NORMAL,
-                    "Couldn't open %s (`%c')",
+                    "Couldn't start %s (`%c')",
                     play_mode->id_name, play_mode->id_character);
-           send_status(510, "Couldn't open %s (`%c')",
+           send_status(510, "Couldn't start %s (`%c')",
                        play_mode->id_name, play_mode->id_character);
            if (control_port) {
                close(control_fd);
                control_fd = -1;
            }
-           continue;
+           break;
        }
 
        server_reset();
@@ -447,7 +446,7 @@ static int ctl_pass_playing_list(int n, char *args[])
        doit();
        ctl.cmsg(CMSG_INFO, VERB_NOISY, "Connection closed");
 
-       play_mode->close_output();
+       play_mode->acntl(PM_REQ_PLAY_END, NULL);
 
        if(control_fd != -1 && control_port)
        {
@@ -651,15 +650,14 @@ static void doit(void)
 
            if(data_fd != -1 && (tmr_running || notmr_running))
            {
-                   double wait_time;
-                   int32 filled;
+                   double wait_time, filled;
 
                    if (IS_STREAM_TRACE)
                        filled = aq_filled();
                    else
                        filled = high_time_at * play_mode->rate;
 
-                   wait_time = (double)filled / play_mode->rate - low_time_at;
+                   wait_time = filled / play_mode->rate - low_time_at;
                    if(wait_time <= 0)
                        usec = 0;
                    else
index 15af346..6467ee1 100644 (file)
@@ -36,6 +36,7 @@ timidity_SOURCES = \
        aq.c \
        aq.h \
        au_a.c \
+       midi_a.c \
        audio_cnv.c \
        audio_cnv.h \
        common.c \
index 83b5057..0b5be0a 100755 (executable)
@@ -242,10 +242,11 @@ static int acntl(int request, void *arg)
       case PM_REQ_FLUSH: /* Wait until playback is complete */
       case PM_REQ_MIDI: /* Send MIDI event */
       case PM_REQ_INST_NAME: /* Get instrument name */
+       return -1;
       case PM_REQ_OUTPUT_FINISH: /* Sent after last output_data */
       case PM_REQ_PLAY_START: /* Called just before playing */
       case PM_REQ_PLAY_END: /* Called just after playing */
-       return -1;
+       return 0;
     }
     return -1;
 }
index a4cfa8e..199d74c 100644 (file)
@@ -352,8 +352,9 @@ static int open_output(void)
     dpm.encoding = validate_encoding(dpm.encoding, include_enc, exclude_enc);
 
     if(dpm.name == NULL) {
+      if (!current_file_info || !current_file_info->filename)
+        return -1;
       dpm.flag |= PF_AUTO_SPLIT_FILE;
-      dpm.name = NULL;
     } else {
       dpm.flag &= ~PF_AUTO_SPLIT_FILE;
       if(aiff_output_open(dpm.name) == -1)
@@ -411,13 +412,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_aiff_output_open(current_file_info->filename);
-    break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }
index 863f178..38ca3c2 100644 (file)
@@ -629,6 +629,10 @@ static int acntl(int request, void *arg)
       return -1;
     output_counter = 0;
     return 0;
+
+  case PM_REQ_PLAY_START: /* Called just before playing */
+  case PM_REQ_PLAY_END: /* Called just after playing */
+    return 0;
   }
   return -1;
 }
index 6d6ebc4..2f5b25c 100644 (file)
@@ -162,7 +162,8 @@ static int acntl(int request, void *arg)
 {
   switch(request) {
   case PM_REQ_DISCARD:
-    ;;
+  case PM_REQ_PLAY_START: /* Called just before playing */
+  case PM_REQ_PLAY_END: /* Called just after playing */
     return 0;
   }
   return -1;
index 8fd243b..61807d9 100644 (file)
@@ -243,8 +243,9 @@ static int open_output(void)
     dpm.encoding = validate_encoding(dpm.encoding, include_enc, exclude_enc);
 
     if(dpm.name == NULL) {
+      if (!current_file_info || !current_file_info->filename)
+        return -1;
       dpm.flag |= PF_AUTO_SPLIT_FILE;
-      dpm.name = NULL;
     } else {
       dpm.flag &= ~PF_AUTO_SPLIT_FILE;
       if(au_output_open(dpm.name, NULL) == -1)
@@ -324,13 +325,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_au_output_open(current_file_info->filename);
-    break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }
index 7d223b5..722e29f 100644 (file)
@@ -253,6 +253,10 @@ static int acntl(int request, void *arg)
        audriv_play_stop(); /* Reset audriv's sample counter */
        Audio_On();
        return 0;
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index 944ce20..063411d 100644 (file)
@@ -146,6 +146,10 @@ static int acntl(int request, void *arg)
     {
       case PM_REQ_DISCARD:
        return ioctl(dpm.fd, DSP_IOCTL_RESET);
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index bfeeaf6..259553c 100644 (file)
@@ -232,7 +232,7 @@ ControlMode *ctl_list[]={
 
 ControlMode *ctl=DEFAULT_CONTROL_MODE;
 
-int std_write(int fd, char *buffer, int size)
+int std_write(int fd, const char *buffer, int size)
 {
     /* redirect stdout writes */
     if (fd == 1 && ctl->write)
index e2ce605..1d5b2a6 100644 (file)
@@ -158,6 +158,6 @@ typedef struct {
 extern ControlMode *ctl_list[], *ctl;
 extern int dumb_error_count;
 
-extern int std_write(int fd, char *buffer, int size);
+extern int std_write(int fd, const char *buffer, int size);
 
 #endif /* ___CONTROLS_H_ */
index f40c788..84f99fd 100644 (file)
@@ -180,6 +180,10 @@ static int acntl(int request, void *arg)
          /* not implemented yet */
           break;
        }
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index 641b070..32faf9d 100644 (file)
@@ -706,8 +706,9 @@ static int open_output(void)
 
 #ifndef __W32G__
   if(dpm.name == NULL) {
+    if (!current_file_info || !current_file_info->filename)
+      return -1;
     dpm.flag |= PF_AUTO_SPLIT_FILE;
-    dpm.name = NULL;
   } else {
     dpm.flag &= ~PF_AUTO_SPLIT_FILE;
     if(flac_output_open(dpm.name, NULL) == -1)
@@ -986,13 +987,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_flac_output_open(current_file_info->filename, current_file_info->seq_name);
-    break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }
index 68eff48..e6ca0b1 100644 (file)
@@ -1255,8 +1255,9 @@ static int open_output(void)
 
 #if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
     if(dpm.name == NULL) {
+      if (!current_file_info || !current_file_info->filename)
+        return -1;
       dpm.flag |= PF_AUTO_SPLIT_FILE;
-      dpm.name = NULL;
     } else {
       dpm.flag &= ~PF_AUTO_SPLIT_FILE;
       if((dpm.fd = gogo_output_open(dpm.name)) == -1)
@@ -1347,13 +1348,11 @@ static int acntl(int request, void *arg)
        case PM_REQ_PLAY_START:
                if(dpm.flag & PF_AUTO_SPLIT_FILE)
                        return auto_gogo_output_open(current_file_info->filename,current_file_info->seq_name);
-               break;
+               return 0;
        case PM_REQ_PLAY_END:
-               if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+               if(dpm.flag & PF_AUTO_SPLIT_FILE)
                        close_output();
-                       return 0;
-               }
-               break;
+               return 0;
        case PM_REQ_DISCARD:
 #if 1
                gogo_buffer_reset();
index d795e7b..5b29bb5 100644 (file)
@@ -287,11 +287,9 @@ static int acntl(int request, void *arg)
     switch(request)
     {
       case PM_REQ_DISCARD:
-       /* Must be defined this request but I don't know how to do */
-/*     fprintf(stderr,
-               "hpux_a.c: acntl(): PM_REQ_DISCARD is not implemented.");
- */
-       return -1;
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index c1b145e..f50cb13 100644 (file)
@@ -118,6 +118,10 @@ static int acntl(int request, void *arg)
     {
       case PM_REQ_DISCARD:
        return ioctl(dpm.fd, AUDIO_RESET, RESET_TX_BUF);
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
diff --git a/timidity/midi_a.c b/timidity/midi_a.c
new file mode 100644 (file)
index 0000000..4b3b59e
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+    TiMidity++ -- MIDI to WAVE converter and player
+    Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
+    Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    midi_a.c - write midi file
+
+    Author: Stas Sergeev <stsp@users.sourceforge.net>
+    Based on midi-writer code by Rober Komar <rkomar@telus.net>
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif                         /* HAVE_CONFIG_H */
+
+#ifdef HAVE_OPEN_MEMSTREAM
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif                         /* HAVE_UNISTD_H */
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#ifndef __WIN32__
+#include <arpa/inet.h>
+#else
+#include <winsock.h>
+#endif
+#ifdef HAVE_SYS_SOUNDCARD_H
+#include <sys/soundcard.h>
+#else
+#include "server_defs.h"
+#endif /* HAVE_SYS_SOUNDCARD_H */
+
+#include "timidity.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "readmidi.h"
+#include "output.h"
+#include "controls.h"
+
+#define IGNORE_TEMPO_EVENTS 0
+
+static int open_output(void);
+static void close_output(void);
+static int acntl(int request, void *arg);
+
+static char *midibuf;
+static size_t midi_pos;
+#ifdef HAVE_OPEN_MEMSTREAM
+static FILE *fp;
+#else
+static size_t midibuf_size;
+#define fflush(x) do {} while (0)
+#define fclose(x) do {} while (0)
+#endif
+
+static long track_size_pos;
+static double last_time;
+
+static int tempo;
+static int ticks_per_quarter_note;
+#define TICKS_OFFSET 12
+
+#define dmp midi_play_mode
+
+PlayMode dmp = {
+    DEFAULT_RATE, 0, PF_MIDI_EVENT,
+    -1,
+    {0, 0, 0, 0, 0},
+    "Write MIDI file", 'm',
+    NULL,
+    open_output,
+    close_output,
+    NULL,
+    acntl
+};
+
+#define CARR(...) ((u_int8_t []) {__VA_ARGS__})
+#define M_FWRITE(...) m_fwrite(CARR(__VA_ARGS__), sizeof(CARR(__VA_ARGS__)))
+#define M_FWRITE_STR(s) m_fwrite((s), sizeof(s) - 1)
+
+static size_t m_fwrite(const void *ptr, size_t size)
+{
+#ifdef HAVE_OPEN_MEMSTREAM
+    return fwrite(ptr, size, 1, fp);
+#else
+    if (midi_pos + size > midibuf_size) {
+       size_t new_len = (midi_pos + size) * 2;
+       midibuf = safe_realloc(midibuf, new_len);
+       midibuf_size = new_len;
+    }
+    memcpy(midibuf + midi_pos, ptr, size);
+    midi_pos += size;
+    return 1;
+#endif
+}
+
+#ifndef HAVE_OPEN_MEMSTREAM
+static void my_open_memstream(void)
+{
+    midibuf_size = 1024;
+    midibuf = safe_malloc(midibuf_size);
+    midi_pos = 0;
+}
+#endif
+
+static void write_midi_header(void)
+{
+    /* Write out MID file header.
+     * The file will have a single track, with the configured number of
+     * ticks per quarter note.
+     */
+    M_FWRITE_STR("MThd");
+    M_FWRITE_STR("\0\0\0\6");          /* header size */
+    M_FWRITE_STR("\0\0");              /* single track format */
+    M_FWRITE_STR("\0\1");              /* #tracks = 1 */
+    M_FWRITE_STR("\0\0");              /* #ticks / quarter note written later */
+}
+
+static void finalize_midi_header(void)
+{
+    unsigned short tpqn = htons(ticks_per_quarter_note);
+
+    fflush(fp);
+    memcpy(midibuf + TICKS_OFFSET, &tpqn, 2);  /* #ticks / quarter note */
+}
+
+static void set_tempo(void)
+{
+    M_FWRITE_STR("\xff\x51\3");
+    M_FWRITE(tempo >> 16, tempo >> 8, tempo);
+}
+
+static void set_time_sig(void)
+{
+    /* Set the time sig to 4/4 */
+    M_FWRITE_STR("\xff\x58\4\4\x2\x18\x08");
+}
+
+static void midout_write_delta_time(int32 time)
+{
+    int32 delta_time;
+    unsigned char c[4];
+    int idx;
+    int started_printing = 0;
+
+#if !IGNORE_TEMPO_EVENTS
+    double div;
+    delta_time = time - last_time;
+    div = (double)tempo * (double)play_mode->rate /
+       (double)(ticks_per_quarter_note * 1000000);
+    delta_time /= div;
+    last_time += delta_time * div;
+#else
+    delta_time = time - last_time;
+    last_time += delta_time;
+#endif
+
+    /* We have to divide the number of ticks into 7-bit segments, and only write
+     * the non-zero segments starting with the most significant (except for the
+     * least significant segment, which we always write).  The most significant bit
+     * is set to 1 in all but the least significant segment.
+     */
+    c[0] = (delta_time >> 21) & 0x7f;
+    c[1] = (delta_time >> 14) & 0x7f;
+    c[2] = (delta_time >> 7) & 0x7f;
+    c[3] = (delta_time) & 0x7f;
+
+    for (idx = 0; idx < 3; idx++) {
+       if (started_printing || c[idx]) {
+           started_printing = 1;
+           M_FWRITE(c[idx] | 0x80);
+       }
+    }
+    M_FWRITE(c[3]);
+}
+
+static void start_midi_track(void)
+{
+    /* Write out track header.
+     * The track will have a large length (0x7fffffff) because we don't know at
+     * this time how big it will really be.
+     */
+    M_FWRITE_STR("MTrk");
+    fflush(fp);
+    track_size_pos = midi_pos;
+    M_FWRITE_STR("\x7f\xff\xff\xff");  /* #chunks */
+
+    last_time = 0;
+
+#if !IGNORE_TEMPO_EVENTS
+    tempo = 500000;
+#else
+    tempo = (ticks_per_quarter_note * 1000000) /
+       (double)play_mode->rate;
+#endif
+
+    midout_write_delta_time(0);
+    set_tempo();
+    midout_write_delta_time(0);
+    set_time_sig();
+}
+
+static void end_midi_track(void)
+{
+    int32 track_bytes;
+    /* Send (with delta-time of 0) "0xff 0x2f 0x0" to finish the track. */
+    M_FWRITE_STR("\0\xff\x2f\0");
+
+    fflush(fp);
+
+    track_bytes = htonl(midi_pos - track_size_pos - 4);
+    memcpy(midibuf + track_size_pos, &track_bytes, 4);
+}
+
+static int open_output(void)
+{
+#ifdef HAVE_OPEN_MEMSTREAM
+    fp = open_memstream(&midibuf, &midi_pos);
+#else
+    my_open_memstream();
+#endif
+
+    ticks_per_quarter_note = 144;
+    write_midi_header();
+
+    return 0;
+}
+
+static void close_output(void)
+{
+    finalize_midi_header();
+
+    fclose(fp);
+    if (dmp.name) {
+       if (strcmp(dmp.name, "-") == 0)
+           dmp.fd = STDOUT_FILENO;
+       else
+           dmp.fd = creat(dmp.name, 0666);
+       if (dmp.fd != -1) {
+           std_write(dmp.fd, midibuf, midi_pos);
+           if (strcmp(dmp.name, "-") != 0)
+               close(dmp.fd);
+       }
+       dmp.fd = -1;
+    }
+    free(midibuf);
+}
+
+static void midout_noteon(int chn, int note, int vel, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_NOTEON, note & 0x7f, vel & 0x7f);
+}
+
+static void midout_noteoff(int chn, int note, int vel, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_NOTEOFF, note & 0x7f, vel & 0x7f);
+}
+
+static void midout_control(int chn, int control, int value, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_CTL_CHANGE, control & 0x7f, value & 0x7f);
+}
+
+static void midout_keypressure(int chn, int control, int value, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_KEY_PRESSURE, control & 0x7f, value & 0x7f);
+}
+
+static void midout_channelpressure(int chn, int vel, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_CHN_PRESSURE, vel & 0x7f);
+}
+
+static void midout_bender(int chn, int pitch, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_PITCH_BEND, pitch & 0x7f, (pitch >> 7) & 0x7f);
+}
+
+static void midout_program(int chn, int pgm, int32 time)
+{
+    midout_write_delta_time(time);
+    M_FWRITE((chn & 0x0f) | MIDI_PGM_CHANGE, pgm & 0x7f);
+}
+
+static void midout_tempo(int chn, int a, int b, int32 time)
+{
+    midout_write_delta_time(time);
+    tempo = (a << 16) | (b << 8) | chn;
+    set_tempo();
+}
+
+static int find_bit(int val)
+{
+    int i = 0;
+    while (val) {
+       if (val & 1)
+           return i;
+       i++;
+       val >>= 1;
+    }
+    return -1;
+}
+
+static void midout_timesig(int chn, int a, int b, int32 time)
+{
+    if (chn == 0) {
+       if (!b)
+           return;
+       b = find_bit(b);
+       midout_write_delta_time(time);
+       M_FWRITE_STR("\xff\x58\4");
+    }
+    M_FWRITE(a, b);
+}
+
+static int do_event(MidiEvent * ev)
+{
+    int ch, co, va, type;
+
+    ch = ev->channel;
+
+    if ((type = unconvert_midi_control_change(ev)) != -1) {
+       midout_control(ch, type, ev->a, ev->time);
+       return RC_NONE;
+    }
+
+    switch (ev->type) {
+    case ME_NOTEON:
+       midout_noteon(ch, ev->a, ev->b, ev->time);
+       break;
+    case ME_NOTEOFF:
+       midout_noteoff(ch, ev->a, ev->b, ev->time);
+       break;
+    case ME_KEYPRESSURE:
+       midout_keypressure(ch, ev->a, ev->b, ev->time);
+       break;
+    case ME_PROGRAM:
+       midout_program(ch, ev->a, ev->time);
+       break;
+    case ME_CHANNEL_PRESSURE:
+       midout_channelpressure(ch, ev->a, ev->time);
+       break;
+    case ME_PITCHWHEEL:
+       midout_bender(ch, ev->a, ev->time);
+       break;
+    case ME_TEMPO:
+#if !IGNORE_TEMPO_EVENTS
+       midout_tempo(ch, ev->a, ev->b, ev->time);
+#endif
+       break;
+    case ME_TIMESIG:
+       midout_timesig(ch, ev->a, ev->b, ev->time);
+       break;
+    case ME_EOT:
+       return RC_TUNE_END;
+    }
+    return RC_NONE;
+}
+
+static int acntl(int request, void *arg)
+{
+    switch (request) {
+    case PM_REQ_MIDI:
+       return do_event((MidiEvent *) arg);
+    case PM_REQ_PLAY_START:
+       start_midi_track();
+       return 0;
+    case PM_REQ_PLAY_END:
+       end_midi_track();
+       return 0;
+    case PM_REQ_DIVISIONS:
+       ticks_per_quarter_note = *(int32 *) arg;
+       return 0;
+    }
+    return -1;
+}
index f798de6..33c1832 100644 (file)
@@ -64,6 +64,8 @@ static int acntl(int request, void *arg)
     switch(request)
     {
       case PM_REQ_DISCARD:
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
        return 0;
     }
     return -1;
index f135296..c752497 100644 (file)
@@ -413,6 +413,10 @@ static int acntl(int request, void *arg)
        *((int *)arg) = i;
        return 0;
 #endif /* SNDCTL_DSP_GETODELAY */
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index 878f8e5..474ac1d 100644 (file)
@@ -130,6 +130,7 @@ extern PlayMode gogo_play_mode;
 #endif /* AU_GOGO */
 #endif /* !__MACOS__ */
 
+extern PlayMode midi_play_mode;
 extern PlayMode modmidi_play_mode;
 
 PlayMode *play_mode_list[] = {
@@ -194,6 +195,7 @@ PlayMode *play_mode_list[] = {
 #endif /* AU_GOGO */
   &list_play_mode,
 #endif /* __MACOS__ */
+  &midi_play_mode,
   &modmidi_play_mode,
   0
 };
index 66c7024..bcea131 100644 (file)
@@ -103,11 +103,14 @@ enum {
                         * Get filled device queue size
                         */
 
-    PM_REQ_OUTPUT_FINISH /* ARG: not-used
+    PM_REQ_OUTPUT_FINISH, /* ARG: not-used
                          * PM_REQ_OUTPUT_FINISH calls just after the last
                          * output_data(), and TiMidity would into
                          * waiting to flush the audio buffer.
                          */
+
+    PM_REQ_DIVISIONS,    /* ARG: int32* - pointer to divisions number
+                         */
 };
 
 
index 4b9a6ed..2ebe93d 100644 (file)
@@ -8827,7 +8827,6 @@ void playmidi_tmr_reset(void)
     buffer_pointer = common_buffer;
     for(i = 0; i < MAX_CHANNELS; i++)
        channel[i].lasttime = 0;
-    play_mode->acntl(PM_REQ_PLAY_START, NULL);
 }
 
 void playmidi_stream_free(void)
index 97ac6db..6cc153f 100644 (file)
@@ -569,6 +569,10 @@ static int acntl(int request, void *arg)
                }
        }
        //break;
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index 8fcbfbb..d6a38ed 100644 (file)
@@ -174,8 +174,9 @@ static int open_output(void)
   dpm.encoding = validate_encoding(dpm.encoding, 0, 0);
 
   if(dpm.name == NULL) {
+    if (!current_file_info || !current_file_info->filename)
+      return -1;
     dpm.flag |= PF_AUTO_SPLIT_FILE;
-    dpm.name = NULL;
   } else {
     dpm.flag &= ~PF_AUTO_SPLIT_FILE;
     if((dpm.fd = raw_output_open(dpm.name)) == -1)
@@ -216,13 +217,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_raw_output_open(current_file_info->filename);
-    break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }
index c51a9eb..44bf12f 100644 (file)
@@ -519,52 +519,63 @@ static void check_chorus_text_start(void)
     }
 }
 
+struct ctl_chg_types {
+    unsigned char mtype;
+    int ttype;
+} ctl_chg_list[] = {
+      { 0, ME_TONE_BANK_MSB },
+      { 1, ME_MODULATION_WHEEL },
+      { 2, ME_BREATH },
+      { 4, ME_FOOT },
+      { 5, ME_PORTAMENTO_TIME_MSB },
+      { 6, ME_DATA_ENTRY_MSB },
+      { 7, ME_MAINVOLUME },
+      { 8, ME_BALANCE },
+      { 10, ME_PAN },
+      { 11, ME_EXPRESSION },
+      { 32, ME_TONE_BANK_LSB },
+      { 37, ME_PORTAMENTO_TIME_LSB },
+      { 38, ME_DATA_ENTRY_LSB },
+      { 64, ME_SUSTAIN },
+      { 65, ME_PORTAMENTO },
+      { 66, ME_SOSTENUTO },
+      { 67, ME_SOFT_PEDAL },
+      { 68, ME_LEGATO_FOOTSWITCH },
+      { 69, ME_HOLD2 },
+      { 71, ME_HARMONIC_CONTENT },
+      { 72, ME_RELEASE_TIME },
+      { 73, ME_ATTACK_TIME },
+      { 74, ME_BRIGHTNESS },
+      { 84, ME_PORTAMENTO_CONTROL },
+      { 91, ME_REVERB_EFFECT },
+      { 92, ME_TREMOLO_EFFECT },
+      { 93, ME_CHORUS_EFFECT },
+      { 94, ME_CELESTE_EFFECT },
+      { 95, ME_PHASER_EFFECT },
+      { 96, ME_RPN_INC },
+      { 97, ME_RPN_DEC },
+      { 98, ME_NRPN_LSB },
+      { 99, ME_NRPN_MSB },
+      { 100, ME_RPN_LSB },
+      { 101, ME_RPN_MSB },
+      { 120, ME_ALL_SOUNDS_OFF },
+      { 121, ME_RESET_CONTROLLERS },
+      { 123, ME_ALL_NOTES_OFF },
+      { 126, ME_MONO },
+      { 127, ME_POLY },
+};
+
 int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret)
 {
-    switch(type)
-    {
-      case   0: type = ME_TONE_BANK_MSB; break;
-      case   1: type = ME_MODULATION_WHEEL; break;
-      case   2: type = ME_BREATH; break;
-      case   4: type = ME_FOOT; break;
-      case   5: type = ME_PORTAMENTO_TIME_MSB; break;
-      case   6: type = ME_DATA_ENTRY_MSB; break;
-      case   7: type = ME_MAINVOLUME; break;
-      case   8: type = ME_BALANCE; break;
-      case  10: type = ME_PAN; break;
-      case  11: type = ME_EXPRESSION; break;
-      case  32: type = ME_TONE_BANK_LSB; break;
-      case  37: type = ME_PORTAMENTO_TIME_LSB; break;
-      case  38: type = ME_DATA_ENTRY_LSB; break;
-      case  64: type = ME_SUSTAIN; break;
-      case  65: type = ME_PORTAMENTO; break;
-      case  66: type = ME_SOSTENUTO; break;
-      case  67: type = ME_SOFT_PEDAL; break;
-      case  68: type = ME_LEGATO_FOOTSWITCH; break;
-      case  69: type = ME_HOLD2; break;
-      case  71: type = ME_HARMONIC_CONTENT; break;
-      case  72: type = ME_RELEASE_TIME; break;
-      case  73: type = ME_ATTACK_TIME; break;
-      case  74: type = ME_BRIGHTNESS; break;
-      case  84: type = ME_PORTAMENTO_CONTROL; break;
-      case  91: type = ME_REVERB_EFFECT; break;
-      case  92: type = ME_TREMOLO_EFFECT; break;
-      case  93: type = ME_CHORUS_EFFECT; break;
-      case  94: type = ME_CELESTE_EFFECT; break;
-      case  95: type = ME_PHASER_EFFECT; break;
-      case  96: type = ME_RPN_INC; break;
-      case  97: type = ME_RPN_DEC; break;
-      case  98: type = ME_NRPN_LSB; break;
-      case  99: type = ME_NRPN_MSB; break;
-      case 100: type = ME_RPN_LSB; break;
-      case 101: type = ME_RPN_MSB; break;
-      case 120: type = ME_ALL_SOUNDS_OFF; break;
-      case 121: type = ME_RESET_CONTROLLERS; break;
-      case 123: type = ME_ALL_NOTES_OFF; break;
-      case 126: type = ME_MONO; break;
-      case 127: type = ME_POLY; break;
-      default: type = -1; break;
+    int i;
+    for (i = 0; i < ARRAY_SIZE(ctl_chg_list); i++) {
+       if (ctl_chg_list[i].mtype == type) {
+           type = ctl_chg_list[i].ttype;
+           break;
+       }
     }
+    if (i >= ARRAY_SIZE(ctl_chg_list))
+       type = -1;
 
     if(type != -1)
     {
@@ -579,6 +590,19 @@ int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret)
     return 0;
 }
 
+int unconvert_midi_control_change(MidiEvent *ev)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(ctl_chg_list); i++) {
+       if (ctl_chg_list[i].ttype == ev->type)
+           break;
+    }
+    if (i >= ARRAY_SIZE(ctl_chg_list))
+       return -1;
+
+    return ctl_chg_list[i].mtype;
+}
+
 static int block_to_part(int block, int port)
 {
        int p;
@@ -4345,6 +4369,9 @@ static int read_smf_file(struct timidity_file *tf)
     else
        divisions = (int32)divisions_tmp;
 
+    if(play_mode->flag & PF_MIDI_EVENT)
+       play_mode->acntl(PM_REQ_DIVISIONS, &divisions);
+
     if(len > 6)
     {
        ctl->cmsg(CMSG_WARNING, VERB_NORMAL,
index 1df4151..757a637 100644 (file)
@@ -120,6 +120,7 @@ extern int parse_sysex_event(uint8 *data, int32 datalen, MidiEvent *ev_ret);
 extern int parse_sysex_event_multi(uint8 *data, int32 datalen, MidiEvent *ev_ret);
 extern int convert_midi_control_change(int chn, int type, int val,
                                       MidiEvent *ev_ret);
+extern int unconvert_midi_control_change(MidiEvent *ev);
 extern char *readmidi_make_string_event(int type, char *string, MidiEvent *ev,
                                        int cnv);
 extern MidiEvent *read_midi_file(struct timidity_file *mtf,
@@ -174,4 +175,6 @@ extern void remove_channel_layer(int);
 
 extern void free_readmidi(void);
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
 #endif /* ___READMIDI_H_ */
index 14aa41d..d6038d0 100644 (file)
@@ -435,8 +435,9 @@ static int open_output(void)
 
 #if !defined (IA_W32GUI) && !defined (IA_W32G_SYN)
   if (dpm.name == NULL) {
+    if (!current_file_info || !current_file_info->filename)
+      return -1;
     dpm.flag |= PF_AUTO_SPLIT_FILE;
-    dpm.name = NULL;
   }
   else {
     dpm.flag &= ~PF_AUTO_SPLIT_FILE;
@@ -630,13 +631,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_speex_output_open(current_file_info->filename,current_file_info->seq_name);
-      break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }
index bc0e514..b968dee 100644 (file)
@@ -375,6 +375,10 @@ static int acntl(int request, void *arg)
          play_mode->rate = rate;
          return 0;
         }
+
+      case PM_REQ_PLAY_START: /* Called just before playing */
+      case PM_REQ_PLAY_END: /* Called just after playing */
+        return 0;
     }
     return -1;
 }
index f4c4480..7f9798e 100644 (file)
@@ -415,8 +415,9 @@ static int open_output(void)
 
 #if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
   if(dpm.name == NULL) {
+    if (!current_file_info || !current_file_info->filename)
+      return -1;
     dpm.flag |= PF_AUTO_SPLIT_FILE;
-    dpm.name = NULL;
   } else {
     dpm.flag &= ~PF_AUTO_SPLIT_FILE;
     if((dpm.fd = ogg_output_open(dpm.name, NULL)) == -1)
@@ -554,13 +555,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_ogg_output_open(current_file_info->filename,current_file_info->seq_name);
-    break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }
index 23e2ccd..9adebf6 100644 (file)
@@ -517,6 +517,10 @@ static int acntl(int request, void *arg)
            open_output();
             return 0;
         }
+
+        case PM_REQ_PLAY_START: /* Called just before playing */
+        case PM_REQ_PLAY_END: /* Called just after playing */
+           return 0;
     }
 
     return -1;
index 5f7e269..8edd0b8 100644 (file)
@@ -236,8 +236,9 @@ static int open_output(void)
 
 #ifndef __W32G__
     if(dpm.name == NULL) {
+      if (!current_file_info || !current_file_info->filename)
+        return -1;
       dpm.flag |= PF_AUTO_SPLIT_FILE;
-      dpm.name = NULL;
     } else {
       dpm.flag &= ~PF_AUTO_SPLIT_FILE;
       if((dpm.fd = wav_output_open(dpm.name)) == -1)
@@ -338,13 +339,11 @@ static int acntl(int request, void *arg)
   case PM_REQ_PLAY_START:
     if(dpm.flag & PF_AUTO_SPLIT_FILE)
       return auto_wav_output_open(current_file_info->filename);
-    break;
+    return 0;
   case PM_REQ_PLAY_END:
-    if(dpm.flag & PF_AUTO_SPLIT_FILE) {
+    if(dpm.flag & PF_AUTO_SPLIT_FILE)
       close_output();
-      return 0;
-    }
-    break;
+    return 0;
   case PM_REQ_DISCARD:
     return 0;
   }