1 /*
2  * madplay - MPEG audio decoder and player
3  * Copyright (C) 2000-2004 Robert Leslie
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * $Id: audio_cdda.c,v 1.9 2004/01/23 09:41:31 rob Exp $
20  */
21 
22 # ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 # endif
25 
26 # include "global.h"
27 
28 # include <stdio.h>
29 # include <string.h>
30 
31 # ifdef HAVE_ASSERT_H
32 #  include <assert.h>
33 # endif
34 
35 # include <mad.h>
36 
37 # include "audio.h"
38 
39 static FILE *outfile;
40 unsigned int samplecount;
41 
42 # define CD_FRAMESZ  (44100 / 75)
43 
44 static
init(struct audio_init * init)45 int init(struct audio_init *init)
46 {
47   if (init->path && strcmp(init->path, "-") != 0) {
48     outfile = fopen(init->path, "wb");
49     if (outfile == 0) {
50       audio_error = ":";
51       return -1;
52     }
53   }
54   else
55     outfile = stdout;
56 
57   samplecount = 0;
58 
59   return 0;
60 }
61 
62 static
config(struct audio_config * config)63 int config(struct audio_config *config)
64 {
65   /* force 16-bit 44100 Hz stereo */
66 
67   config->channels  = 2;
68   config->speed     = 44100;
69   config->precision = 16;
70 
71   return 0;
72 }
73 
74 static
output(unsigned char const * data,unsigned int nsamples)75 int output(unsigned char const *data, unsigned int nsamples)
76 {
77   unsigned int count;
78   int result = 0;
79 
80   count = fwrite(data, 2 * 2, nsamples, outfile);
81 
82   if (count != nsamples) {
83     audio_error = ":fwrite";
84     result = -1;
85   }
86 
87   samplecount = (samplecount + count) % CD_FRAMESZ;
88 
89   return result;
90 }
91 
92 static
play(struct audio_play * play)93 int play(struct audio_play *play)
94 {
95   unsigned char data[MAX_NSAMPLES * 2 * 2];
96 
97   assert(play->samples[1]);
98 
99   audio_pcm_s16be(data, play->nsamples, play->samples[0], play->samples[1],
100 		  play->mode, play->stats);
101 
102   return output(data, play->nsamples);
103 }
104 
105 static
stop(struct audio_stop * stop)106 int stop(struct audio_stop *stop)
107 {
108   return 0;
109 }
110 
111 static
finish(struct audio_finish * finish)112 int finish(struct audio_finish *finish)
113 {
114   int result = 0;
115 
116   /* pad audio to CD frame boundary */
117 
118   if (samplecount) {
119     unsigned char padding[CD_FRAMESZ * 2 * 2];
120     unsigned int padsz;
121 
122     assert(samplecount < CD_FRAMESZ);
123     padsz = CD_FRAMESZ - samplecount;
124 
125     memset(padding, 0, padsz * 2 * 2);
126 
127     result = output(padding, padsz);
128   }
129 
130   if (outfile != stdout &&
131       fclose(outfile) == EOF &&
132       result == 0) {
133     audio_error = ":fclose";
134     result = -1;
135   }
136 
137   return result;
138 }
139 
audio_cdda(union audio_control * control)140 int audio_cdda(union audio_control *control)
141 {
142   audio_error = 0;
143 
144   switch (control->command) {
145   case AUDIO_COMMAND_INIT:
146     return init(&control->init);
147 
148   case AUDIO_COMMAND_CONFIG:
149     return config(&control->config);
150 
151   case AUDIO_COMMAND_PLAY:
152     return play(&control->play);
153 
154   case AUDIO_COMMAND_STOP:
155     return stop(&control->stop);
156 
157   case AUDIO_COMMAND_FINISH:
158     return finish(&control->finish);
159   }
160 
161   return 0;
162 }
163