* linux/kernel/chr_drv/sound/sequencer.c
* The sequencer personality manager.
* (C) 1992 Hannu Savolainen (hsavolai@cs.helsinki.fi) See COPYING for further
* details. Should be distributed with this file.
#include "sound_config.h"
#ifdef CONFIGURE_SOUNDCARD
#ifndef EXCLUDE_SEQUENCER
static int sequencer_ok
= 0;
DEFINE_WAIT_QUEUE (seq_sleeper
, seq_sleep_flag
);
DEFINE_WAIT_QUEUE (midi_sleeper
, midi_sleep_flag
);
static int midi_opened
[MAX_MIDI_DEV
] =
{0}; /* 1 if the process has opened MIDI */
static int midi_written
[MAX_MIDI_DEV
] =
long seq_time
= 0; /* Reference point for the timer */
static unsigned char queue
[SEQ_MAX_QUEUE
][EV_SZ
];
static unsigned char iqueue
[SEQ_MAX_QUEUE
][4];
static volatile int qhead
= 0, qtail
= 0, qlen
= 0;
static volatile int iqhead
= 0, iqtail
= 0, iqlen
= 0;
static volatile int seq_playing
= 0;
static int sequencer_busy
= 0;
static int output_treshold
;
static unsigned synth_open_mask
;
static int seq_queue (unsigned char *note
);
static void seq_startplay (void);
static int seq_sync (void);
static void seq_reset (void);
static int pmgr_present
[MAX_SYNTH_DEV
] =
#error Too many synthesizer devices
sequencer_read (int dev
, struct fileinfo
*file
, snd_rw_buf
* buf
, int count
)
if (dev
) /* Patch manager device */
return pmgr_read (dev
- 1, file
, buf
, count
);
INTERRUPTIBLE_SLEEP_ON (midi_sleeper
, midi_sleep_flag
);
COPY_TO_USER (buf
, p
, &iqueue
[iqhead
][0], 4);
iqhead
= (iqhead
+ 1) % SEQ_MAX_QUEUE
;
sequencer_midi_output (int dev
)
copy_to_input (unsigned char *event
)
if (iqlen
>= (SEQ_MAX_QUEUE
- 1))
memcpy (iqueue
[iqtail
], event
, 4);
iqtail
= (iqtail
+ 1) % SEQ_MAX_QUEUE
;
sequencer_midi_input (int dev
, unsigned char data
)
if (data
== 0xfe) /* Active sensing */
tstamp
= GET_TIME () - seq_time
; /* Time since open() */
tstamp
= (tstamp
<< 8) | SEQ_WAIT
;
copy_to_input ((unsigned char *) &tstamp
);
sequencer_write (int dev
, struct fileinfo
*file
, snd_rw_buf
* buf
, int count
)
unsigned char event
[EV_SZ
], ev_code
;
int mode
= file
->mode
& O_ACCMODE
;
DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev
, count
));
if (dev
) /* Patch manager device */
return pmgr_write (dev
- 1, file
, buf
, count
);
COPY_FROM_USER (event
, buf
, p
, 4);
if (ev_code
== SEQ_FULLSIZE
)
dev
= *(unsigned short *) &event
[2];
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << dev
)))
return RET_ERROR (ENXIO
);
err
= synth_devs
[dev
]->load_patch (dev
, *(short *) &event
[0], buf
, p
+ 4, c
, 0);
if (ev_code
== SEQ_EXTENDED
|| ev_code
== SEQ_PRIVATE
)
COPY_FROM_USER (&event
[4], buf
, p
+ 4, 4);
if (event
[0] == SEQ_MIDIPUTC
)
if (!midi_opened
[event
[2]])
printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev
);
return RET_ERROR (ENXIO
);
mode
= file
->mode
& O_ACCMODE
;
if ((err
= midi_devs
[dev
]->open (dev
, mode
)) < 0)
printk ("Sequencer Error: Unable to open Midi #%d\n", dev
);
seq_queue (unsigned char *note
)
/* Test if there is space in the queue */
if (qlen
>= SEQ_MAX_QUEUE
)
seq_startplay (); /* Give chance to drain the queue */
if (qlen
>= SEQ_MAX_QUEUE
&& !seq_sleep_flag
)
/* Sleep until there is enough space on the queue */
INTERRUPTIBLE_SLEEP_ON (seq_sleeper
, seq_sleep_flag
);
if (qlen
>= SEQ_MAX_QUEUE
)
return 0; /* To be sure */
memcpy (&queue
[qtail
][0], note
, EV_SZ
);
qtail
= (qtail
+ 1) % SEQ_MAX_QUEUE
;
extended_event (unsigned char *q
)
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << dev
)))
return RET_ERROR (ENXIO
);
synth_devs
[dev
]->kill_note (dev
, q
[3], q
[5]);
if (q
[4] > 127 && q
[4] != 255)
synth_devs
[dev
]->start_note (dev
, q
[3], q
[4], q
[5]);
synth_devs
[dev
]->set_instr (dev
, q
[3], q
[4]);
synth_devs
[dev
]->aftertouch (dev
, q
[3], q
[4]);
synth_devs
[dev
]->panning (dev
, q
[3], (char) q
[4]);
synth_devs
[dev
]->controller (dev
, q
[3], q
[4], *(short *) &q
[5]);
return RET_ERROR (EINVAL
);
qhead
= ((this_one
= qhead
) + 1) % SEQ_MAX_QUEUE
;
if (synth_open_mask
& (1 << 0))
synth_devs
[0]->kill_note (0, q
[1], q
[3]);
if (q
[4] < 128 || q
[4] == 255)
if (synth_open_mask
& (1 << 0))
synth_devs
[0]->start_note (0, q
[1], q
[2], q
[3]);
delay
= (unsigned long *) q
; /* Bytes 1 to 3 are containing the
*delay
= (*delay
>> 8) & 0xffffff;
request_sound_timer (time
);
if ((SEQ_MAX_QUEUE
- qlen
) >= output_treshold
)
return; /* Stop here. Timer routine will continue
* playing after the delay */
if (synth_open_mask
& (1 << 0))
synth_devs
[0]->set_instr (0, q
[1], q
[2]);
case SEQ_SYNCTIMER
: /* Reset timer */
case SEQ_MIDIPUTC
: /* Put a midi character */
if (!midi_devs
[dev
]->putc (dev
, q
[1]))
* Output FIFO is full. Wait one timer cycle and try again.
qhead
= this_one
; /* Restore queue */
request_sound_timer (-1);
copy_to_input (q
); /* Echo back to the process */
synth_devs
[q
[1]]->hw_control (q
[1], q
);
if ((SEQ_MAX_QUEUE
- qlen
) >= output_treshold
)
sequencer_open (int dev
, struct fileinfo
*file
)
mode
= file
->mode
& O_ACCMODE
;
DEB (printk ("sequencer_open(dev=%d)\n", dev
));
printk ("Soundcard: Sequencer not initialized\n");
return RET_ERROR (ENXIO
);
if (dev
) /* Patch manager device */
return RET_ERROR (EBUSY
);
if ((err
= pmgr_open (dev
)) < 0)
printk ("Sequencer busy\n");
return RET_ERROR (EBUSY
);
if (!(num_synths
+ num_midis
))
return RET_ERROR (ENXIO
);
if (mode
== OPEN_WRITE
|| mode
== OPEN_READWRITE
)
for (i
= 0; i
< num_synths
; i
++) /* Open synth devices */
if (synth_devs
[i
]->open (i
, mode
) < 0)
printk ("Sequencer: Warning! Cannot open synth device #%d\n", i
);
synth_open_mask
|= (1 << i
);
for (i
= 0; i
< num_midis
; i
++)
if (mode
== OPEN_READ
|| mode
== OPEN_READWRITE
)
{ /* Initialize midi input devices */
printk ("Sequencer: No Midi devices. Input not possible\n");
return RET_ERROR (ENXIO
);
for (i
= 0; i
< num_midis
; i
++)
if ((retval
= midi_devs
[i
]->open (i
, mode
)) >= 0)
seq_sleep_flag
= midi_sleep_flag
= 0;
output_treshold
= SEQ_MAX_QUEUE
/ 2;
for (i
= 0; i
< num_synths
; i
++)
pmgr_inform (i
, PM_E_OPENED
, 0, 0, 0, 0);
seq_drain_midi_queues (void)
* Give the Midi drivers time to drain their output queues
while (!PROCESS_ABORTING
&& n
)
for (i
= 0; i
< num_midis
; i
++)
if (midi_opened
[i
] && midi_written
[i
])
if (midi_devs
[i
]->buffer_status
!= NULL
)
if (midi_devs
[i
]->buffer_status (i
))
REQUEST_TIMEOUT (HZ
/ 10, seq_sleeper
);
INTERRUPTIBLE_SLEEP_ON (seq_sleeper
, seq_sleep_flag
);
sequencer_release (int dev
, struct fileinfo
*file
)
int mode
= file
->mode
& O_ACCMODE
;
DEB (printk ("sequencer_release(dev=%d)\n", dev
));
if (dev
) /* Patch manager device */
* Wait until the queue is empty
while (!PROCESS_ABORTING
&& qlen
)
seq_drain_midi_queues (); /* Ensure the output queues are empty */
seq_drain_midi_queues (); /* Flush the all notes off messages */
for (i
= 0; i
< num_midis
; i
++)
if (mode
== OPEN_WRITE
|| mode
== OPEN_READWRITE
)
for (i
= 0; i
< num_synths
; i
++)
if (synth_open_mask
& (1 << i
)) /* Actually opened */
synth_devs
[i
]->close (i
);
for (i
= 0; i
< num_synths
; i
++)
pmgr_inform (i
, PM_E_CLOSED
, 0, 0, 0, 0);
if (qlen
&& !seq_playing
&& !PROCESS_ABORTING
)
if (qlen
&& !seq_sleep_flag
) /* Queue not empty */
INTERRUPTIBLE_SLEEP_ON (seq_sleeper
, seq_sleep_flag
);
midi_outc (int dev
, unsigned char data
)
* NOTE! Calls sleep(). Don't call this from interrupt.
/* This routine sends one byte to the Midi channel. */
/* If the output Fifo is full, it waits until there */
/* is space in the queue */
n
= 300; /* Timeout in jiffies */
while (n
&& !midi_devs
[dev
]->putc (dev
, data
))
REQUEST_TIMEOUT (1, seq_sleeper
);
INTERRUPTIBLE_SLEEP_ON (seq_sleeper
, seq_sleep_flag
);
* NOTE! Calls sleep(). Don't call this from interrupt.
qlen
= qhead
= qtail
= 0;
iqlen
= iqhead
= iqtail
= 0;
for (i
= 0; i
< num_synths
; i
++)
if (synth_open_mask
& (1 << i
))
synth_devs
[i
]->reset (i
);
for (i
= 0; i
< num_midis
; i
++)
if (midi_written
[i
]) /* Midi used. Some notes may still be playing */
for (chn
= 0; chn
< 16; chn
++)
midi_outc (i
, 0xb0 + chn
); /* Channel message */
midi_outc (i
, 0x7b);/* All notes off */
midi_outc (i
, 0); /* Dummy parameter */
printk ("Sequencer Warning: Unexpected sleeping process\n");
sequencer_ioctl (int dev
, struct fileinfo
*file
,
unsigned int cmd
, unsigned int arg
)
int mode
= file
->mode
& O_ACCMODE
;
orig_dev
= dev
= dev
>> 4;
if (dev
) /* Patch manager */
while (qlen
&& !PROCESS_ABORTING
)
if (dev
) /* Patch manager */
case SNDCTL_SEQ_TESTMIDI
:
if (dev
) /* Patch manager */
midi_dev
= IOCTL_IN (arg
);
if (midi_dev
>= num_midis
)
return RET_ERROR (ENXIO
);
if (!midi_opened
[midi_dev
])
mode
= file
->mode
& O_ACCMODE
;
if ((err
= midi_devs
[midi_dev
]->open (midi_dev
, mode
)) < 0)
midi_opened
[midi_dev
] = 1;
case SNDCTL_SEQ_GETINCOUNT
:
if (dev
) /* Patch manager */
return IOCTL_OUT (arg
, iqlen
);
case SNDCTL_SEQ_GETOUTCOUNT
:
return IOCTL_OUT (arg
, SEQ_MAX_QUEUE
- qlen
);
case SNDCTL_SEQ_CTRLRATE
:
if (dev
) /* Patch manager */
/* If *arg == 0, just return the current rate */
return IOCTL_OUT (arg
, HZ
);
case SNDCTL_SEQ_RESETSAMPLES
:
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << dev
)) && !orig_dev
)
return RET_ERROR (EBUSY
);
if (!orig_dev
&& pmgr_present
[dev
])
pmgr_inform (dev
, PM_E_PATCH_RESET
, 0, 0, 0, 0);
return synth_devs
[dev
]->ioctl (dev
, cmd
, arg
);
case SNDCTL_SEQ_NRSYNTHS
:
return IOCTL_OUT (arg
, num_synths
);
return IOCTL_OUT (arg
, num_midis
);
case SNDCTL_SYNTH_MEMAVL
:
int dev
= IOCTL_IN (arg
);
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << dev
)) && !orig_dev
)
return RET_ERROR (EBUSY
);
return IOCTL_OUT (arg
, synth_devs
[dev
]->ioctl (dev
, cmd
, arg
));
case SNDCTL_FM_4OP_ENABLE
:
int dev
= IOCTL_IN (arg
);
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << dev
)))
return RET_ERROR (ENXIO
);
synth_devs
[dev
]->ioctl (dev
, cmd
, arg
);
IOCTL_FROM_USER ((char *) &inf
, (char *) arg
, 0, sizeof (inf
));
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << dev
)) && !orig_dev
)
return RET_ERROR (EBUSY
);
return synth_devs
[dev
]->ioctl (dev
, cmd
, arg
);
IOCTL_FROM_USER ((char *) &inf
, (char *) arg
, 0, sizeof (inf
));
if (dev
< 0 || dev
>= num_midis
)
return RET_ERROR (ENXIO
);
IOCTL_TO_USER ((char *) arg
, 0, (char *) &(midi_devs
[dev
]->info
), sizeof (inf
));
inf
= (struct patmgr_info
*) KERNEL_MALLOC (sizeof (*inf
));
IOCTL_FROM_USER ((char *) inf
, (char *) arg
, 0, sizeof (*inf
));
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
if (!synth_devs
[dev
]->pmgr_interface
)
return RET_ERROR (ENXIO
);
if ((err
= synth_devs
[dev
]->pmgr_interface (dev
, inf
)) == -1)
IOCTL_TO_USER ((char *) arg
, 0, (char *) inf
, sizeof (*inf
));
inf
= (struct patmgr_info
*) KERNEL_MALLOC (sizeof (*inf
));
IOCTL_FROM_USER ((char *) inf
, (char *) arg
, 0, sizeof (*inf
));
if (dev
< 0 || dev
>= num_synths
)
return RET_ERROR (ENXIO
);
return RET_ERROR (ESRCH
);
if ((err
= pmgr_access (dev
, inf
)) < 0)
IOCTL_TO_USER ((char *) arg
, 0, (char *) inf
, sizeof (*inf
));
case SNDCTL_SEQ_TRESHOLD
:
int tmp
= IOCTL_IN (arg
);
if (dev
) /* Patch manager */
if (tmp
>= SEQ_MAX_QUEUE
)
if (dev
) /* Patch manager */
return RET_ERROR (ENXIO
);
if (!(synth_open_mask
& (1 << 0)))
return RET_ERROR (ENXIO
);
return synth_devs
[0]->ioctl (0, cmd
, arg
);
return RET_ERROR (EINVAL
);
sequencer_select (int dev
, struct fileinfo
*file
, int sel_type
, select_table
* wait
)
select_wait (&midi_sleeper
, wait
);
if (qlen
>= SEQ_MAX_QUEUE
)
select_wait (&seq_sleeper
, wait
);
note_to_freq (int note_num
)
* This routine converts a midi note to a frequency (multiplied by 1000)
int note
, octave
, note_freq
;
261632, 277189, 293671, 311132, 329632, 349232,
369998, 391998, 415306, 440000, 466162, 493880
}; /* Note freq*1000 for octave 5 */
if (octave
< BASE_OCTAVE
)
note_freq
>>= (BASE_OCTAVE
- octave
);
else if (octave
> BASE_OCTAVE
)
note_freq
<<= (octave
- BASE_OCTAVE
);
compute_finetune (unsigned long base_freq
, int bend
, int range
)
int negative
, semitones
, cents
;
bend
= bend
* range
/ 8192;
negative
= bend
< 0 ? 1 : 0;
amount
= semitone_tuning
[semitones
] * cent_tuning
[cents
] / 10000;
return (base_freq
* 10000) / amount
; /* Bend down */
return (base_freq
* amount
) / 10000; /* Bend up */
sequencer_init (long mem_start
)
sequencer_read (int dev
, struct fileinfo
*file
, snd_rw_buf
* buf
, int count
)
sequencer_write (int dev
, struct fileinfo
*file
, snd_rw_buf
* buf
, int count
)
sequencer_open (int dev
, struct fileinfo
*file
)
return RET_ERROR (ENXIO
);
sequencer_release (int dev
, struct fileinfo
*file
)
sequencer_ioctl (int dev
, struct fileinfo
*file
,
unsigned int cmd
, unsigned int arg
)
sequencer_lseek (int dev
, struct fileinfo
*file
, off_t offset
, int orig
)
sequencer_init (long mem_start
)
sequencer_midi_input (int dev
, unsigned char data
)
sequencer_midi_output (int dev
)
sequencer_select (int dev
, struct fileinfo
*file
, int sel_type
, select_table
* wait
)