00001 #include <endian.h>
00002 #include <byteswap.h>
00003
00004 #include <sys/types.h>
00005 #include <unistd.h>
00006 #include <stdio.h>
00007
00008 #include "camogm_wav.h"
00009 #include "camogm.h"
00010
00011 #include <alsa/asoundlib.h>
00012
00013
00014
00015 #if __BYTE_ORDER == __LITTLE_ENDIAN
00016 #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
00017 #define LE_SHORT(v) (v)
00018 #define LE_INT(v) (v)
00019 #define BE_SHORT(v) bswap_16(v)
00020 #define BE_INT(v) bswap_32(v)
00021 #elif __BYTE_ORDER == __BIG_ENDIAN
00022 #define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
00023 #define LE_SHORT(v) bswap_16(v)
00024 #define LE_INT(v) bswap_32(v)
00025 #define BE_SHORT(v) (v)
00026 #define BE_INT(v) (v)
00027 #else
00028 #error "Wrong endian"
00029 #endif
00030
00031 #define WAV_RIFF COMPOSE_ID('R','I','F','F')
00032 #define WAV_WAVE COMPOSE_ID('W','A','V','E')
00033 #define WAV_FMT COMPOSE_ID('f','m','t',' ')
00034 #define WAV_DATA COMPOSE_ID('d','a','t','a')
00035 #define WAV_PCM_CODE 1
00036
00037
00038
00039
00040
00041 typedef struct {
00042 u_int magic;
00043 u_int length;
00044 u_int type;
00045 } WaveHeader;
00046
00047 typedef struct {
00048 u_short format;
00049 u_short modus;
00050 u_int sample_fq;
00051 u_int byte_p_sec;
00052 u_short byte_p_spl;
00053 u_short bit_p_spl;
00054 } WaveFmtBody;
00055
00056 typedef struct {
00057 u_int type;
00058 u_int length;
00059 } WaveChunkHeader;
00060
00061 long long fdcount = 0;
00062
00063
00064 static int begin_wave(int fd, size_t cnt) {
00065 WaveHeader h;
00066 WaveFmtBody f;
00067 WaveChunkHeader cf, cd;
00068 int bits;
00069 u_int tmp;
00070 u_short tmp2;
00071
00072
00073 if(cnt == (size_t) - 2)
00074 cnt = 0x7fffff00;
00075
00076 bits = 8;
00077 unsigned long audio_format = SND_PCM_FORMAT_S16_LE;
00078
00079 switch ((unsigned long) audio_format) {
00080 case SND_PCM_FORMAT_U8:
00081 bits = 8;
00082 break;
00083 case SND_PCM_FORMAT_S16_LE:
00084 case SND_PCM_FORMAT_S16_BE:
00085 bits = 16;
00086 break;
00087 case SND_PCM_FORMAT_S32_LE:
00088 bits = 32;
00089 break;
00090 case SND_PCM_FORMAT_S24_LE:
00091 case SND_PCM_FORMAT_S24_3LE:
00092 bits = 24;
00093 break;
00094 default:
00095 return -1;
00096
00097
00098 }
00099 h.magic = WAV_RIFF;
00100 tmp = cnt + sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + sizeof(WaveChunkHeader) - 8;
00101 h.length = LE_INT(tmp);
00102 h.type = WAV_WAVE;
00103
00104 cf.type = WAV_FMT;
00105 cf.length = LE_INT(16);
00106
00107 f.format = LE_SHORT(WAV_PCM_CODE);
00108 f.modus = LE_SHORT(state->audio_channels);
00109 f.sample_fq = LE_INT(state->audio_rate);
00110 #if 0
00111 tmp2 = (samplesize == 8) ? 1 : 2;
00112 f.byte_p_spl = LE_SHORT(tmp2);
00113 tmp = dsp_speed * hwparams.channels * (u_int) tmp2;
00114 #else
00115
00116 tmp2 = state->audio_channels * snd_pcm_format_physical_width(audio_format) / 8;
00117 f.byte_p_spl = LE_SHORT(tmp2);
00118 tmp = (u_int) tmp2 * state->audio_rate;
00119 #endif
00120 f.byte_p_sec = LE_INT(tmp);
00121 f.bit_p_spl = LE_SHORT(bits);
00122
00123 cd.type = WAV_DATA;
00124 cd.length = LE_INT(cnt);
00125
00126 if(write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) ||
00127 write(fd, &cf, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader) ||
00128 write(fd, &f, sizeof(WaveFmtBody)) != sizeof(WaveFmtBody) ||
00129 write(fd, &cd, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) {
00130 return -2;
00131
00132
00133 }
00134
00135 return 0;
00136 }
00137
00138 static void end_wave(int fd) {
00139
00140 WaveChunkHeader cd;
00141 off_t length_seek;
00142 off_t filelen;
00143 u_int rifflen;
00144
00145 length_seek = sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody);
00146 cd.type = WAV_DATA;
00147 cd.length = fdcount > 0x7fffffff ? LE_INT(0x7fffffff) : LE_INT(fdcount);
00148 filelen = fdcount + 2*sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + 4;
00149 rifflen = filelen > 0x7fffffff ? LE_INT(0x7fffffff) : LE_INT(filelen);
00150 if(lseek(fd, 4, SEEK_SET) == 4)
00151 write(fd, &rifflen, 4);
00152 if(lseek(fd, length_seek, SEEK_SET) == length_seek)
00153 write(fd, &cd, sizeof(WaveChunkHeader));
00154 if(fd != 1)
00155 close(fd);
00156 }
00157
00158 int wave_fd;
00159
00160 void wave_begin(const char *fname) {
00161 wave_fd = open(fname, O_RDWR | O_CREAT);
00162 int r = begin_wave(wave_fd, 0);
00163 fprintf(stderr, "fname == \"%s\", wave_fd == %d, begin_wave() == %d\n", fname, wave_fd, r);
00164 }
00165
00166 void wave_push(void *buf, int len) {
00167 fdcount += write(wave_fd, buf, len);
00168 }
00169
00170 void wave_end() {
00171 end_wave(wave_fd);
00172 }