~ubuntu-branches/ubuntu/lucid/mpg123/lucid

« back to all changes in this revision

Viewing changes to wav.c

Tags: upstream-0.60
ImportĀ upstreamĀ versionĀ 0.60

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Geez, why are WAV RIFF headers are so secret?  I got something together,
2
 
   but wow...  anyway, I hope someone will find this useful.
3
 
   - Samuel Audet <guardia@cam.org> */
4
 
 
5
 
/* minor simplifications and ugly AU/CDR format stuff by MH */
6
 
 
7
 
/* It's not a very clean code ... Fix this! */
8
 
 
9
 
#include <stdlib.h>
10
 
#include <stdio.h>
11
 
#include "mpg123.h"
12
 
 
13
 
struct
14
 
{
15
 
   byte riffheader[4];
16
 
   byte WAVElen[4];
17
 
   struct
18
 
   {
19
 
      byte fmtheader[8];
20
 
      byte fmtlen[4];
21
 
      struct
22
 
      {
23
 
         byte FormatTag[2];
24
 
         byte Channels[2];
25
 
         byte SamplesPerSec[4];
26
 
         byte AvgBytesPerSec[4];
27
 
         byte BlockAlign[2];
28
 
         byte BitsPerSample[2]; /* format specific for PCM */
29
 
      } fmt;
30
 
      struct
31
 
      {
32
 
         byte dataheader[4];
33
 
         byte datalen[4];
34
 
         /* from here you insert your PCM data */
35
 
      } data;
36
 
   } WAVE;
37
 
} RIFF = 
38
 
{  { 'R','I','F','F' } , { sizeof(RIFF.WAVE),0,0,0 } , 
39
 
   {  { 'W','A','V','E','f','m','t',' ' } , { sizeof(RIFF.WAVE.fmt),0,0,0} ,
40
 
      { {1,0} , {0,0},{0,0,0,0},{0,0,0,0},{0,0},{0,0} } ,
41
 
      { { 'd','a','t','a' }  , {0,0,0,0} }
42
 
   }
43
 
};
44
 
 
45
 
struct auhead {
46
 
  byte magic[4];
47
 
  byte headlen[4];
48
 
  byte datalen[4];
49
 
  byte encoding[4];
50
 
  byte rate[4];
51
 
  byte channels[4];
52
 
  byte dummy[8];
53
 
} auhead = { 
54
 
  { 0x2e,0x73,0x6e,0x64 } , { 0x00,0x00,0x00,0x20 } , 
55
 
  { 0xff,0xff,0xff,0xff } , { 0,0,0,0 } , { 0,0,0,0 } , { 0,0,0,0 } , 
56
 
  { 0,0,0,0,0,0,0,0 }};
57
 
 
58
 
 
59
 
static FILE *wavfp;
60
 
static long datalen = 0;
61
 
static int flipendian=0;
62
 
 
63
 
/* Convertfunctions: */
64
 
/* always little endian */
65
 
 
66
 
static void long2littleendian(long inval,byte *outval,int b)
67
 
{
68
 
  int i;
69
 
  for(i=0;i<b;i++) {
70
 
    outval[i] = (inval>>(i*8)) & 0xff;
71
 
  } 
72
 
}
73
 
 
74
 
/* always big endian */
75
 
static void long2bigendian(long inval,byte *outval,int b)
76
 
{
77
 
  int i;
78
 
  for(i=0;i<b;i++) {
79
 
    outval[i] = (inval>>((b-i-1)*8)) & 0xff;
80
 
  }
81
 
}
82
 
 
83
 
static int testEndian(void) 
84
 
{
85
 
  long i,a=0,b=0,c=0;
86
 
  int ret = 0;
87
 
 
88
 
  for(i=0;i<sizeof(long);i++) {
89
 
    ((byte *)&a)[i] = i;
90
 
    b<<=8;
91
 
    b |= i;
92
 
    c |= i << (i*8);
93
 
  }
94
 
  if(a == b)
95
 
      ret = 1;
96
 
  else if(a != c) {
97
 
      fprintf(stderr,"Strange endianess?? %08lx %08lx %08lx\n",a,b,c);
98
 
      exit(1);
99
 
  }
100
 
  return ret;
101
 
}
102
 
 
103
 
static int open_file(char *filename)
104
 
{
105
 
#ifndef GENERIC
106
 
   setuid(getuid()); /* dunno whether this helps. I'm not a security expert */
107
 
#endif
108
 
   if(!strcmp("-",filename))  {
109
 
      wavfp = stdout;
110
 
   }
111
 
   else {
112
 
     wavfp = fopen(filename,"w");
113
 
     if(!wavfp)
114
 
       return -1;
115
 
   }
116
 
  return 0;
117
 
}
118
 
 
119
 
 
120
 
int au_open(struct audio_info_struct *ai, char *aufilename)
121
 
{
122
 
  flipendian = 0;
123
 
 
124
 
  switch(ai->format) {
125
 
    case AUDIO_FORMAT_SIGNED_16:
126
 
      flipendian = !testEndian(); /* big end */
127
 
      long2bigendian(3,auhead.encoding,sizeof(auhead.encoding));
128
 
      break;
129
 
    case AUDIO_FORMAT_UNSIGNED_8:
130
 
      ai->format = AUDIO_FORMAT_ULAW_8; 
131
 
    case AUDIO_FORMAT_ULAW_8:
132
 
      long2bigendian(1,auhead.encoding,sizeof(auhead.encoding));
133
 
      break;
134
 
    default:
135
 
      fprintf(stderr,"AU output is only a hack. This audio mode isn't supported yet.\n");
136
 
      exit(1);
137
 
  }
138
 
 
139
 
  long2bigendian(0xffffffff,auhead.datalen,sizeof(auhead.datalen));
140
 
  long2bigendian(ai->rate,auhead.rate,sizeof(auhead.rate));
141
 
  long2bigendian(ai->channels,auhead.channels,sizeof(auhead.channels));
142
 
 
143
 
  if(open_file(aufilename) < 0)
144
 
    return -1;
145
 
 
146
 
  fwrite(&auhead, sizeof(auhead),1,wavfp);
147
 
  datalen = 0;
148
 
 
149
 
  return 0;
150
 
}
151
 
 
152
 
int cdr_open(struct audio_info_struct *ai, char *cdrfilename)
153
 
{
154
 
  param.force_stereo = 0;
155
 
  ai->format = AUDIO_FORMAT_SIGNED_16;
156
 
  ai->rate = 44100;
157
 
  ai->channels = 2;
158
 
/*
159
 
  if(ai->format != AUDIO_FORMAT_SIGNED_16 || ai->rate != 44100 || ai->channels != 2) {
160
 
    fprintf(stderr,"Oops .. not forced to 16 bit, 44kHz?, stereo\n");
161
 
    exit(1);
162
 
  }
163
 
*/
164
 
  flipendian = !testEndian(); /* big end */
165
 
  
166
 
 
167
 
  if(open_file(cdrfilename) < 0)
168
 
    return -1;
169
 
 
170
 
  return 0;
171
 
}
172
 
 
173
 
int wav_open(struct audio_info_struct *ai, char *wavfilename)
174
 
{
175
 
   int bps;
176
 
   
177
 
   flipendian = 0;
178
 
 
179
 
   /* standard MS PCM, and its format specific is BitsPerSample */
180
 
   long2littleendian(1,RIFF.WAVE.fmt.FormatTag,sizeof(RIFF.WAVE.fmt.FormatTag));
181
 
 
182
 
   if(ai->format == AUDIO_FORMAT_SIGNED_16) {
183
 
      long2littleendian(bps=16,RIFF.WAVE.fmt.BitsPerSample,sizeof(RIFF.WAVE.fmt.BitsPerSample));
184
 
      flipendian = testEndian();
185
 
   }
186
 
   else if(ai->format == AUDIO_FORMAT_UNSIGNED_8)
187
 
      long2littleendian(bps=8,RIFF.WAVE.fmt.BitsPerSample,sizeof(RIFF.WAVE.fmt.BitsPerSample));
188
 
   else
189
 
   {
190
 
      fprintf(stderr,"Format not supported.");
191
 
      return -1;
192
 
   }
193
 
 
194
 
   if(ai->rate < 0) ai->rate = 44100;
195
 
 
196
 
   long2littleendian(ai->channels,RIFF.WAVE.fmt.Channels,sizeof(RIFF.WAVE.fmt.Channels));
197
 
    long2littleendian(ai->rate,RIFF.WAVE.fmt.SamplesPerSec,sizeof(RIFF.WAVE.fmt.SamplesPerSec));
198
 
   long2littleendian((int)(ai->channels * ai->rate * bps)>>3,
199
 
         RIFF.WAVE.fmt.AvgBytesPerSec,sizeof(RIFF.WAVE.fmt.AvgBytesPerSec));
200
 
   long2littleendian((int)(ai->channels * bps)>>3,
201
 
         RIFF.WAVE.fmt.BlockAlign,sizeof(RIFF.WAVE.fmt.BlockAlign));
202
 
 
203
 
   if(open_file(wavfilename) < 0)
204
 
     return -1;
205
 
 
206
 
   long2littleendian(datalen,RIFF.WAVE.data.datalen,sizeof(RIFF.WAVE.data.datalen));
207
 
   long2littleendian(datalen+sizeof(RIFF.WAVE),RIFF.WAVElen,sizeof(RIFF.WAVElen));
208
 
   fwrite(&RIFF, sizeof(RIFF),1,wavfp);
209
 
 
210
 
   datalen = 0;
211
 
   
212
 
   return 0;
213
 
}
214
 
 
215
 
int wav_write(unsigned char *buf,int len)
216
 
{
217
 
   int temp;
218
 
   int i;
219
 
 
220
 
   if(!wavfp) 
221
 
     return 0;
222
 
  
223
 
   if(flipendian) {
224
 
     if(len & 1) {
225
 
       fprintf(stderr,"Odd number of bytes!\n");
226
 
       exit(1);
227
 
     }
228
 
     for(i=0;i<len;i+=2) {
229
 
       unsigned char tmp;
230
 
       tmp = buf[i+0];
231
 
       buf[i+0] = buf[i+1];
232
 
       buf[i+1] = tmp;
233
 
     }
234
 
   }
235
 
 
236
 
   temp = fwrite(buf, 1, len, wavfp);
237
 
   if(temp <= 0)
238
 
     return 0;
239
 
     
240
 
   datalen += temp;
241
 
 
242
 
   return temp;
243
 
}
244
 
 
245
 
int wav_close(void)
246
 
{
247
 
   if(!wavfp) 
248
 
      return 0;
249
 
 
250
 
   if(fseek(wavfp, 0L, SEEK_SET) >= 0) {
251
 
     long2littleendian(datalen,RIFF.WAVE.data.datalen,sizeof(RIFF.WAVE.data.datalen));
252
 
     long2littleendian(datalen+sizeof(RIFF.WAVE),RIFF.WAVElen,sizeof(RIFF.WAVElen));
253
 
     fwrite(&RIFF, sizeof(RIFF),1,wavfp);
254
 
   }
255
 
   else {
256
 
     fprintf(stderr,"Warning can't rewind WAV file. File-format isn't fully conform now.\n");
257
 
   }
258
 
 
259
 
   return 0;
260
 
}
261
 
 
262
 
int au_close(void)
263
 
{
264
 
   if(!wavfp)
265
 
      return 0;
266
 
 
267
 
   if(fseek(wavfp, 0L, SEEK_SET) >= 0) {
268
 
     long2bigendian(datalen,auhead.datalen,sizeof(auhead.datalen));
269
 
     fwrite(&auhead, sizeof(auhead),1,wavfp); 
270
 
   }
271
 
 
272
 
  return 0;
273
 
}
274
 
 
275
 
int cdr_close(void)
276
 
{
277
 
  return 0;
278
 
}
279
 
 
280
 
 
281