DTintro(3dm) DTintro(3dm)
DTintro - Introduction to the Silicon Graphics DAT Audio Library (DT)
#include <sys/types.h>
#include <dmedia/dataudio.h>
-ldataudio
The Archive Python DAT (Digital Audio Tape) drive has the capability of
reading and writing audio tapes compatible with consumer and professional
DAT recorders. This man page describes the support for handling audio
tapes in the DAT drive. There are two components to the support: the
kernel SCSI tape driver and libdataudio.
SCSI Tape Driver
The kernel tape driver supports both regular data mode and the special
audio mode. The driver is switched between modes using the MTIOCTOP ioctl
as follows:
struct mtop mt_com;
mt_com.mt_op = MTAUD;
mt_com.mt_count = 1; /* 1 == audio mode, 0 == data mode */
ioctl(fd, MTIOCTOP, &mt_com);
The mode sticks until the tape is ejected or until a subsequent ioctl
request to switch modes. When an audio tape is read, the driver will
automatically switch to audio mode.
Once the driver is in audio mode the tape is read and written using the
normal read(2) and write(2) system calls. Reads and writes must be done
in multiples of a DTFRAME, [see datframe(4) ] the typedef describing one
frame of data on the tape otherwise your software will have no idea where
it is in the block structured audio data.
In audio mode the tape can be repositioned using the MTSETAUDIO ioctl to
search for a given location in any of the three time codes or for the
start of a given program number. For example the following code searches
for the start of program number 2.
struct mtaudio mt_aud;
bzero(&mt_aud, sizeof(mt_aud));
mt_aud.pno1 = 0;
mt_aud.pno2 = 0;
mt_aud.pno3 = 2;
mt_aud.seektype = MTAUDPOSN_PROG;
ioctl(fd, MTSETAUDIO, &mt_aud);
Page 1
DTintro(3dm) DTintro(3dm)
This puts the tape into a special 150X normal speed search mode. The
tape can be rewound, also at 150X normal speed, with the MTIOCTOP ioctl
as follows:
struct mtop mt_com;
mt_com.mt_op = MTREW;
mt_com.mt_count = 1;
ioctl(fd, MTIOCTOP, &mt_com);
These commands happen in immediate mode which means the ioctl's return
immediately. While the tape is moving the MTGETAUDIO ioctl can be used
to track the progress of the tape. To determine if the requested
operation has finished use the MTIOCGET ioctl and check the CT_SEEKING
bit in the error register. The following code, for example, initiates a
search for program 2, then loops until the search is finished continually
requesting the current position:
struct mtget mt_get;
struct mtaudio mt_aud;
bzero(&mt_aud, sizeof(mt_aud));
mt_aud.pno1 = 0;
mt_aud.pno2 = 0;
mt_aud.pno3 = 2;
mt_aud.seektype = MTAUDPOSN_PROG;
ioctl(fd, MTSETAUDIO, &mt_aud);
do {
ioctl(fd, MTGETAUDIO, &mt_aud);
/* do something with the position information */
ioctl(fd, MTIOCGET, &mt_get);
} while (mt_get.mt_erreg & (CT_SEEKING >> 16));
After the second ioctl call, mt_aud contains the program number and the
time codes (if present on the tape) of the location of the tape at the
time of the call.
libdataudio
The library contains a group of utility functions for handling some
elements of the sub code data and it contains support for parsing and
understanding the complete content of the digital audio data returned by
a read(2).
The utility functions are: DTatotime, DThmsftoframe, DTinctime, DTsbtoa,
DTtcvalid, DTtctoframe and DTtimetoa. DTatotime converts an ASCII string
into a time code suitable for writing on the tape or using as an argument
for the MTSETUDIO ioctl. DTinctime increments such a time code.
DTtctoframe converts a time code to a frame number. DTtcvalid checks a
time code for validity. DTtimetoa converts a time code to ASCII.
DThmsftoframe converts an hours, minutes, seconds, frame quadruple into a
Page 2
DTintro(3dm) DTintro(3dm)
frame number. DTsbtoa converts a string encoded in the six-bit code of
the International Standard Recording Code into an ASCII string.
libdataudio supports breaking down of the digital audio data into more
manageable units. You should first read datframe(4) for complete details
of the format of a DTFRAME, the block of data read from the tape. The
DAT parser dissects the frame of data and for each data item it finds, it
can execute a function in your code to which it passes the data. See
DTaddcallback for complete details of the callback functions. The parser
functions are DTcreateparser, DTdeleteparser, DTaddcallback,
DTparseframe, DTresetparser, DTremovecallback and DTdeleteparser.
The following example opens the tape drive, switches it to audio mode
then constantly reads DTFRAMEs from the tape and hands them to the
parser. It has one callback set up to play the audio data The parser
will call this function with the audio data which it will have byteswapped
and de-emphasized if the tape's pre-emphasis bit is turned on.
The example uses another callback to keep track of the sampling
frequency.
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/mtio.h>
#include <dmedia/audio.h>
#include <dmedia/dataudio.h>
#include <stdio.h>
/*
* playdat.c
*
* simple DAT playing program
* adapted from the dataudio man page example code.
*
*/
#define NUMBLOCKS 4
static int sampsperframe = DTDA_NUMSAMPS44K;
ALport audioport;
int isPaused;
void
playaudio(void *arg, DTDATATYPES type, short *audio)
{
ALwritesamps(audioport, audio, sampsperframe);
}
void
frequency(void *arg, DTDATATYPES type, int *freq)
{
switch (*freq) {
case DT_FREQ48000:
Page 3
DTintro(3dm) DTintro(3dm)
sampsperframe = DTDA_NUMSAMPS48K;
break;
case DT_FREQ44100:
sampsperframe = DTDA_NUMSAMPS44K;
break;
case DT_FREQ32000:
sampsperframe = DTDA_NUMSAMPS32K;
break;
}
}
main()
{
int tape = open("/dev/nrtape", O_RDONLY);
DTPARSER *dtp = DTcreateparser();
DTFRAME buf[NUMBLOCKS];
struct mtop mt_com;
int i, n;
audioport = ALopenport("DAT Test", "w", 0);
if (dtp) {
DTsetcallback(dtp, dt_audio, (DTCALLBACKFUNC)playaudio, 0);
DTsetcallback(dtp, dt_sampfreq, (DTCALLBACKFUNC)frequency, 0);
} else
exit(1);
if (tape >= 0) {
mt_com.mt_op = MTAUD;
mt_com.mt_count = 1;
if (ioctl(tape, MTIOCTOP, &mt_com) < 0) {
fprintf(stderr, "MTIOCTOP failed.0);
exit(-1);
}
while (1) {
while (!isPaused) {
n = read(tape, buf, sizeof(buf));
if (n < 0) {
fprintf(stderr, "tape error! (is audio tape in drive?)0);
exit(-1);
}
if (n == 0) /* We're at the end of the tape*/
break;
for (i = 0; i < NUMBLOCKS; i++)
DTparseframe(dtp, &buf[i]);
}
while (isPaused) {
sginap(2);
}
}
}
else {
fprintf(stderr, "tape open failed0);
}
Page 4
DTintro(3dm) DTintro(3dm)
exit(-1);
}
In deemphasis filtering floating point underflows are normal and
expected. Thus underflows may happen when DTparseframe is called if you
have a dt_audio callback and the incoming data is pre-emphasized. IRIX'
default underflow handling causes a trap to the kernel on each underflow
followed by a software emulation of the calculation that produces a denormalized
result. The resulting value, when used in a subsequent
calculation, can cause another underflow and kernel trap. The cycle
repeats leading to a complete loss of performance to the point where the
tape will not play in real time.
A saner method of handling underflows in this case is to trap on the
first one and replace the result with zero. Subsequent operations then
do not cause traps, thus performance remains at an acceptable level. The
two lines of code in the previous example referring to sigfpe set up this
saner method of handling the exceptions. See sigfpe(3C) for more
details. This code can't be put into the library because it affects
global state for the program and the programmer may not always want this
type of exception handling. They may want the correct slow result in
some parts of their program.
This example must be linked with -lfpe in addition to the libraries shown
above.
/usr/include/dmedia/dataudio.h
/usr/include/mtio.h
/usr/include/sys/tpsc.h
/usr/lib/libdataudio.a /usr/share/src/dmedia/cd+dat/* - example code
DTaddcallback(3dm), DTatohmsf(3dm), DTatotime(3dm), DTcreateparser(3dm),
DTdeleteparser(3dm), DTframetohmsf(3dm), DTframetotc(3dm),
DThmsftoframe(3dm), DTinctime(3dm), DTparseframe(3dm), DTpnotodec(3dm),
DTremovecallback(3dm), DTresetparser(3dm), DTsbtoa(3dm), DTsetdat
, DTtcvalid(3dm), DTtimetoa(3dm), datframe(4), ioctl(2),
mt(1), mtio(7), open(2), read(2), sigfpe(3C), tps(7m)
Mark Callow
PPPPaaaaggggeeee 5555 [ Back ]
|