blob: e30c233bfb0594a7659b770d3e33ada1e5520d07 [file] [log] [blame] [edit]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include "log.h"
#include "io_misc.h"
#include "midi.h"
#define MIDI_OSS_DEVICE_PATH "/dev/sequencer";
struct MidiDeviceStruct {
int fileDescriptor;
int deviceNumber;
/*SEQ_DEFINEBUF(0X80);*/
unsigned char buffer[0X80];
int bufferLength;
int bufferUsed;
};
#ifndef SAMPLE_TYPE_AWE
#define SAMPLE_TYPE_AWE 0x20
#endif /* SAMPLE_TYPE_AWE */
static MidiDevice *midiDevice = NULL;
#define _seqbuf midiDevice->buffer
#define _seqbuflen midiDevice->bufferLength
#define _seqbufptr midiDevice->bufferUsed
void
seqbuf_dump (void) {
if (_seqbufptr)
if (writeFile(midiDevice->fileDescriptor, _seqbuf, _seqbufptr) == -1)
logSystemError("MIDI write");
_seqbufptr = 0;
}
MidiDevice *
openMidiDevice (int errorLevel, const char *device) {
MidiDevice *midi;
if ((midi = malloc(sizeof(*midi)))) {
if (!*device) device = MIDI_OSS_DEVICE_PATH;
if ((midi->fileDescriptor = open(device, O_WRONLY)) != -1) {
{
int count;
int awe = -1;
int fm = -1;
int gus = -1;
int ext = -1;
if (ioctl(midi->fileDescriptor, SNDCTL_SEQ_NRSYNTHS, &count) != -1) {
int index;
for (index=0; index<count; ++index) {
struct synth_info info;
info.device = index;
if (ioctl(midi->fileDescriptor, SNDCTL_SYNTH_INFO, &info) != -1) {
switch (info.synth_type) {
case SYNTH_TYPE_SAMPLE:
switch (info.synth_subtype) {
case SAMPLE_TYPE_AWE:
awe = index;
continue;
case SAMPLE_TYPE_GUS:
gus = index;
continue;
}
break;
case SYNTH_TYPE_FM:
fm = index;
continue;
}
logMessage(LOG_DEBUG, "Unknown synthesizer: %d[%d]: %s",
info.synth_type, info.synth_subtype, info.name);
} else {
logMessage(errorLevel, "Cannot get description for synthesizer %d: %s",
index, strerror(errno));
}
}
if (gus >= 0)
if (ioctl(midi->fileDescriptor, SNDCTL_SEQ_RESETSAMPLES, &gus) == -1)
logMessage(errorLevel, "Cannot reset samples for gus synthesizer %d: %s",
gus, strerror(errno));
} else {
logMessage(errorLevel, "Cannot get MIDI synthesizer count: %s",
strerror(errno));
}
if (ioctl(midi->fileDescriptor, SNDCTL_SEQ_NRMIDIS, &count) != -1) {
if (count > 0) ext = count - 1;
} else {
logMessage(errorLevel, "Cannot get MIDI device count: %s",
strerror(errno));
}
midi->deviceNumber = (awe >= 0)? awe:
(gus >= 0)? gus:
(fm >= 0)? fm:
(ext >= 0)? ext:
0;
}
midi->bufferLength = sizeof(midi->buffer);
midi->bufferUsed = 0;
return midi;
} else {
logMessage(errorLevel, "Cannot open MIDI device: %s: %s", device, strerror(errno));
}
free(midi);
} else {
logSystemError("MIDI device allocation");
}
return NULL;
}
void
closeMidiDevice (MidiDevice *midi) {
close(midi->fileDescriptor);
free(midi);
}
static void
beginMidiOperation (MidiDevice *midi) {
midiDevice = midi;
}
static int
endMidiOperation (MidiDevice *midi) {
midiDevice = NULL;
return 1;
}
int
flushMidiDevice (MidiDevice *midi) {
beginMidiOperation(midi);
seqbuf_dump();
return endMidiOperation(midi);
}
int
setMidiInstrument (MidiDevice *midi, unsigned char channel, unsigned char instrument) {
beginMidiOperation(midi);
SEQ_SET_PATCH(midi->deviceNumber, channel, instrument);
return endMidiOperation(midi);
}
int
beginMidiBlock (MidiDevice *midi) {
beginMidiOperation(midi);
SEQ_START_TIMER();
return endMidiOperation(midi);
}
int
endMidiBlock (MidiDevice *midi) {
beginMidiOperation(midi);
SEQ_STOP_TIMER();
seqbuf_dump();
ioctl(midi->fileDescriptor, SNDCTL_SEQ_SYNC);
return endMidiOperation(midi);
}
int
startMidiNote (MidiDevice *midi, unsigned char channel, unsigned char note, unsigned char volume) {
beginMidiOperation(midi);
SEQ_START_NOTE(midi->deviceNumber, channel, note, 0X7F*volume/100);
return endMidiOperation(midi);
}
int
stopMidiNote (MidiDevice *midi, unsigned char channel) {
beginMidiOperation(midi);
SEQ_STOP_NOTE(midi->deviceNumber, channel, 0, 0);
return endMidiOperation(midi);
}
int
insertMidiWait (MidiDevice *midi, int duration) {
beginMidiOperation(midi);
SEQ_DELTA_TIME((duration + 9) / 10);
return endMidiOperation(midi);
}