Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v97i017: Splitter [1.2] - A Bars and Pipes accessory for splitting a track, Part 01/01

2 views
Skip to first unread message

Richard Hagen

unread,
Nov 18, 1997, 3:00:00 AM11/18/97
to

Submitted-by: Richard Hagen <R.H...@mailbox.uq.edu.au>
Posting-number: Volume 97, Issue 17
Archive-name: music/Splitter-1.2/part01
URL: http://www.it.uq.edu.au/~richard/music/bars-and-pipes/index.html#programs

[ Executable (splitter.paccess) included. ...zim ]

Splitter: A Bars and Pipes accessory for splitting one track into many.

#!/bin/sh
# This is music/Splitter-1.2, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 11/18/1997 18:27 UTC by z...@ibx.com
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 1284 -rw------- dmakefile
# 2170 -rw------- myheader.h
# 23043 -rw------- splitter.c
# 5288 -rw------- splitter.paccess
# 2055 -rw------- splitter.readme
#
if test -r _shar_seq_.tmp; then
echo 'Must unpack archives in sequence!'
echo Please unpack part `cat _shar_seq_.tmp` next
exit 1
fi
# ============= dmakefile ==============
if test -f 'dmakefile' -a X"$1" != X"-c"; then
echo 'x - skipping dmakefile (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting dmakefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dmakefile' &&
#
# The name of the accessory.
#
ACCESS = splitter
X
#
# The source files that you need to build the accessory.
#
MYSRCS = splitter.c
X
MYHDRS = myheader.h
X
#
# You might want to tinker with the compiler flags and libraries.
#
# -3.0 - Compile for a 3.0 system (optional)
# -mc - Small code model
# -md - Small data model
#
CFLAGS = -3.0 -mc -md
X
#
# Required libraries
#
# amiga30s.lib - The small code version of the Amiga library
# cs.lib - The small code version of the C library
#
LIBS = amiga30s.lib cs.lib
X
#
# You shouldn't have to touch anything below here.
#
# (FYI: (It's important that toolstart.c gets listed first... toolstart.o
# has to be the first thing mentioned when the accessory is linked
# together.)
#
PACCESS = $(ACCESS).paccess
README = $(ACCESS).readme
ARCHIVE = $(ACCESS).lha
X
SRCS = toolstart.c $(MYSRCS)
OBJS = $(SRCS:*.c:*.o)
X
all: $(PACCESS)
X
$(PACCESS): $(OBJS)
X dlink $(OBJS) $(LIBS) -o $(PACCESS)
X
$(OBJS): $(SRCS)
X dcc $(CFLAGS) -c %(right) -o %(left)
X
# I use emacs, so I tend to have a lot of backup files ending in ``!''
# lying around.
clean:
X delete $(OBJS) *!
X
clobber: clean
X delete $(PACCESS) $(ARCHIVE)
X
distribution: $(ARCHIVE)
X
$(ARCHIVE): clobber $(PACCESS) clean
X lha a $(ARCHIVE) dmakefile $(PACCESS) $(MYHDRS) $(MYSRCS) $(README)
X
X
X
SHAR_EOF
chmod 0600 dmakefile ||
echo 'restore of dmakefile failed'
Wc_c="`wc -c < 'dmakefile'`"
test 1284 -eq "$Wc_c" ||
echo 'dmakefile: original size 1284, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= myheader.h ==============
if test -f 'myheader.h' -a X"$1" != X"-c"; then
echo 'x - skipping myheader.h (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting myheader.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'myheader.h' &&
/*
X myheader.h - Useful #defines and typedefs for tool/accessory programs.
*/
X
#ifndef MYHEADER_H
#define MYHEADER_H
X
/* Length of tool/accessory id. */
#define ID_LEN 4
X
/* Make an id out of four characters. */
#define MAKE_ID(a, b, c, d) ((ULONG) ((((a << 8) + b << 8) + c << 8) + d))
X
/* Make an id out of a string. */
#define MAKE_IDS(s) (MAKE_ID(s[0], s[1], s[2], s[3]))
X
/* Split an id into four characters. */
#define SPLIT_ID(id, a, b, c, d) \
do { \
X a = (UBYTE) ((id >> 24) & 0xff); \
X b = (UBYTE) ((id >> 16) & 0xff); \
X c = (UBYTE) ((id >> 8) & 0xff); \
X d = (UBYTE) (id & 0xff); \
} while (0)
X
/* Split an id into a string. */
#define SPLIT_IDS(id, s) \
do { \
X SPLIT_ID(id, s[0], s[1], s[2], s[3]); \
} while (0)
X
/* Maximum MIDI note # */
#define MIDI_NOTE_MAX (127)
X
/* Number of MIDI notes. */
#define MIDI_NOTE_NUM (MIDI_NOTE_MAX + 1)
X
/* Maximum program change number. */
#define PC_CHANGE_MAX 127
X
/* Number of program changes. */
#define PC_CHANGE_NUM (PC_CHANGE_MAX + 1)
X
/* Flags for use in the BRB file requester. */
#define FILES_DELETE 1 /* Delete button */
#define FILES_OPEN 2 /* Open button */
#define FILES_SAVE 4 /* Save button */
#define FILES_TEST 8 /* ??? */
#define FILES_TYPE 16 /* Type string gadget */
#define FILES_PATH 32 /* Path string gadget */
X
/* Initial placement of tool/accessory windows. */
#define INITIAL_LEFT 50
#define INITIAL_TOP 50
X
/* Unprototyping cast. */
typedef __geta4 long (*no_prototype)();
X
/* Void cast. */
typedef __geta4 void (*void_prototype)();
X
/* Event *cast. */
typedef __geta4 struct Event *(*event_prototype)();
X
/* For non-stdio debugging messages. */
#define DEBUG(message) \
do { \
X struct EasyStruct es = { \
X sizeof(struct EasyStruct), \
X 0, \
X "Debugging information", \
X "Message: %s", \
X "OK" \
X }; \
X (void) EasyRequest(functions->window, &es, 0, message); \
} while (0)
X
#define NOTE_LENGTH(x) (768 >> (x))
X
#define MBC_STRING_LENGTH 12
X
#define CLOCKSPERMEASURE 768L
X
#define STREQ(x, y) (strcmp((x), (y)) == 0)
#define STREQN(x, y, n) (strncmp((x), (y), (n)) == 0)
X
#endif /* MYHEADER_H */
SHAR_EOF
chmod 0600 myheader.h ||
echo 'restore of myheader.h failed'
Wc_c="`wc -c < 'myheader.h'`"
test 2170 -eq "$Wc_c" ||
echo 'myheader.h: original size 2170, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= splitter.c ==============
if test -f 'splitter.c' -a X"$1" != X"-c"; then
echo 'x - skipping splitter.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting splitter.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'splitter.c' &&
/*
X Splitter: A Bars & Pipes Accessory for splitting a track into
X many tracks, according to a note map as used
X by the Pattern Tool for drum kits.
X
X Copyright (C) 1997 Richard Hagen
X
X This code is released into the Public Domain, and may be freely
X distributed in its original form.
X
X It is supplied ``as is'', and comes with no warranty.
X This program code was released because it might be useful as a
X starting point for other programmers. However, if any damage arises
X from its use, the original author will not be held liable.
X
X You are free to use and modify this code to your heart's content,
X provided you acknowledge me as the original author in any code
X that you might distribute which is based largely on this code.
X
X I acknowledge that the design of this accessory is influenced
X strongly by the example code supplied with the Rules for Tools
X package. However, I have made substantial contributions of my
X own.
X
X Richard Hagen
X ric...@it.uq.edu.au
X
X History:
X 1.3 (29 September 1997)
X Removed dynamically allocated strings.
X
X 1.2 (22 September 1997)
X Improved the code a bit.
X
X 1.1 (19 August 1997)
X Added ``Clear Note Map'' button.
X Tidied up some silly code.
X
X 1.0 (12 August 1997)
X Initial Release.
*/
X
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/gadtools.h>
#include <exec/memory.h>
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>
X
#include "bars.h"
X
#include "myheader.h"
X
#define SPLITTER_NAME "Splitter 1.3"
X
X
/* -------------------------------------------------------------------- */
/* ICON IMAGERY */
/* -------------------------------------------------------------------- */
X
/* Normal icon. */
static const __chip UWORD splitter_image_data[] = {
X /* Plane 0 */
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x38f0, 0x0c00, 0x0,
X 0x38f0, 0x0c00, 0x0,
X 0x0401, 0x8270, 0x0,
X 0x0401, 0x8270, 0x0,
X 0x0303, 0xc103, 0x0,
X 0x0303, 0xc103, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X
X /* Plane 1 */
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X
X /* Plane #2 */
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
};
X
static const struct Image splitter_image = {
X 0, 0,
X 48, 34, 3,
X splitter_image_data,
X 0x1f, 0x00,
X NULL
};
X
/* Selected icon. */
static const __chip UWORD splitter_onimage_data[] = {
X /* Plane 0 */
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x38f0, 0x0c00, 0x0,
X 0x38f0, 0x0c00, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0401, 0x8270, 0x0,
X 0x0401, 0x8270, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0303, 0xc103, 0x0,
X 0x0303, 0xc103, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X
X /* Plane 1 */
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X
X /* Plane #2 */
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x2108, 0x4210, 0x8000,
X 0x2108, 0x4210, 0x8000,
X 0x7fff, 0xffff, 0xe000,
X 0x7fff, 0xffff, 0xe000,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
X 0x0, 0x0, 0x0,
};
X
static const struct Image splitter_onimage = {
X 1, 0,
X 48, 34, 3,
X splitter_onimage_data,
X 0x1f, 0x00,
X NULL
};
X
/* Global Bars & Pipes functions pointer. */
extern struct Functions *functions;
X
/* Title for error requester. */
static const char *error_title = "Splitter error";
X
/* Puts up a simple requester for relaying error messages. */
static void
accessory_error(struct Window *window, /* Window to open requester in. */
X const char *s) /* String to put in the requester. */
{
X const struct EasyStruct easy = {
X sizeof(struct EasyStruct),
X 0,
X error_title,
X s,
X "OK"
X };
X
X (void) EasyRequest(window, &easy, NULL);
}
X
/* -------------------------------------------------------------------- */
/* Note Maps */
/* -------------------------------------------------------------------- */
X
/* Note maps are created by the Pattern tool when you edit a drum
X kit. Have a bit of a play with the drum map editing facility
X to get a feel for what data needs to be stored for a note map.
X
X The file containing the note map has the following format:
X
X Description Size Value Comment
X
X File ID 4 Bytes "NTMP"
X Length of File 4 Bytes File length - 8
X Offset to note data 4 Bytes
X Pointer to note data 4 Bytes Ignore this
X ?Spare byte? 1 Byte 0x00 ?
X MIDI Note to ID Map 128 Bytes
X ID to MIDI Note Map 128 Bytes
X ID to position Map 128 Bytes
X ?Spare Byte? 1 Byte 0x00 ?
X ?Map ID? 4 Bytes "DRUM" ?Different maps?
X Length of map 4 Bytes
X Length of map entry 4 Bytes 0x00000018
X Map entries -
X Pointer to next 4 Bytes 0 if last entry,
X otherwise, ignore
X Note name 15 Bytes 0 in last byte
X Note ID 1 Byte
X MIDI note 1 Byte
X Note position 1 Byte
X Flags 4 Bytes 0x00000001 == selected
X ?other flags?
X
X If anyone can help me out with the things marked ``?'', I'd really
X appreciate it! */
X
/* Length of note name as stored in note map file. */
#define NOTE_NAME_LEN 15
X
/* Format of records stored in the note map file. */
struct NotemapFileEntry {
X char name[NOTE_NAME_LEN];
X UBYTE id;
X UBYTE note;
X UBYTE pos;
X UWORD flags;
};
X
/* Strings for holding note names. */
typedef char Notemap[MIDI_NOTE_NUM][NOTE_NAME_LEN]; /* Indexed by note number. */
X
/* My accessory needs to remember a notemap, so I've bundled the two
X things together. */
struct Splitter {
X struct Accessory accessory;
X Notemap notemap;
};
X
/* My accessory. */
struct Splitter splitter;
X
/* Returns a text string given a midi note number. */
static char *
note_name(UBYTE note)
{
X static char name[NOTE_NAME_LEN];
X
X static const char *note_names[] = {
X "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "Bb", "B"
X };
X
X sprintf(name, "%s%1ld", note_names[note % 12], (int) note / 12);
X
X return name;
}
X
static void
name_init(UBYTE note, char name[])
{
X strcpy(name, note_name(note));
}
X
/* Initialises a note map. */
static void
notemap_init(Notemap *notemap)
{
X for (UBYTE i = 0; i < MIDI_NOTE_NUM; i++)
X {
X name_init(i, (*notemap)[i]);
X }
}
X
static void
notemap_load(long file, /* Open file. */
X Notemap *notemap) /* Notemap to fill in. */
{
X char file_id[ID_LEN]; /* File ID. */
X ULONG offset = 0; /* Offset to name map entries. */
X ULONG next = 0; /* Next pointer. */
X
X /* Ensure that the file id is one for a note map. */
X if ((*functions->fastread)(file, file_id, ID_LEN) < ID_LEN)
X {
X /* Failed to read the correct number of bytes for the file id. */
X return;
X }
X if (!STREQN(file_id, "NTMP", ID_LEN))
X {
X /* Incorrect id */
X return;
X }
X
X /* Skip over the file length */
X if ((*functions->fastseek)(file, sizeof(ULONG), OFFSET_CURRENT) < 0)
X {
X /* Seek failed */
X return;
X }
X
X /* Read the offset for the note map entry data. */
X if ((*functions->fastread)(file, (UBYTE *)&offset, sizeof(offset)) < sizeof(offset))
X {
X /* Failed to read the correct number of bytes for the offset. */
X return;
X }
X
X /* Skip to the note map entries. Don't bother checking the
X map id or record length. */
X if ((*functions->fastseek)(file, offset+12, OFFSET_CURRENT) < 0)
X {
X /* Seek failed. */
X return;
X }
X
X /* We've made it this far, assume that we have a valid note map file. */
X
X /* Initialise the notemap. */
X notemap_init(notemap);
X
X /* Read in entries as long as the ``next'' pointer is not 0. */
X do {
X /* Notemap entry to be read from file. */
X struct NotemapFileEntry entry;
X
X /* Read the ``next'' pointer and note map entry. */
X if ((*functions->fastread)(file, (UBYTE *)&next, sizeof(next)) < sizeof(next))
X {
X /* Failed to read the correct number of bytes for the ``next'' pointer. */
X return;
X }
X if ((*functions->fastread)(file, (UBYTE *)&entry, sizeof(entry)) < sizeof(entry))
X {
X /* Failed to read the correct number of bytes for an entry. */
X return;
X }
X
X strcpy((*notemap)[entry.note], entry.name);
X } while (next != 0);
X
X return;
}
X
/* -------------------------------------------------------------------- */
/* SPLITTING TRACKS */
/* -------------------------------------------------------------------- */
X
/* For splitting the tracks, I maintain two separate structures, one for
X the note events, and one for the others (i.e. control change, etc.)
X The note events are stored in an array, with each element of the array
X corresponding to a particular MIDI note. The other events are all lumped
X in together. */
X
/* Split a list of events into note events and other events. */
static BOOL
eventlist_split(struct Event *source, /* Pointer to first event in list */
X /* to be split. */
X struct Event **notes, /* Array of event lists, */
X /* one for each MIDI note. */
X struct Event **others) /* Handle for event list for */
X /* non-note events. */
{
X struct NoteEvent *event;
X
X /* For each event in the list. */
X for (event = (struct NoteEvent *) source;
X event;
X event = (struct NoteEvent *) event->next)
X {
X /* If it's a MIDI performance event.*/
X if (event->type == EVENT_VOICE)
X {
X /* Try to allocate a new event and check to see if we succeeded. */
X struct NoteEvent *new =
X (struct NoteEvent *)(*functions->allocevent)();
X if (new == (struct NoteEvent *) NULL)
X {
X /* Allocation failed. */
X return FALSE;
X }
X
X /* Initialise the new event. */
X *new = *event;
X
X /* Is it a note event? */
X if (new->status == MIDI_NOTEON)
X {
X new->next = notes[new->value];
X notes[new->value] = new;
X }
X else /* It's some other sort of MIDI event. */
X {
X new->next = *others;
X *others = new;
X }
X }
X }
X
X return TRUE;
}
X
/* Shameless plug inserted into track notes by the accessory. */
static const char *splitter_notes = "Created by Splitter Accessory 1.2";
X
/* Allocate, initialise and return a new track.
X If something goes wrong, returns NULL. */
static struct Track *
track_new(struct Track *old, /* Track to initialise from. */
X char *name, /* Name of the new track. */
X unsigned char note, /* Which MIDI note this corresponds to. */
X struct Event *events) /* Events for the new track. */
X /* In reverse order! */
{
X /* Attempt to allocate the track, and check to see if we succeeded. */
X struct Track *track =
X (struct Track *)(*functions->createtrack)(1, 0);
X if (track == (struct Track *) NULL)
X {
X return (struct Track *) NULL;
X }
X
X /* Initialise the track from the fields of the supplied track. */
X track->next = (struct Track *) NULL;
X
X /* Keep the same channel in and out assignments. */
X track->channelin = old->channelin;
X track->channelout = old->channelout;
X
X /* Careful! createtrack() has already given the track a name. */
X (*functions->replacestring)(&(track->clip.name), name);
X track->clip.notes =
X (struct String *)(*functions->allocstring)(splitter_notes);
X
X /* Highest and lowest notes for the clip are the same as the note. */
X track->clip.highnote = note;
X track->clip.lownote = note;
X
X /* Begin and end times. */
X track->clip.begin = 0;
X track->clip.end = events == (struct Event *) NULL ? 0 : events->time;
X
X /* Sort and add the events. */
X track->clip.events.first =
X (struct Event *)(*functions->sorteventlist)(events);
X track->clip.events.point = (struct Event *) NULL;
X
X return track;
}
X
/* Split a track according to the supplied notemap. It will add as many
X tracks as needed following the selected track. */
static void
track_split(struct Track *track, /* Track to be split. */
X Notemap *notemap) /* Note map to use. */
{
X /* List of events for non-note MIDI events. */
X struct Event *others = (struct Event *) NULL;
X
X /* Array of lists of events, one for each MIDI note. */
X struct Event *notes[MIDI_NOTE_NUM];
X
X /* Initialise the event list array. */
X for (int i = 0; i < MIDI_NOTE_NUM; i++)
X {
X notes[i] = (struct Event *) NULL;
X }
X
X /* Try to separate out the events in the track. */
X if (eventlist_split(track->clip.events.first, notes, &others))
X {
X /* List of new tracks */
X struct Track *new_tracks = NULL;
X
X /* Were there any non-note events? */
X if (others != (struct Event *) NULL)
X {
X new_tracks = track_new(track, "Other Events",
X (unsigned char) 0,
X others);
X }
X
X /* Create tracks for each of the lists of events. */
X for (int i = 0; i < MIDI_NOTE_NUM; i++)
X {
X /* If there are notes for the track, notes[i] will be non-null. */
X if (notes[i] != (struct Event *) NULL)
X {
X /* Make the new track. */
X struct Track *new = track_new(track,
X (*notemap)[i],
X (unsigned char) i,
X notes[i]);
X
X /* Stick it at the start of the list so far. */
X new->next = new_tracks;
X new_tracks = new;
X }
X }
X
X /* Splice in the list of new tracks. */
X track->next = (struct Track *)(*functions->List_Cat)(new_tracks, track->next);
X }
}
X
/* -------------------------------------------------------------------- */
/* INTERFACE */
/* -------------------------------------------------------------------- */
X
#define LOAD_NOTE_MAP_GADGET 1
#define SPLIT_TRACK_GADGET 2
#define CLEAR_NOTE_MAP_GADGET 3
X
static const struct IntuiText itext1 = {
X 4,0,JAM1,
X 12,1,
X NULL,
X "Load Note Map File",
X NULL
};
X
static const struct Gadget gadget1 = {
X NULL,
X 15, 16,
X 168, 9,
X (ULONG) NULL,
X RELVERIFY+GADGIMMEDIATE,
X BOOLGADGET,
X NULL,
X NULL,
X &itext1,
X (ULONG) NULL,
X NULL,
X LOAD_NOTE_MAP_GADGET,
X NULL
};
X
static const struct IntuiText itext2 = {
X 4,0,JAM1,
X 4,1,
X NULL,
X "Split Selected Track",
X NULL
};
X
static const struct Gadget gadget2 = {
X &gadget1,
X 15, 27,
X 168, 9,
X (ULONG) NULL,
X RELVERIFY+GADGIMMEDIATE,
X BOOLGADGET,
X NULL,
X NULL,
X &itext2,
X (ULONG) NULL,
X NULL,
X SPLIT_TRACK_GADGET,
X NULL
};
X
static const struct IntuiText itext3 = {
X 4,0,JAM1,
X 28, 1,
X NULL,
X "Clear Notemap",
X NULL
};
X
static const struct Gadget gadget3 = {
X &gadget2,
X 15, 38,
X 168, 9,
X (ULONG) NULL,
X RELVERIFY+GADGIMMEDIATE,
X BOOLGADGET,
X NULL,
X NULL,
X &itext3,
X (ULONG) NULL,
X NULL,
X CLEAR_NOTE_MAP_GADGET,
X NULL
};
X
/* Start of gadget list. */
#define gadget_list (&gadget3)
X
/* Close the splitter window. */
__geta4 /* Callback function. */
splitter_close(void)
{
X /* Ensure that we have something to close. */
X if (splitter.accessory.window)
X {
X struct IntuiMessage *message;
X
X (*functions->EmbossOff)(splitter.accessory.window,1);
X (*functions->EmbossOff)(splitter.accessory.window,2);
X (*functions->EmbossOff)(splitter.accessory.window,3);
X (*functions->EmbossWindowOff)(splitter.accessory.window);
X
X /* Remember where we were in case we're reopened later. */
X splitter.accessory.left = splitter.accessory.window->LeftEdge;
X splitter.accessory.top = splitter.accessory.window->TopEdge;
X
X /* Make it hard to send us messages and eat up any that are pending. */
X splitter.accessory.window->UserPort = 0;
X ModifyIDCMP(splitter.accessory.window,0);
X WaitTOF();
X WaitTOF();
X WaitTOF();
X WaitTOF();
X WaitTOF();
X Forbid();
X while (message = (struct IntuiMessage *)GetMsg(functions->window->UserPort))
X {
X ReplyMsg((struct Message *)message);
X }
X (*functions->FlashyCloseWindow)(splitter.accessory.window);
X splitter.accessory.window = NULL;
X Permit();
X }
X
X return(1);
}
X
/* Open the splitter window. */
__geta4 /* Callback function. */
splitter_open(void)
{
X /* Use v37+ style window tags to specify the new window. */
X const struct TagItem tags[] = {
X {WA_Left, splitter.accessory.left},
X {WA_Top, splitter.accessory.top},
X {WA_Width, 198},
X {WA_Height, 53},
X {WA_DetailPen, 5},
X {WA_BlockPen, 1},
X {WA_IDCMP, GADGETUP|CLOSEWINDOW},
X {WA_DragBar, FALSE},
X {WA_DepthGadget, FALSE},
X {WA_CloseGadget, FALSE},
X {WA_Activate, TRUE},
X {WA_NoCareRefresh, TRUE},
X {WA_Borderless, TRUE},
X {WA_Gadgets, (ULONG) gadget_list},
X {WA_Checkmark, (ULONG) NULL},
X {WA_Title, (ULONG) NULL},
X {WA_ScreenTitle, (ULONG) SPLITTER_NAME},
X {WA_CustomScreen, (ULONG) functions->screen}
X };
X
X /* Attempt to open the window, and check to see if we were successful. */
X splitter.accessory.window = (struct Window *)OpenWindowTagList(NULL, &tags);
X if (splitter.accessory.window != (struct Window *) NULL)
X {
X /* Set up communication. */
X splitter.accessory.window->UserPort = functions->window->UserPort;
X ModifyIDCMP(splitter.accessory.window,functions->window->IDCMPFlags);
X
X (*functions->EmbossWindowOn)(splitter.accessory.window,
X WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG,
X SPLITTER_NAME, (short)-1,(short)-1,0,0);
X (*functions->EmbossOn)(splitter.accessory.window,1,1);
X (*functions->EmbossOn)(splitter.accessory.window,2,1);
X (*functions->EmbossOn)(splitter.accessory.window,3,1);
X }
X
X return((long)splitter.accessory.window);
}
X
/* Gather and process user input from the splitter window. */
__geta4 /* Callback function. */
splitter_edit(struct IntuiMessage *message) /* Message to process. */
{
X struct Window *window = message->IDCMPWindow;
X struct Gadget *gadget;
X long class,code;
X
X class = message->Class;
X code = message->Code;
X gadget = (struct Gadget *) message->IAddress;
X ReplyMsg((struct Message *)message);
X class = (*functions->SystemGadgets)(window,class,gadget,code);
X
X if (class == CLOSEWINDOW)
X {
X (void) splitter_close();
X return 0;
X }
X else if (class == GADGETUP)
X {
X switch (gadget->GadgetID)
X {
X case LOAD_NOTE_MAP_GADGET:
X {
X char filename[255];
X
X /* Get the filename */
X (*functions->FileName)(filename,"Load Note Map File:","drummap",
X functions->screen,
X FILES_OPEN|FILES_DELETE|FILES_TYPE,0,0);
X if (filename[0])
X {
X /* Attempt to open the file and check to see if we
X succeeded. */
X long file = (*functions->fastopen)(filename,MODE_OLDFILE);
X if (file != -1)
X {
X if ((*functions->areyousure)("replace the note map?"))
X {
X (*functions->openwait)();
X notemap_load(file, splitter.notemap);
X (*functions->closewait)();
X }
X (*functions->fastclose)(file);
X }
X else
X {
X accessory_error(splitter.accessory.window,
X "Couldn't open file for reading");
X }
X }
X }
X break;
X case SPLIT_TRACK_GADGET:
X {
X if (functions->groupid != 0) /* Group selected? */
X {
X accessory_error(splitter.accessory.window,
X "Can't split a group");
X }
X else if (functions->selectedtrack) /* Track selected? */
X {
X (*functions->openwait)();
X track_split(functions->selectedtrack, splitter.notemap);
X (*functions->display)(0x1000000);
X (*functions->closewait)();
X }
X else /* No track selected. */
X {
X accessory_error(splitter.accessory.window,
X "You must select a track for splitting");
X }
X }
X break;
X case CLEAR_NOTE_MAP_GADGET:
X {
X if ((*functions->areyousure)("clear the note map?"))
X {
X (*functions->openwait)();
X notemap_init(&(splitter.notemap));
X (*functions->closewait)();
X }
X }
X }
X }
X return 1;
}
X
struct Accessory *
inittoolmaster(void)
{
X memset((char *)&splitter,0,sizeof(struct Splitter));
X splitter.accessory.left = INITIAL_LEFT;
X splitter.accessory.top = INITIAL_TOP;
X splitter.accessory.id = MAKE_IDS("SPLT");
X splitter.accessory.next = 0;
X splitter.accessory.image = &splitter_image;
X splitter.accessory.onimage = &splitter_onimage;
X splitter.accessory.open = splitter_open;
X splitter.accessory.close = splitter_close;
X splitter.accessory.edit = (no_prototype) splitter_edit;
X strcpy(splitter.accessory.name, SPLITTER_NAME);
X notemap_init(&(splitter.notemap));
X
X return(&splitter.accessory);
}
SHAR_EOF
chmod 0600 splitter.c ||
echo 'restore of splitter.c failed'
Wc_c="`wc -c < 'splitter.c'`"
test 23043 -eq "$Wc_c" ||
echo 'splitter.c: original size 23043, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= splitter.paccess ==============
if test -f 'splitter.paccess' -a X"$1" != X"-c"; then
echo 'x - skipping splitter.paccess (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting splitter.paccess (Binary)'
sed 's/^X//' << 'SHAR_EOF' > _shar_tmp_.tmp &&
begin 600 splitter.paccess
<encoded_portion_removed>
end
SHAR_EOF
echo 'uudecoding file splitter.paccess' &&
uudecode < _shar_tmp_.tmp && rm -f _shar_tmp_.tmp &&
chmod 0600 splitter.paccess ||
echo 'restore of splitter.paccess failed'
Wc_c="`wc -c < 'splitter.paccess'`"
test 5288 -eq "$Wc_c" ||
echo 'splitter.paccess: original size 5288, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= splitter.readme ==============
if test -f 'splitter.readme' -a X"$1" != X"-c"; then
echo 'x - skipping splitter.readme (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting splitter.readme (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'splitter.readme' &&
Short: Bars & Pipes Accessory for splitting one track into many.
Author: Richard Hagen (R.H...@mailbox.uq.edu.au)
Uploader: Richard Hagen (R.H...@mailbox.uq.edu.au)
Version: 1.3 (29 September 1997)
Type: mus/midi
Requires: Bars and Pipes Professional
Distribution: Freely distributable by anyone, anywhere.
X
Splitter: A Bars and Pipes accessory for splitting one track into many.
X
Version: 1.2 (22 September 1997)
X
Author: Richard Hagen
X R.H...@mailbox.uq.edu.au
X
Distribution: Freeware. See the copyright notice in splitter.c.
X
Requirements for running:
X Bars and Pipes Professional
X
Requirements for recompiling:
X DICE (or some other C compiler)
X bars.h and toolstart.c from the Rules for Tools kit.
X
Usage:
X Run Bars and Pipes
X
X Load a song.
X Select a track to be split.
X
X Install the Splitter in the Accessories window.
X Open the Splitter.
X Click ``Split Selected Track''.
X
X Your track will be split into a number of tracks, each containing
X the events for a single MIDI note number. Tracks will only be
X created for MIDI note numbers that occur in the original track.
X Each new track of MIDI note events is named for the note that
X it contains.
X
X Another track for non-note MIDI events will be created if needed.
X
X If you prefer, you can use a ``note map'' to supply names to the
X newly created tracks. Note maps are created by the Pattern tool
X when you're using Drum Map mode. These can be saved to disk,
X and then be loaded into the Splitter using the
X ``Load Notemap from File'' gadget. Load the note map before
X splitting the track.
X
Useful for:
X Splitting a drum track into individual instruments for separate
X processing.
X
History:
X 1.3 (29 September 1997)
X Removed dynamically allocated strings.
X
X 1.2 (22 September 1997)
X Improved the code a bit.
X
X 1.1 (19 August 1997)
X Added ``Clear Note Map'' button.
X Tidied up some silly code.
X
X 1.0 (12 August 1997)
X Initial Release.
X
If you like this accessory, please drop me a line.
X
richard
R.H...@mailbox.uq.edul.au
29 September 1997
X
X
SHAR_EOF
chmod 0600 splitter.readme ||
echo 'restore of splitter.readme failed'
Wc_c="`wc -c < 'splitter.readme'`"
test 2055 -eq "$Wc_c" ||
echo 'splitter.readme: original size 2055, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
exit 0
--
Bill Zimmer - z...@ibx.com

0 new messages