home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / cdsend12 / part01 < prev    next >
Encoding:
Text File  |  1993-04-14  |  23.4 KB  |  883 lines

  1. Newsgroups: comp.sources.unix
  2. From: Sjoerd.Mullender@cwi.nl (Sjoerd Mullender)
  3. Subject: v26i165: cdsend - read music CD's via SCSI, convert and play [SGI], Part01/01
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: Sjoerd.Mullender@cwi.nl (Sjoerd Mullender)
  8. Posting-Number: Volume 26, Issue 165
  9. Archive-Name: cdsend1.2/part01
  10.  
  11. Cdsend reads audio CD's over the SCSI bus, converts the data to a format
  12. suitable for broadcast, and writes this converted data to standard output.
  13. Optionally, the music is also played over the system's own speakers.
  14.  
  15. Cdsend only works on certain Silicon Graphics systems.  It was developed on
  16. an Iris Indigo.
  17.  
  18. The db_get_*.c files were grabbed off the net and were written by people at
  19. SGI.
  20.  
  21. The code in the file convert.c was taken from sox and adapted to incorporate
  22. it into cdsend.
  23.  
  24.     Sjoerd Mullender, CWI, Amsterdam (email: Sjoerd.Mullender@cwi.nl).
  25.  
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then unpack
  28. # it by saving it into a file and typing "sh file".  To overwrite existing
  29. # files, type "sh file -c".  You can also feed this as standard input via
  30. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  31. # will see the following message at the end:
  32. #        "End of archive 1 (of 1)."
  33. # Contents:  MANIFEST Makefile README cdsend.1 cdsend.c cdsend.h
  34. #   convert.c db_get_TOC.c db_get_id.c
  35. # Wrapped by vixie@gw.home.vix.com on Thu Apr 15 18:45:22 1993
  36. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  37. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  38.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  39. else
  40. echo shar: Extracting \"'MANIFEST'\" \(393 characters\)
  41. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  42. X   File Name        Archive #    Description
  43. X-----------------------------------------------------------
  44. X MANIFEST                   1    This shipping list
  45. X Makefile                   1    
  46. X README                     1    
  47. X cdsend.1                   1    
  48. X cdsend.c                   1    
  49. X cdsend.h                   1    
  50. X convert.c                  1    
  51. X db_get_TOC.c               1    
  52. X db_get_id.c                1    
  53. END_OF_FILE
  54. if test 393 -ne `wc -c <'MANIFEST'`; then
  55.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  56. fi
  57. # end of 'MANIFEST'
  58. fi
  59. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  60.   echo shar: Will not clobber existing file \"'Makefile'\"
  61. else
  62. echo shar: Extracting \"'Makefile'\" \(301 characters\)
  63. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  64. CFLAGS = -O
  65. X
  66. all:    cdsend
  67. X
  68. cdsend:    cdsend.o convert.o libcddb.a
  69. X    $(CC) -o cdsend cdsend.o convert.o libcddb.a -lcdaudio -lds -laudio -lc_s
  70. X
  71. clean:
  72. X    -rm -f cdsend *.o *~ core
  73. X
  74. cdsend.o convert.o:    cdsend.h
  75. X
  76. libcddb.a:    db_get_TOC.o db_get_id.o
  77. X        rm -f libcddb.a
  78. X        ar cr libcddb.a db_get_TOC.o db_get_id.o
  79. END_OF_FILE
  80. if test 301 -ne `wc -c <'Makefile'`; then
  81.     echo shar: \"'Makefile'\" unpacked with wrong size!
  82. fi
  83. # end of 'Makefile'
  84. fi
  85. if test -f 'README' -a "${1}" != "-c" ; then 
  86.   echo shar: Will not clobber existing file \"'README'\"
  87. else
  88. echo shar: Extracting \"'README'\" \(563 characters\)
  89. sed "s/^X//" >'README' <<'END_OF_FILE'
  90. Cdsend reads audio CD's over the SCSI bus, converts the data to a
  91. format suitable for broadcast, and writes this converted data to
  92. standard output.  Optionally, the music is also played over the
  93. system's own speakers.
  94. X
  95. Cdsend only works on certain Silicon Graphics systems.  It was
  96. developed on an Iris Indigo.
  97. X
  98. The db_get_*.c files were grabbed off the net and were written by
  99. people at SGI.
  100. X
  101. The code in the file convert.c was taken from sox and adapted to
  102. incorporate it into cdsend.
  103. X
  104. Author: Sjoerd Mullender, CWI, Amsterdam (email: Sjoerd.Mullender@cwi.nl).
  105. END_OF_FILE
  106. if test 563 -ne `wc -c <'README'`; then
  107.     echo shar: \"'README'\" unpacked with wrong size!
  108. fi
  109. # end of 'README'
  110. fi
  111. if test -f 'cdsend.1' -a "${1}" != "-c" ; then 
  112.   echo shar: Will not clobber existing file \"'cdsend.1'\"
  113. else
  114. echo shar: Extracting \"'cdsend.1'\" \(2845 characters\)
  115. sed "s/^X//" >'cdsend.1' <<'END_OF_FILE'
  116. X.TH CDSEND 1 sgi
  117. X.SH NAME
  118. cdsend \- read an audio CD and convert
  119. X.SH SYNOPSIS
  120. X.B cdsend
  121. X[
  122. X.B \-c
  123. X.I catalogfile
  124. X] [
  125. X.B \-n
  126. X] [
  127. X.B \-d
  128. X] [
  129. X.B \-p
  130. X] [
  131. X.B \-l
  132. X]
  133. X.SH DESCRIPTION
  134. X.I Cdsend
  135. reads audio CD's through the SCSI bus and converts the data to one of
  136. several formats.  The formats are 8kHz, mono, U-law (1 byte per
  137. sample), and 8kHz, mono, linear (2 bytes per sample).  The default is
  138. to convert to U-law.  Linear can be chosen by using the
  139. X.B \-l
  140. option.
  141. X.PP
  142. When a CD has been read completely, it is automatically ejected from
  143. the drive.  When in daemon mode,
  144. X.I cdsend
  145. will then wait for a new CD to be inserted.  If a CD that is not an
  146. audio CD is inserted, it is ignored.  This means that
  147. X.I cdsend
  148. does not have to be killed when the CD-ROM drive has to be used for
  149. software installations.  Daemon mode is selected by using the
  150. X.B \-d
  151. flag.
  152. X.PP
  153. Optionally,
  154. X.I cdsend
  155. will play the unconverted sound through the audio interface.  This can
  156. be enabled using the
  157. X.B \-p
  158. option or by sending a SIGHUP to
  159. X.IR cdsend .
  160. X.PP
  161. X.I Cdsend
  162. writes information that identifies the CD being read to a file.  The
  163. name of the file is $HOME/.CDcatalognumber, unless another file is
  164. specified using the
  165. X.B \-c
  166. flag.  The information written consists of three lines.  All lines are
  167. of the form
  168. X.IR identifier=value .
  169. The first line is the result of a hash function on the CD's table of
  170. contents.  This is the same value that is used by
  171. X.IR cdman (1)
  172. to generate a file name for the title of the CD.  The second line is
  173. the table of contents.  The table of contents is encoded in the way
  174. that
  175. X.IR cdplayer (1)
  176. and
  177. X.IR cdman (1)
  178. use.  The third line is either the catalog number on the CD (if
  179. present) or the total playing time of the CD in the format
  180. X.IR tracks.minutes.seconds.frames .
  181. X.PP
  182. When the
  183. X.B \-n
  184. flag is present,
  185. X.I cdsend
  186. will run with a non-degrading priority.  The priority chosen is
  187. NDPNORMMAX, which is the lowest non-degrading priority higher than the
  188. normal user priorities.  This option will only have an effect if
  189. X.I cdsend
  190. is installed set-uid root.
  191. X.PP
  192. When playing,
  193. X.I cdsend
  194. can still be influenced.  This is done by sending certain signals to
  195. the process.  The following signals are accepted.
  196. X.TP
  197. X.B SIGHUP
  198. Toggle between playing and not playing through the system's audio interface.
  199. X.TP
  200. X.B SIGUSR1
  201. Stop playing the current CD and eject it.
  202. X.PP
  203. When
  204. X.I cdsend
  205. stops playing, whether it is because the CD has finished ot because it
  206. was sent a SIGHUP, it sets the sampling rate of the audio interface
  207. back.
  208. X.PP
  209. Typically,
  210. X.I cdsend
  211. is started as follows:
  212. X.IP
  213. cdsend -dnpl | broadcast -l -a -b <broadcast address> &
  214. X.PP
  215. With older broadcast programs you may need to use the following:
  216. X.IP
  217. cdsend -dnp | broadcast -b <broadcast address> &
  218. X.SH SEE ALSO
  219. X.IR schedctl (2),
  220. X.IR apanel (1),
  221. X.IR cdman (1),
  222. X.IR cdplayer (1),
  223. X.IR broadcast (1).
  224. END_OF_FILE
  225. if test 2845 -ne `wc -c <'cdsend.1'`; then
  226.     echo shar: \"'cdsend.1'\" unpacked with wrong size!
  227. fi
  228. # end of 'cdsend.1'
  229. fi
  230. if test -f 'cdsend.c' -a "${1}" != "-c" ; then 
  231.   echo shar: Will not clobber existing file \"'cdsend.c'\"
  232. else
  233. echo shar: Extracting \"'cdsend.c'\" \(8872 characters\)
  234. sed "s/^X//" >'cdsend.c' <<'END_OF_FILE'
  235. X/***********************************************************
  236. Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
  237. Netherlands.
  238. X
  239. X                        All Rights Reserved
  240. X
  241. Permission to use, copy, modify, and distribute this software and its 
  242. documentation for any purpose and without fee is hereby granted, 
  243. provided that the above copyright notice appear in all copies and that
  244. both that copyright notice and this permission notice appear in 
  245. supporting documentation, and that the names of Stichting Mathematisch
  246. Centrum or CWI not be used in advertising or publicity pertaining to
  247. distribution of the software without specific, written prior permission.
  248. X
  249. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  250. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  251. XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  252. XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  253. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  254. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  255. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  256. X
  257. X******************************************************************/
  258. X
  259. X/* $Id: cdsend.c,v 1.2 1993/01/18 10:02:47 sjoerd Exp $ */
  260. X
  261. X/*
  262. X * cdsend reads audio CD's over the SCSI bus, converts it to a format
  263. X * suitable for broadcast, and writes this converted data to standard
  264. X * output.  Optionally, the msuic is also played over the system's own
  265. X * speakers.
  266. X *
  267. X * Options.
  268. X *    -n    use non-degradable priority for the program (works
  269. X *        only if installed set-uid root).  The default is to
  270. X *        not change the priority.
  271. X *    -d    daemon mode.  When a CD finishes, hang around until
  272. X *        the next CD is put in the CD player and play it.  The
  273. X *        default is to exit after playing one CD.
  274. X *    -p    play the music over the system's speakers.  Default is
  275. X *        to not play the music.
  276. X *    -l    convert the data to 2-byte-per-sample linear format.
  277. X *        Default is to convert to 1-byte-per-sample U-law.
  278. X *    -c file    use the specified file to write the CD's
  279. X *        identification to.  Default is to write to the file
  280. X *        $HOME/.CDcatalognumber.
  281. X */
  282. X
  283. X#include "cdsend.h"
  284. X#include <unistd.h>
  285. X#include <stdlib.h>
  286. X#include <stdarg.h>
  287. X#include <stdio.h>
  288. X#include <signal.h>
  289. X#include <limits.h>
  290. X#include <sys/prctl.h>
  291. X#include <sys/schedctl.h>
  292. X#include <audio.h>
  293. X#include <fcntl.h>
  294. X
  295. static ALport port;        /* audio output port */
  296. static int playaudio;        /* 1 iff we changed output rate */
  297. static volatile int silent = 1;    /* 1 iff we must be quiet */
  298. static volatile int stop_playing; /* 1 if we must stop playing */
  299. static int linear = 0;        /* 1 iff we produce linear (2-byte) output */
  300. static long oldparams[2] = {AL_OUTPUT_RATE, 0};
  301. static long newparams[2] = {AL_OUTPUT_RATE, AL_RATE_44100};
  302. static char *cdtoc, *cdid;
  303. static char cdcatnamebuf[1024];
  304. static char *cdcatname = cdcatnamebuf;
  305. extern char *db_get_TOC(CDPLAYER *, CDSTATUS *);
  306. extern char *db_get_id(CDPLAYER *, CDSTATUS *);
  307. extern char *optarg;
  308. X
  309. X/* newer libraries use CDaddcallback and have a backward compatibility */
  310. X/* define for CDsetcallback, we do it the other way round */
  311. X#ifndef CDsetcallback
  312. X#define CDaddcallback    CDsetcallback
  313. X#endif
  314. X
  315. X#define DEFCDCATNAME    ".CDcatalognumber"
  316. X
  317. X/*
  318. X * Called when the program is interrupted.  This means that the audio
  319. X * params have to be reset, but only if we've changed them.
  320. X */
  321. static void
  322. die(int sig)
  323. X{
  324. X    if (playaudio)
  325. X        ALsetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
  326. X    exit(sig);
  327. X}
  328. X
  329. X/*
  330. X * Called when we get a SIGHUP.  This means that we must switch from
  331. X * playing the audio to being silent or vv.
  332. X */
  333. static void
  334. toggle(void)
  335. X{
  336. X    silent = !silent;
  337. X}
  338. X
  339. X/*
  340. X * Called when we get a SIGUSR1.  This means we have to stop reading
  341. X * the CD (and eject it).  This is useful if the CD player is needed
  342. X * for official business.
  343. X */
  344. static void
  345. eject(void)
  346. X{
  347. X    stop_playing = 1;
  348. X}
  349. X
  350. X/*
  351. X * Callback routine, called to do something to the audio data.
  352. X */
  353. static void
  354. handleaudio(void *arg, CDDATATYPES type, short *audio)
  355. X{
  356. X    if (!playaudio && !silent) {
  357. X        /* we were silent but want to start playing, so set */
  358. X        /* audio params */
  359. X        ALgetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
  360. X        ALsetparams(AL_DEFAULT_DEVICE, newparams, 2L);
  361. X        playaudio = 1;
  362. X    }
  363. X    /* play the audio, but only if enough space in output port */
  364. X    if (playaudio && ALgetfillable(port) >= CDDA_NUMSAMPLES)
  365. X        ALwritesamps(port, audio, CDDA_NUMSAMPLES);
  366. X    if (playaudio && silent) {
  367. X        /* we were playing but want to be silent now, so reset */
  368. X        /* audio params */
  369. X        ALsetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
  370. X        playaudio = 0;
  371. X    }
  372. X
  373. X    /* actually do the work we're being paid for */
  374. X    convert_audio_and_print(audio, CDDA_NUMSAMPLES / 2, linear);
  375. X}
  376. X
  377. X/*
  378. X * Callback routine, called when the CD contains a catalog number.
  379. X * This routine writes the catalog number and the table of contents to
  380. X * a file.  Other programs can use this information to display the
  381. X * title of the CD being played.
  382. X */
  383. static void
  384. handlecatalog(void *arg, CDDATATYPES type, char *data)
  385. X{
  386. X    int i;
  387. X    FILE *fp;
  388. X
  389. X    for (i = 0; i < 13; i++)
  390. X        if (data[i] != 0)
  391. X            break;
  392. X    if (i == 13)        /* catalog # is null, so ignore it */
  393. X        return;
  394. X
  395. X    if ((fp = fopen(cdcatname, "w")) == NULL)
  396. X        return;
  397. X    fprintf(fp, "hash=%s\n", cdid);
  398. X    fprintf(fp, "toc=%s\n", cdtoc);
  399. X    fprintf(fp, "catalog=");
  400. X    for (i = 0; i < 13; i++)
  401. X        fprintf(fp, "%c", *data++ + '0');
  402. X    fprintf(fp, "\n");
  403. X    fclose(fp);
  404. X}
  405. X
  406. X/*
  407. X * This routine is called to write identification information in the
  408. X * .CDcatalognumber file.  If there is a catalog number on the CD,
  409. X * this information is overwritten, but if there is no catalog number
  410. X * on the CD, the information written here can be used.
  411. X */
  412. static void
  413. nocatalog(CDSTATUS *cdstatus)
  414. X{
  415. X    FILE *fp;
  416. X
  417. X    if ((fp = fopen(cdcatname, "w")) == NULL)
  418. X        return;
  419. X    fprintf(fp, "hash=%s\n", cdid);
  420. X    fprintf(fp, "toc=%s\n", cdtoc);
  421. X    fprintf(fp, "tmsf=%d.%d.%d.%d\n", cdstatus->last, cdstatus->total_min,
  422. X        cdstatus->total_sec, cdstatus->total_frame);
  423. X    fclose(fp);
  424. X}
  425. X
  426. X/*
  427. X * Wait for an audio CD to be inserted into the player.
  428. X */
  429. static void
  430. waitforcd(void)
  431. X{
  432. X    CDPLAYER *cdp;
  433. X    CDSTATUS status;
  434. X
  435. X    for (;;) {
  436. X        for (;;) {
  437. X            if ((cdp = CDopen(0, 0)) != 0)
  438. X                break;
  439. X            /* opening the CD player failed; wait a while */
  440. X            /* and try again */
  441. X            sginap(60);
  442. X        }
  443. X
  444. X        /* opening the CD player succeeded; now wait until the */
  445. X        /* player is ready */
  446. X        for (;;) {
  447. X            if (!CDgetstatus(cdp, &status)) {
  448. X                CDclose(cdp);
  449. X                break;
  450. X            }
  451. X            if (status.state == CD_READY) {
  452. X                if (!status.scsi_audio) {
  453. X                    fprintf(stderr, "cdsend: CD-ROM player does not support audio CD's\n");
  454. X                    CDclose(cdp);
  455. X                    exit(1);
  456. X                }
  457. X                CDclose(cdp);
  458. X                return;
  459. X            }
  460. X            sginap(60);
  461. X        }
  462. X        sginap(60);
  463. X    }
  464. X}
  465. X
  466. X/*
  467. X * This routine reads one whole CD and when it is finished, it ejects
  468. X * the CD.
  469. X */
  470. static void
  471. play(void)
  472. X{
  473. X    CDPLAYER *cdp;
  474. X    CDPARSER *parser;
  475. X    CDFRAME buf[12];
  476. X    CDSTATUS cdstatus;
  477. X    FILE *fd;
  478. X    int i, n, first = 1;
  479. X    ALconfig c;
  480. X
  481. X    waitforcd();
  482. X
  483. X    stop_playing = 0;
  484. X
  485. X    cdp = CDopen(0, 0);
  486. X    if (cdp == 0)
  487. X        return;
  488. X
  489. X    CDgetstatus(cdp, &cdstatus);
  490. X    if (cdtoc)
  491. X        free(cdtoc);
  492. X    if (cdid)
  493. X        free(cdid);
  494. X    cdtoc = db_get_TOC(cdp, &cdstatus);
  495. X    cdid = db_get_id(cdp, &cdstatus);
  496. X
  497. X    nocatalog(&cdstatus);
  498. X
  499. X    if ((parser = CDcreateparser()) == 0) {
  500. X        perror("CDcreateparser");
  501. X        exit(1);
  502. X    }
  503. X
  504. X    ALgetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
  505. X    c = ALnewconfig();
  506. X    ALsetwidth(c, AL_SAMPLE_16);
  507. X    ALsetchannels(c, AL_STEREO);
  508. X    port = ALopenport("cd", "w", c);
  509. X
  510. X    CDaddcallback(parser, cd_audio, (CDCALLBACKFUNC) handleaudio, 0);
  511. X    CDaddcallback(parser, cd_catalog, (CDCALLBACKFUNC) handlecatalog, 0);
  512. X
  513. X    init_convert();
  514. X
  515. X    while (!stop_playing) {
  516. X        n = CDreadda(cdp, buf, 12);
  517. X        if (first && n == 0) {
  518. X            /* apparantly not an audio CD */
  519. X            CDclose(cdp);
  520. X            ALcloseport(port);
  521. X            ALfreeconfig(c);
  522. X            close(creat(cdcatname, 0666));
  523. X            sginap(300);
  524. X            return;
  525. X        }
  526. X        first = 0;
  527. X        if (n < 0) {
  528. X            perror("CDreadda");
  529. X            exit(1);
  530. X        }
  531. X        if (n == 0)
  532. X            break;
  533. X
  534. X        for (i = 0; i < n && !stop_playing; i++)
  535. X            CDparseframe(parser, &buf[i]);
  536. X    }
  537. X
  538. X    if (playaudio) {
  539. X        ALsetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
  540. X        playaudio = 0;
  541. X    }
  542. X
  543. X    CDeject(cdp);
  544. X    CDdeleteparser(parser);
  545. X    CDclose(cdp);
  546. X    ALcloseport(port);
  547. X    ALfreeconfig(c);
  548. X    close(creat(cdcatname, 0666));
  549. X}
  550. X
  551. main(int argc, char **argv)
  552. X{
  553. X    int c;
  554. X    int daemon = 0;
  555. X
  556. X    sprintf(cdcatname, "%s/%s", getenv("HOME"), DEFCDCATNAME);
  557. X
  558. X    while ((c = getopt(argc, argv, "c:npdl")) != EOF) {
  559. X        switch (c) {
  560. X        case 'c':
  561. X            cdcatname = optarg;
  562. X            break;
  563. X        case 'n':
  564. X            schedctl(NDPRI, 0, NDPNORMMAX);
  565. X            break;
  566. X        case 'd':
  567. X            daemon = 1;
  568. X            break;
  569. X        case 'p':
  570. X            silent = 0;
  571. X            break;
  572. X        case 'l':
  573. X            linear = 1;
  574. X            break;
  575. X        }
  576. X    }
  577. X
  578. X    setuid(getuid());
  579. X
  580. X    if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
  581. X        sigset(SIGINT, die);
  582. X    sigset(SIGTERM, die);
  583. X    sigset(SIGHUP, toggle);
  584. X    sigset(SIGUSR1, eject);
  585. X
  586. X    if (daemon)
  587. X        for (;;)
  588. X            play();
  589. X    else
  590. X        play();
  591. X    die(0);
  592. X}
  593. END_OF_FILE
  594. if test 8872 -ne `wc -c <'cdsend.c'`; then
  595.     echo shar: \"'cdsend.c'\" unpacked with wrong size!
  596. fi
  597. # end of 'cdsend.c'
  598. fi
  599. if test -f 'cdsend.h' -a "${1}" != "-c" ; then 
  600.   echo shar: Will not clobber existing file \"'cdsend.h'\"
  601. else
  602. echo shar: Extracting \"'cdsend.h'\" \(166 characters\)
  603. sed "s/^X//" >'cdsend.h' <<'END_OF_FILE'
  604. X#include <sys/types.h>
  605. X#include <cdaudio.h>
  606. X
  607. X#define IN_RATE        44100
  608. X#define OUT_RATE     8000
  609. X
  610. void init_convert(void);
  611. void convert_audio_and_print(short *, int, int);
  612. END_OF_FILE
  613. if test 166 -ne `wc -c <'cdsend.h'`; then
  614.     echo shar: \"'cdsend.h'\" unpacked with wrong size!
  615. fi
  616. # end of 'cdsend.h'
  617. fi
  618. if test -f 'convert.c' -a "${1}" != "-c" ; then 
  619.   echo shar: Will not clobber existing file \"'convert.c'\"
  620. else
  621. echo shar: Extracting \"'convert.c'\" \(2800 characters\)
  622. sed "s/^X//" >'convert.c' <<'END_OF_FILE'
  623. X#include <stdio.h>
  624. X#include "cdsend.h"
  625. X
  626. X#define A    1
  627. X#define B    7
  628. X
  629. static int d;
  630. static int prev_i, cur_i;
  631. static int rate_i = IN_RATE, rate_o = OUT_RATE;
  632. static short outbuf[(CDDA_NUMSAMPLES/2)*OUT_RATE/IN_RATE + 1];
  633. X
  634. X#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
  635. X#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
  636. X#define CLIP 32635
  637. X
  638. static unsigned char
  639. st_linear_to_ulaw(int sample)
  640. X{
  641. X    static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
  642. X                   4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  643. X                   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  644. X                   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  645. X                   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  646. X                   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  647. X                   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  648. X                   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  649. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  650. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  651. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  652. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  653. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  654. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  655. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  656. X                   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
  657. X    int sign, exponent, mantissa;
  658. X    unsigned char ulawbyte;
  659. X
  660. X    /* Get the sample into sign-magnitude. */
  661. X    sign = (sample >> 8) & 0x80; /* set aside the sign */
  662. X    if (sign != 0)
  663. X        sample = -sample; /* get magnitude */
  664. X    if (sample > CLIP)
  665. X        sample = CLIP; /* clip the magnitude */
  666. X
  667. X    /* Convert from 16 bit linear to ulaw. */
  668. X    sample = sample + BIAS;
  669. X    exponent = exp_lut[( sample >> 7 ) & 0xFF];
  670. X    mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
  671. X    ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
  672. X#ifdef ZEROTRAP
  673. X    if (ulawbyte == 0)
  674. X        ulawbyte = 0x02; /* optional CCITT trap */
  675. X#endif
  676. X
  677. X    return ulawbyte;
  678. X}
  679. X
  680. void
  681. init_convert(void)
  682. X{
  683. X    d = -OUT_RATE;
  684. X    prev_i = cur_i = 0;
  685. X}
  686. X
  687. void
  688. convert_audio_and_print(short *audio, int nsamples, int linear)
  689. X{
  690. X    int cur_o;
  691. X    short *outp = outbuf;
  692. X#if !defined(A) || !defined(B)
  693. X    int ab = a + b;
  694. X#endif
  695. X    int ld = d, lp = prev_i, lc = cur_i;    /* local copy (register?) */
  696. X
  697. X#if !defined(A) || !defined(B)
  698. X    /* some efficiency hacks */
  699. X    ab *= 2;
  700. X    b *= 2;
  701. X#endif
  702. X
  703. X    for (;;) {
  704. X        while (ld < 0) {
  705. X            if (nsamples == 0) {
  706. X                d = ld;
  707. X                prev_i = lp;
  708. X                cur_i = lc;
  709. X
  710. X                if (linear) {
  711. X                    write(1, (char *) outbuf,
  712. X                          sizeof(short) * (outp - outbuf));
  713. X                }
  714. X                return;
  715. X            }
  716. X            lp = lc;
  717. X#if defined(A) && defined(B)
  718. X            lc = (A * (audio[0] + audio[1]) + 2*B * lp) / (2*(A+B));
  719. X#else
  720. X            /* depends on efficiency hacks */
  721. X            lc = (a * (audio[0] + audio[1]) + b * lp) / ab;
  722. X#endif
  723. X            nsamples--;
  724. X            audio += 2;
  725. X            ld += OUT_RATE;
  726. X        }
  727. X#if IN_RATE < OUT_RATE
  728. X        while (ld >= 0)
  729. X#endif
  730. X        {
  731. X            cur_o = (lp * ld + lc * (OUT_RATE - ld)) / OUT_RATE;
  732. X            if (linear) {
  733. X                *outp++ = cur_o;
  734. X            } else {
  735. X                /* not efficient at all */
  736. X                putchar(st_linear_to_ulaw(cur_o));
  737. X            }
  738. X            ld -= IN_RATE;
  739. X        }
  740. X    }
  741. X}
  742. END_OF_FILE
  743. if test 2800 -ne `wc -c <'convert.c'`; then
  744.     echo shar: \"'convert.c'\" unpacked with wrong size!
  745. fi
  746. # end of 'convert.c'
  747. fi
  748. if test -f 'db_get_TOC.c' -a "${1}" != "-c" ; then 
  749.   echo shar: Will not clobber existing file \"'db_get_TOC.c'\"
  750. else
  751. echo shar: Extracting \"'db_get_TOC.c'\" \(627 characters\)
  752. sed "s/^X//" >'db_get_TOC.c' <<'END_OF_FILE'
  753. X#include <string.h>
  754. X#include <sys/types.h>
  755. X#include <cdaudio.h>
  756. X
  757. X#define    MAX_CATALOG    (99*3+6+1)
  758. X
  759. const char *
  760. db_get_TOC( CDPLAYER *cdplayer, CDSTATUS *status )
  761. X{
  762. CDTRACKINFO    info;
  763. int        min, sec, i;
  764. char        buf[MAX_CATALOG], *bufp = buf, *tmp;
  765. X
  766. X    if (status->state == CD_NODISC || status->state == CD_ERROR)
  767. X    return (NULL);
  768. X
  769. X    sprintf( bufp, "%02d", status->last - status->first + 1 );
  770. X    bufp += 2;
  771. X
  772. X    for (i = status->first; i <= status->last; i++) {
  773. X    CDgettrackinfo( cdplayer, i, &info );
  774. X    sprintf( bufp, "%02d%02d", info.total_min, info.total_sec );
  775. X    bufp += 4;
  776. X    }
  777. X    *bufp++ = '\0';
  778. X    return (strdup( buf ));
  779. X}
  780. END_OF_FILE
  781. if test 627 -ne `wc -c <'db_get_TOC.c'`; then
  782.     echo shar: \"'db_get_TOC.c'\" unpacked with wrong size!
  783. fi
  784. # end of 'db_get_TOC.c'
  785. fi
  786. if test -f 'db_get_id.c' -a "${1}" != "-c" ; then 
  787.   echo shar: Will not clobber existing file \"'db_get_id.c'\"
  788. else
  789. echo shar: Extracting \"'db_get_id.c'\" \(1806 characters\)
  790. sed "s/^X//" >'db_get_id.c' <<'END_OF_FILE'
  791. X#include <string.h>
  792. X#include <sys/types.h>
  793. X#include <cdaudio.h>
  794. X
  795. X#define    DB_ID_NTRACKS    5
  796. X#define    DB_ID_MAXLEN    20
  797. X
  798. X#define    DBID_MAP_SIZE    66
  799. X
  800. static char dbid_int_map[DBID_MAP_SIZE] = {
  801. X  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
  802. X  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
  803. X  'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  804. X  'U', 'V', 'W', 'X', 'Y', 'Z', '@', '_', '=', '+',
  805. X  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 
  806. X  'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 
  807. X  'u', 'v', 'w', 'x', 'y', 'z',
  808. X};
  809. X
  810. X#define    DBID_MAP(b,val)    {\
  811. X    register int v = (val);\
  812. X    if (v>=DBID_MAP_SIZE) {\
  813. X        sprintf(b, "%02d", v);\
  814. X        b+= 2;\
  815. X    }\
  816. X    else *b++ = dbid_int_map[v];\
  817. X}
  818. X
  819. const char *
  820. db_get_id( CDPLAYER *cdplayer, CDSTATUS *status )
  821. X{
  822. char        db_rtrn_buf[1024];
  823. CDTRACKINFO    info;
  824. int        min, sec, i;
  825. char        *bufp = db_rtrn_buf, *tmp;
  826. int        nCDTracks, nIDTracks;
  827. X
  828. X    if (status->state == CD_NODISC || status->state == CD_ERROR)
  829. X    return (NULL);
  830. X
  831. X    nCDTracks = status->last - status->first + 1;
  832. X    DBID_MAP( bufp, ((nCDTracks>>4)&0xf) );
  833. X    DBID_MAP( bufp, (nCDTracks&0xf) );
  834. X
  835. X    if ( nCDTracks < DB_ID_NTRACKS )        nIDTracks = nCDTracks;
  836. X    else if (nCDTracks == DB_ID_NTRACKS )    nIDTracks = DB_ID_NTRACKS;
  837. X    else {
  838. X    nIDTracks = DB_ID_NTRACKS - 1;
  839. X    for (min= 0, sec= 0,i = status->first ; i <= status->last ; i++ ) {
  840. X        CDgettrackinfo( cdplayer, i, &info );
  841. X        min+= info.total_min;
  842. X        sec+= info.total_sec;
  843. X    }
  844. X    min+= sec/60;
  845. X    sec = sec % 60;
  846. X    DBID_MAP( bufp, min );
  847. X    DBID_MAP( bufp, sec );
  848. X    }
  849. X
  850. X    for (i = 0; i < nIDTracks; i++) {
  851. X    if (status->first+i <= status->last) {
  852. X        CDgettrackinfo( cdplayer, status->first+i, &info );
  853. X        DBID_MAP( bufp, info.total_min );
  854. X        DBID_MAP( bufp, info.total_sec );
  855. X    }
  856. X    }
  857. X    *bufp++ = '\0';
  858. X    return (strdup( db_rtrn_buf ));
  859. X}
  860. END_OF_FILE
  861. if test 1806 -ne `wc -c <'db_get_id.c'`; then
  862.     echo shar: \"'db_get_id.c'\" unpacked with wrong size!
  863. fi
  864. # end of 'db_get_id.c'
  865. fi
  866. echo shar: End of archive 1 \(of 1\).
  867. cp /dev/null ark1isdone
  868. MISSING=""
  869. for I in 1 ; do
  870.     if test ! -f ark${I}isdone ; then
  871.     MISSING="${MISSING} ${I}"
  872.     fi
  873. done
  874. if test "${MISSING}" = "" ; then
  875.     echo You have the archive.
  876.     rm -f ark[1-9]isdone
  877. else
  878.     echo You still need to unpack the following archives:
  879.     echo "        " ${MISSING}
  880. fi
  881. ##  End of shell archive.
  882. exit 0
  883.