Patch to sources of audio/rosegarden (a very ancient X11 version of rosegarden) to enable playing MIDI on NetBSD (with the patch for kern/32694). This is a single patch file (affecting multiple files) to be applied after 'make patch' in audio/rosegarden, rather than the set of separate patch files to include in the package - though it would be easy enough to apply it, run mkpatches and make makepatchsum, and have an updated package. Playing is reasonably solid, but falls behind with a few Note Offs if playing Jeff Glatt's "Joan of Arc" as a test. :) --- configure.in 1999-09-21 06:25:38.000000000 -0500 +++ configure.in 2006-02-01 20:05:44.000000000 -0500 @@ -175,6 +175,10 @@ PETAL_LDFLAGS="-shared" ;; + + *netbsd*) + sound_system="-DSYSTEM_NETBSD" + ;; esac defines="$defines $sound_system" --- configure 1999-09-21 06:26:34.000000000 -0500 +++ configure 2006-02-01 20:05:42.000000000 -0500 @@ -2732,6 +2732,10 @@ PETAL_LDFLAGS="-shared" ;; + + *netbsd*) + sound_system="-DSYSTEM_NETBSD" + ;; esac defines="$defines $sound_system" --- Rosegarden.in 1997-10-22 15:14:54.000000000 -0500 +++ Rosegarden.in 2006-02-01 20:13:47.000000000 -0500 @@ -31,7 +31,7 @@ !!! the output port (/dev/ttyd2 or whatever), and for SGI !!! it's not referred to at all... -Rosegarden*midiPort: /dev/sequencer +Rosegarden*midiPort: /dev/music Rosegarden*shouldWarpPointer: False --- mapper/include/Mapper.h 1997-10-19 09:58:55.000000000 -0500 +++ mapper/include/Mapper.h 2006-01-02 23:31:47.000000000 -0500 @@ -33,10 +33,14 @@ #ifdef SYSTEM_ZILOG #include "Mapper_ZILOG.h" #else +#ifdef SYSTEM_NETBSD +#include "Mapper_NetBSD.h" +#else #include "Mapper_GENERIC.h" #endif #endif #endif +#endif #define PERC_CHN 9 --- mapper/include/Mapper_NetBSD.h 1969-12-31 19:00:00.000000000 -0500 +++ mapper/include/Mapper_NetBSD.h 2006-02-01 19:56:21.000000000 -0500 @@ -0,0 +1,32 @@ +#ifndef _MAPPER_OSS_H_ + +#ifdef MIDI_PITCH_BEND +#undef MIDI_PITCH_BEND +#endif + +#include + +struct midi_info /* cribbed from OSS */ +{ + char name[30]; + int device; + unsigned int xxcapabilities; + int xxdev_type; + int xxdummies[18]; +}; + +typedef struct _DeviceInformation +{ + DeviceType Type; + + union + { + struct midi_info Midi; + struct synth_info Synth; + } Data; + +} DeviceInformation; + +extern void Mapper_nb2_wseq(seq_event_t *); + +#endif --- mapper/include/Systems.h 1997-10-19 10:32:19.000000000 -0500 +++ mapper/include/Systems.h 2006-01-31 00:25:01.000000000 -0500 @@ -58,12 +58,14 @@ #ifndef SYSTEM_OSS #ifndef SYSTEM_ZILOG #ifndef SYSTEM_SGI +#ifndef SYSTEM_NETBSD #ifndef SYSTEM_SILENT #define SYSTEM_SILENT #endif #endif #endif #endif +#endif #endif /* _SYSTEMS_H_ */ --- mapper/src/Mapper.c 1997-10-19 10:23:16.000000000 -0500 +++ mapper/src/Mapper.c 2006-01-02 23:54:09.000000000 -0500 @@ -12,6 +12,10 @@ #include "Mapper_OSS.c" #else +#ifdef SYSTEM_NETBSD +#include "Mapper_NetBSD.c" +#else + #ifdef SYSTEM_SILENT #include "Mapper_STUB.c" #else @@ -19,6 +23,7 @@ #error Internal inconsistency -- no SYSTEM symbol, not even SYSTEM_SILENT #endif /* SYSTEM_SILENT */ +#endif /* SYSTEM_NETBSD */ #endif /* SYSTEM_OSS */ #endif /* SYSTEM_ZILOG */ #endif /* SYSTEM_SGI */ --- mapper/src/Mapper_NetBSD.c 1969-12-31 19:00:00.000000000 -0500 +++ mapper/src/Mapper_NetBSD.c 2006-02-01 17:23:54.000000000 -0500 @@ -0,0 +1,444 @@ +/* + * Midi Event Mapper routines + */ + + +#undef POSIX_PLEASE +#undef _POSIX_SOURCE + +#include "Mapper.h" +#include +#include +#include +#include +#include +#include +#ifndef ENOENT +#include +#endif + +#include +#include +#include +#include +#include +#include <../../sequencer/src/Globals.h> + +TrackMetaInfoElement Tracks; +DeviceMetaInfoElement Devices; +int TracksOnDevice[Mapper_Devices_Supported][Mapper_Max_Tracks]; +int seqfd; + +void +Mapper_nb2_wseq(seq_event_t *ev) +{ + if ( sizeof *ev != write(seqfd, ev, sizeof *ev) ) + perror("Rosegarden Mapper: sequencer write"); + /* shall we sync on EVERY write? no, I think before waits is adequate. */ +} + +void +Mapper_FlushQueue(float FinishTime) +{ + Mapper_nb2_wseq(&SEQ_MK_TIMING(WAIT_ABS, .divisions=(int) FinishTime)); +} + +void +Mapper_CloseDevice() +{ +BEGIN("Mapper_CloseDevice"); + + Devices.MetaDeviceStatus = Device_Unitialised; + close(seqfd); + +END; +} + +/* + * Function: Mapper_WriteMidiEvent + * + * Description: Write the events onto the output buffer according to type + * + */ +void +Mapper_WriteMidiEvent(MIDIEvent OutEvent, int DeviceNumber) +{ + byte StatusByte; + seq_event_t e; + + BEGIN("Mapper_WriteMidiEvent"); + + StatusByte = OutEvent->EventCode; + +#ifdef SEQ_DEBUG + fprintf(stdout,"Writing out Event Data %x\n",StatusByte); +#endif /* SEQ_DEBUG */ + + switch ( MessageType(StatusByte) ) + { + case MIDI_NOTE_OFF: + e = SEQ_MK_CHN(NOTEOFF, + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .key = OutEvent->EventData.NoteOff.Note, + .velocity = OutEvent->EventData.NoteOff.Velocity); + break; + case MIDI_NOTE_ON: + e = SEQ_MK_CHN(NOTEON, + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .key = OutEvent->EventData.NoteOn.Note, + .velocity = OutEvent->EventData.NoteOn.Velocity); + break; + case MIDI_POLY_AFTERTOUCH: + e = SEQ_MK_CHN(KEY_PRESSURE, + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .key = OutEvent->EventData.PolyAftertouch.Note, + .pressure = OutEvent->EventData.PolyAftertouch.Velocity); + break; + case MIDI_CTRL_CHANGE: + e = SEQ_MK_CHN(CTL_CHANGE, /* XXX sequencer MSB/LSB treatment */ + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .controller = OutEvent->EventData.ControlChange.Controller, + .value = OutEvent->EventData.ControlChange.Value); + break; + case MIDI_PROG_CHANGE: + e = SEQ_MK_CHN(PGM_CHANGE, + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .program = OutEvent->EventData.ProgramChange.Program); + break; + case MIDI_CHNL_AFTERTOUCH: + e = SEQ_MK_CHN(CHN_PRESSURE, + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .pressure = OutEvent->EventData.MonoAftertouch.Channel); + break; + case MIDI_PITCH_BEND: + e = SEQ_MK_CHN(PITCH_BEND, + .device = DeviceNumber, + .channel = ChannelNum(StatusByte), + .value = OutEvent->EventData.PitchWheel.MSB << 7 + | OutEvent->EventData.PitchWheel.LSB); + break; + default: + fprintf(stderr,"Teach me what to do with this kind of event.\n"); + } + + Mapper_nb2_wseq(&e); + +END; +} + + +/* + * Mapper_WriteEvent + */ +void +Mapper_WriteEvent(MIDIEvent NextEvent, int DeviceNumber) +{ + DeviceList PBDevice; + int PlayAll = False; + int CurrentDevice = 0; + +BEGIN("Mapper_WriteEvent"); + + PBDevice = Mapper_GetActiveDevice(DeviceNumber); + if (Mapper_GetActiveDevice(DeviceNumber)->Device.Type == Mapper_All_Device) + PlayAll = True; + + do + { + /* get the nth Active device if we're playing to a single + device or step through them all in turn if this is + an ALL device */ + + if (PlayAll == True) + PBDevice = Mapper_GetDevice(CurrentDevice++); + + Mapper_WriteMidiEvent(NextEvent,PBDevice->Device.Data.Midi.device); + } + while((PlayAll == True) && ( CurrentDevice < (Devices.MaxDevices - 1))); +END; +} + +Boolean +Mapper_OpenDevice(int Sense, char *Device) +{ + char ErrBuff[128]; + int DevSense; + +BEGIN("Mapper_OpenDevice"); + + if (Sense&Device_Active_WO) DevSense = O_WRONLY; + else if (Sense&Device_Active_WR) DevSense = O_RDWR|O_NONBLOCK; + else RETURN_BOOL(False); + + /* if the Sense is WO and we are WO then return */ + if ((Devices.MetaDeviceStatus&Sense) && (Sense&Device_Active_WO)) + RETURN_BOOL(True); + + /* if we're WR then close and re-open no matter what for timing + purposes */ + if (Sense&Device_Active_WR) + Mapper_CloseDevice(); + + /* we're clear to carry on */ + Devices.MetaDeviceStatus=Sense; + + if ((seqfd = open(Device, DevSense, 0)) == -1) + { + snprintf(ErrBuff, sizeof ErrBuff, "%s: %s\n", Device, strerror(errno)); + Error(NON_FATAL_REPORT_TO_MSGBOX, ErrBuff); + RETURN_BOOL(False); + } + +RETURN_BOOL(True); +} + + +/* + * Mapper_LoadPatches + */ +void +Mapper_LoadPatches(void) +{ + BEGIN("Mapper_LoadPatches"); + END; +} + + +/* a logical ALL device for all devices in + the list - if we only have one device in + the list then we don't need an ALL. + We use the Number entry to signify this is + a logical device */ +void +Mapper_CreateAllDevice() +{ + DeviceInformation TempDevice; + DeviceList CurrentDev = NULL; + +BEGIN("Mapper_CreateALLDevice"); + + if ( Devices.MaxDevices <= 1 ) + END; + + TempDevice.Type = Mapper_All_Device; + strcpy(TempDevice.Data.Synth.name, Mapper_All_Device_Label); + CurrentDev = (DeviceList)Mapper_NewDeviceList + (TempDevice,Devices.MaxDevices); + LIST_Insert ( (List) Devices.Device, (List) CurrentDev ); + Devices.MaxDevices++; + +END; +} + + +/* + * Function: Mapper_DeviceQuery + * + * Description: Opens device and queries for all Midi ports + * and available synths. Fills out a list that + * is inherent to the global meta device info + * object. + * + */ +DeviceList +Mapper_DeviceQuery() +{ + int midi_devs = 0; + DeviceInformation TempDevice; + DeviceList CurrentDev = NULL; + + int i; + +BEGIN("Mapper_QueryDevice"); + + Devices.MaxDevices = 0; + Devices.ActiveDevices = 0; + + /* open device */ + if ( Mapper_ManageDevices(Device_Active_WO) != True ) + return NULL; + + /* + * NetBSD sequencer makes no distinction between 'synths' and 'MIDI + * devices' - if something is a synth, that's its own affair, it uses + * midisyn to present an ordinary MIDI interface like anything else. + * The NetBSD sequencer currently returns the same number for the + * NRSYNTHS and NRMIDIS ioctls, but we should use only one to avoid + * duplicating the device list. It doesn't really matter, but NRMIDIS + * makes more sense. To get the information on a device, though, we need + * to use the SEQUENCER_INFO ioctl, which corresponds to OSS's SYNTH_INFO + * and requires a synth_info struct as the argument. + */ + + /* see if we have any MIDI devices available */ + ioctl(seqfd, SEQUENCER_NRMIDIS, &midi_devs); + + if ( !midi_devs ) + { +#ifdef DEBUG + Error(NON_FATAL_REPORT_TO_MSGBOX,"No Configurable Devices on Port\n"); +#endif + Mapper_CloseDevice(); + return NULL; + } + + /* construct the devices return list */ + for ( i = 0; i < midi_devs; i++ ) + { + /* initialise the structure */ + TempDevice.Data.Synth.device = i; + ioctl(seqfd, SEQUENCER_INFO, &(TempDevice.Data.Synth)); + + TempDevice.Type = Mapper_Synth_Device; + + /* work around perceived bug in kernel with AWE32 + device not returning the correct device number - + perhaps this method is actually correct and the + OSS documentation is omitting something */ + + TempDevice.Data.Synth.device=i; + + if ( Devices.Device == NULL ) + { + Devices.Device = (DeviceList)Mapper_NewDeviceList(TempDevice, + Devices.MaxDevices); + } + else + { + /* append */ + CurrentDev = (DeviceList)Mapper_NewDeviceList(TempDevice, + Devices.MaxDevices); + LIST_Insert ( (List) Devices.Device, (List) CurrentDev ); + } + Devices.MaxDevices++; + } + + Mapper_CloseDevice(); + Mapper_CreateAllDevice(); /* create the "All" Device */ + + RETURN_PTR(Devices.Device); +} + +Boolean +Mapper_SetupDevices(char *midiPortName) +{ +int i; +BEGIN("Mapper_SetupDevices"); + + /* initialise devices meta information */ + Devices.Device = NULL; + Devices.FileDescriptor = XtNewString(midiPortName); + Devices.MetaDeviceStatus = Device_Unitialised; + Tracks.RecordDevice = -1; + Tracks.EditDevice = -1; + Tracks.Track = NULL; + + if (!(Mapper_DeviceQuery())) + { + /* no devices found - return devices as unavailable */ + Devices.FileDescriptor = XtNewString("/dev/null"); + Mapper_SetTrackInfo(); + RETURN_BOOL(False); + } + + for (i = 0; (i < Devices.MaxDevices) && (Tracks.RecordDevice==-1); i++) + { + if (Mapper_GetDevice(i)->Device.Type == Mapper_Midi_Device) + Tracks.RecordDevice = i; + } + + /* the record and edit devices are global constants + above the dynamic track info - init them here */ + Mapper_SetTrackInfo(); + Mapper_LoadPatches(); /* init the hardware */ + +RETURN_BOOL(True); +} + +int +Mapper_QueueEvent(EventList NextEvent, int *LastTime, float *PlayTime, + unsigned int StartLastTime, float StartPlayTime, float TimeInc) +{ +float DeltaTime; +BEGIN("Mapper_QueueEvent"); + + DeltaTime = ( (float)( NextEvent->Event.DeltaTime ) + - (float)(*LastTime) ) * TimeInc; + (*PlayTime) += DeltaTime; + + /* if buffered output is implemented, add a flush here before the sync */ + if ( -1 == ioctl(seqfd, SEQUENCER_SYNC, NULL) ) + perror("SEQUENCER_SYNC"); + + Mapper_nb2_wseq(&SEQ_MK_TIMING(WAIT_ABS, + .divisions = (int)(*PlayTime) - (int)StartPlayTime )); + + (*LastTime) = NextEvent->Event.DeltaTime; + +RETURN_INT((int)NextEvent->Event.DeltaTime); +} + +void +Mapper_InitVoiceAllocations() +{ + BEGIN("Mapper_InitVoiceAllocations"); + END; +} + +void +Mapper_Reset() +{ +int i; +BEGIN("Mapper_Reset"); + + if ( -1 == ioctl(seqfd, SEQUENCER_RESET, NULL) ) + perror("SEQUENCER_RESET"); +END; +} +void +Mapper_Initialize() +{ +BEGIN("Mapper_Initialize"); + + Mapper_Reset(); + Mapper_InitVoiceAllocations(); + +END; +} + + +/* + * Mapper_ReadEvent + * There doesn't seem to be much point in trying to make this work; looking + * at the Mapper_OSS code I'm not sure if I should think it was ever expected + * to work, and the main code seems to implement Record by iterating this + * function, not by using select, poll, or SIGIO, and that just can't be good. + */ +Boolean +Mapper_ReadEvent(MIDIRawEventBuffer ReturnEvent) +{ + BEGIN("Mapper_ReadEvent"); + RETURN_BOOL(False); +} + +void +Mapper_OpenActiveDevices() +{ + BEGIN("Mapper_OpenActiveDevices"); + /* do nothing */ + END; +} + +void +Mapper_CloseActiveDevices() +{ + BEGIN("Mapper_CloseActiveDevices"); + /* do nothing */ + END; +} --- mapper/src/Timer.c 1997-10-19 10:23:22.000000000 -0500 +++ mapper/src/Timer.c 2006-01-30 23:05:45.000000000 -0500 @@ -12,6 +12,10 @@ #include "Timer_OSS.c" #else +#ifdef SYSTEM_NETBSD +#include "Timer_NetBSD.c" +#else + #ifdef SYSTEM_SILENT #include "Timer_STUB.c" #else @@ -19,6 +23,7 @@ #error Internal inconsistency -- no SYSTEM symbol, not even SYSTEM_SILENT #endif /* SYSTEM_SILENT */ +#endif /* SYSTEM_NETBSD */ #endif /* SYSTEM_OSS */ #endif /* SYSTEM_ZILOG */ #endif /* SYSTEM_SGI */ --- mapper/src/Timer_NetBSD.c 1969-12-31 19:00:00.000000000 -0500 +++ mapper/src/Timer_NetBSD.c 2006-01-30 23:11:56.000000000 -0500 @@ -0,0 +1,43 @@ +/* + * Mapper Timer Routines + */ + +#include "Mapper.h" +#include + +void +Mapper_StopTimer() +{ +BEGIN("Mapper_StopTimer"); + + Mapper_nb2_wseq(&SEQ_MK_TIMING(STOP)); + +END; +} + +void +Mapper_ContinueTimer() +{ +BEGIN("Mapper_ContinueTimer"); + + Mapper_nb2_wseq(&SEQ_MK_TIMING(CONTINUE)); + +END; +} + +void +Mapper_StartTimer() +{ +BEGIN("Mapper_StartTimer"); + + Mapper_nb2_wseq(&SEQ_MK_TIMING(START)); + Mapper_nb2_wseq(&SEQ_MK_TIMING(ECHO, .cookie = Rosegarden_Echo_Key)); + +END; +} + +void Mapper_ModifyTimer(float f) +{ + fprintf(stderr, "Mapper_ModifyTimer: what am I supposed to do?\n"); +} + --- sequencer/src/Sequence.c 1997-10-25 10:49:45.000000000 -0500 +++ sequencer/src/Sequence.c 2006-02-01 17:28:29.000000000 -0500 @@ -237,12 +237,14 @@ NoteOffDevice; EventList NextNoteOnEvent, - NextNoteOffEvent = (EventList)XtMalloc(sizeof(EventListElement)); + NextNoteOffEvent; MIDIEvent MidiNoteOff; BEGIN("Midi_NextEvent"); + NextNoteOffEvent = (EventList)XtMalloc(sizeof(EventListElement)); + /* ++ get event and device next to play ++ */ if ( ( NextNoteOnEvent = Midi_NextNoteOn(&NoteOnDevice) ) == NULL )