📄 audiofile.cpp
字号:
// Copyright (C) 1999-2005 Open Source Telecom Corporation.// // This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.// // This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.// // As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however// invalidate any other reasons why the executable file might be covered by// the GNU General Public License.//// This exception applies only to the code released under the name GNU// ccAudio. If you copy code from other releases into a copy of GNU// ccAudio, as the General Public License permits, the exception does// not apply to the code that you add in this way. To avoid misleading// anyone as to the status of such modified files, you must delete// this exception notice from them.//// If you write modifications of your own for GNU ccAudio, it is your choice// whether to permit this exception to apply to your modifications.// If you do not wish that, delete this exception notice.//#include "private.h"#include "audio2.h"#include <cstdio>using namespace ost;static const char * const ErrorStrs[] = { "errSuccess", "errReadLast", "errNotOpened", "errEndOfFile", "errStartOfFile", "errRateInvalid", "errEncodingInvalid", "errReadInterrupt", "errWriteInterrupt", "errReadFailure", "errWriteFailure", "errReadIncomplete", "errWriteIncomplete", "errRequestInvalid", "errTOCFailed", "errStatFailed", "errInvalidTrack", "errPlaybackFailed", "errNotPlaying"};AudioCodec *AudioFile::getCodec(void){ Encoding e = getEncoding(); switch(e) { case alawAudio: return AudioCodec::getCodec(e, "g.711"); case mulawAudio: return AudioCodec::getCodec(e, "g.711"); case g721ADPCM: case okiADPCM: case voxADPCM: return AudioCodec::getCodec(e, "g.721"); case g722_7bit: case g722_6bit: return AudioCodec::getCodec(e, "g.722"); case g723_3bit: case g723_5bit: return AudioCodec::getCodec(e, "g.723"); default: return NULL; }}void AudioFile::setShort(unsigned char *data, unsigned short val){ if(info.order == __BIG_ENDIAN) { data[0] = val / 256; data[1] = val % 256; } else { data[1] = val / 256; data[0] = val % 256; }}unsigned short AudioFile::getShort(unsigned char *data){ if(info.order == __BIG_ENDIAN) return data[0] * 256 + data[1]; else return data[1] * 256 + data[0];}void AudioFile::setLong(unsigned char *data, unsigned long val){ int i = 4; while(i-- > 0) { if(info.order == __BIG_ENDIAN) data[i] = (unsigned char)(val & 0xff); else data[3 - i] = (unsigned char)(val & 0xff); val /= 256; }}unsigned long AudioFile::getLong(unsigned char * data){ int i = 4; unsigned long val =0; while(i-- > 0) { if(info.order == __BIG_ENDIAN) val = (val << 8) | data[3 - i]; else val = (val << 8) | data[i]; } return val;}AudioFile::AudioFile(const char *name, unsigned long sample) :AudioBase(){ pathname = NULL; initialize(); AudioFile::open(name); if(!isOpen()) return; setPosition(sample);}AudioFile::AudioFile(const char *name, Info *inf, unsigned long samples) :AudioBase(inf){ pathname = NULL; initialize(); AudioFile::create(name, inf); if(!isOpen()) return; setMinimum(samples);}AudioFile::~AudioFile(){ AudioFile::close(); AudioFile::clear();}void AudioFile::create(const char *name, Info *myinfo, bool exclusive, timeout_t framing){ int pcm = 0; unsigned char aufile[24]; unsigned char riffhdr[40]; const char *ext = strrchr(name, '/'); if(!ext) ext = strrchr(name, '\\'); if(!ext) ext = strrchr(name, ':'); if(!ext) ext = strrchr(name, '.'); else ext = strrchr(ext, '.'); if(!ext) ext = ".none"; mode = modeWrite; if(!afCreate(name, exclusive)) return; memset(riffhdr, 0, sizeof(riffhdr)); memcpy(&info, myinfo, sizeof(info)); info.annotation = NULL; pathname = new char[strlen(name) + 1]; strcpy(pathname, name); if(myinfo->annotation) { info.annotation = new char[strlen(myinfo->annotation) + 1]; strcpy(info.annotation, myinfo->annotation); } if(!stricmp(ext, ".raw") || !stricmp(ext, ".bin")) { info.format = raw; if(info.encoding == unknownEncoding) info.encoding = pcm16Mono; } else if(!stricmp(ext, ".au") || !stricmp(ext, ".snd")) { info.order = 0; info.format = snd; } else if(!stricmp(ext, ".wav") || !stricmp(ext, ".wave")) { info.order = 0; info.format = wave; } else if(!stricmp(ext, ".ul") || !stricmp(ext, ".ulaw") || !stricmp(ext, ".mulaw")) { info.encoding = mulawAudio; info.format = raw; info.order = 0; info.rate = 8000; } else if(!stricmp(ext, ".al") || !stricmp(ext, ".alaw")) { info.encoding = alawAudio; info.format = raw; info.order = 0; info.rate = 8000; } else if(!stricmp(ext, ".sw") || !stricmp(ext, ".pcm")) { info.encoding = pcm16Mono; info.format = raw; info.order = 0; } else if(!stricmp(ext, ".vox")) { info.encoding = voxADPCM; info.format = raw; info.order = 0; info.rate = 6000; } else if(!stricmp(ext, ".gsm")) { info.encoding = gsmVoice; info.format = raw; info.order = 0; info.rate = 8000; info.framecount = 160; info.framesize = 33; info.bitrate = 13200; } else if(!stricmp(ext, ".adpcm")) { info.encoding = g721ADPCM; info.format = raw; info.order = 0; info.rate = 8000; } else if(!stricmp(ext, ".a24")) { info.encoding = g723_3bit; info.format = raw; info.order = 0; info.rate = 8000; } else if(!stricmp(ext, ".sx")) { info.encoding = sx96Voice; info.format = raw; info.order = 0; info.rate = 8000; } else if(!stricmp(ext, ".a40")) { info.encoding = g723_5bit; info.format = raw; info.order = 0; info.rate = 8000; } else if(!stricmp(ext, ".cda")) { info.encoding = cdaStereo; info.format = raw; info.order = __LITTLE_ENDIAN; info.rate = 44100; } switch(info.format) { case wave: case riff: /* * RIFF header * * 12 bytes * * 0-3: RIFF magic "RIFF" (0x52 49 46 46) * * 4-7: RIFF header chunk size * (4 + (8 + subchunk 1 size) + (8 + subchunk 2 size)) * * 8-11: WAVE RIFF type magic "WAVE" (0x57 41 56 45) */ if(!info.order) info.order = __LITTLE_ENDIAN; if(info.order == __LITTLE_ENDIAN) strncpy((char *)riffhdr, "RIFF", 4); else strncpy((char *)riffhdr, "RIFX", 4); if(!info.rate) info.rate = Audio::getRate(info.encoding); if(!info.rate) info.rate = rate8khz; header = 0; memset(riffhdr + 4, 0xff, 4); strncpy((char *)riffhdr + 8, "WAVE", 4); if(afWrite(riffhdr, 12) != 12) { AudioFile::close(); return; } /* * Subchunk 1: WAVE metadata * * Length: 24+ * * (offset from start of subchunk 1) startoffset-endoffset * * (0) 12-15: WAVE metadata magic "fmt " (0x 66 6d 74 20) * * (4) 16-19: subchunk 1 size minus 8. 0x10 for PCM. * * (8) 20-21: Audio format code. 0x01 for linear PCM. * More codes here: * http://www.goice.co.jp/member/mo/formats/wav.html * * (10) 22-23: Number of channels. Mono = 0x01, * Stereo = 0x02. * * (12) 24-27: Sample rate in samples per second. (8000, * 44100, etc) * * (16) 28-31: Bytes per second = SampleRate * * NumChannels * (BitsPerSample / 8) * * (20) 32-33: Block align (the number of bytes for * one multi-channel sample) = Numchannels * * (BitsPerSample / 8) * * (22) 34-35: Bits per single-channel sample. 8 bits * per channel sample = 0x8, 16 bits per channel * sample = 0x10 * * (24) 36-37: Size of extra PCM parameters for * non-PCM formats. If a PCM format code is * specified, this doesn't exist. * * Subchunk 3: Optional 'fact' subchunk for non-PCM formats * (26) 38-41: WAVE metadata magic 'fact' (0x 66 61 63 74) * * (30) 42-45: Length of 'fact' subchunk, not * including this field and the fact * identification field (usually 4) * * (34) 46-49: ??? sndrec32.exe outputs 0x 00 00 00 00 * here. See * http://www.health.uottawa.ca/biomech/csb/ARCHIVES/riff-for.txt * */ memset(riffhdr, 0, sizeof(riffhdr)); strncpy((char *)riffhdr, "fmt ", 4); // FIXME A bunch of the following only works for PCM // and mulaw/alaw, so you'll probably have to fix it // if you want to use one of the other formats. if(info.encoding < cdaStereo) setLong(riffhdr + 4, 18); else setLong(riffhdr + 4, 16); setShort(riffhdr + 8, 0x01); // default in case invalid encoding specified if(isMono(info.encoding)) setShort(riffhdr + 10, 1); else setShort(riffhdr + 10, 2); setLong(riffhdr + 12, info.rate); setLong(riffhdr + 16, (unsigned long)toBytes(info, info.rate)); setShort(riffhdr + 20, (snd16_t)toBytes(info, 1)); setShort(riffhdr + 22, 0); switch(info.encoding) { case pcm8Mono: case pcm8Stereo: setShort(riffhdr + 22, 8); pcm = 1; break; case pcm16Mono: case pcm16Stereo: case cdaMono: case cdaStereo: setShort(riffhdr + 22, 16); pcm = 1; break; case pcm32Mono: case pcm32Stereo: setShort(riffhdr + 22, 32); pcm = 1; break; case alawAudio: setShort(riffhdr + 8, 6); setShort(riffhdr + 22, 8); break; case mulawAudio: setShort(riffhdr + 8, 7); setShort(riffhdr + 22, 8); break; // FIXME I'm pretty sure these are supposed to // be writing to offset 22 instead of 24... case okiADPCM: setShort(riffhdr + 8, 0x10); setShort(riffhdr + 24, 4); break; case voxADPCM: setShort(riffhdr + 8, 0x17); setShort(riffhdr + 24, 4); break; case g721ADPCM: setShort(riffhdr + 8, 0x40); setShort(riffhdr + 24, 4); break; case g722Audio: setShort(riffhdr + 8, 0x64); setShort(riffhdr + 24, 8); break; case gsmVoice: case msgsmVoice: setShort(riffhdr + 8, 0x31); setShort(riffhdr + 24, 260); break; case g723_3bit: setShort(riffhdr + 8, 0x14); setShort(riffhdr + 24, 3); break; case g723_5bit: setShort(riffhdr + 8, 0x14); setShort(riffhdr + 24, 5); case unknownEncoding: default: break; } if(pcm == 0) { setShort(riffhdr + 24, 0); strncpy((char *)(riffhdr + 26), "fact", 4); setLong(riffhdr + 30, 4); setLong(riffhdr + 34, 0); if(afWrite(riffhdr, 38) != 38) { AudioFile::close(); return; } } else { if(afWrite(riffhdr, 24) != 24) { AudioFile::close(); return; } } /* * Subchunk 2: data subchunk * * Length: 8+ * * (0) 36-39: data subchunk magic "data" (0x 64 61 74 61) * * (4) 40-43: subchunk 2 size = * NumSamples * NumChannels * (BitsPerSample / 8) * Note that this does not include the size of this * field and the previous one. * * (8) 44+: Samples */ memset(riffhdr, 0, sizeof(riffhdr)); strncpy((char *)riffhdr, "data", 4); memset(riffhdr + 4, 0xff, 4); if(afWrite(riffhdr, 8) != 8) { AudioFile::close(); return; } header = getAbsolutePosition(); length = getAbsolutePosition(); break; case snd:// if(!info.order) info.order = __BIG_ENDIAN; if(!info.rate) info.rate = Audio::getRate(info.encoding); if(!info.rate) info.rate = rate8khz; strncpy((char *)aufile, ".snd", 4); if(info.annotation) setLong(aufile + 4, 24 + (unsigned long)strlen(info.annotation) + 1); else setLong(aufile + 4, 24); header = getLong(aufile + 4); setLong(aufile + 8, ~0l); switch(info.encoding) { case pcm8Stereo: case pcm8Mono: setLong(aufile + 12, 2); break; case pcm16Stereo: case pcm16Mono: case cdaStereo: case cdaMono: setLong(aufile + 12, 3); break; case pcm32Stereo: case pcm32Mono: setLong(aufile + 12, 5); break; case g721ADPCM: setLong(aufile + 12, 23); break; case g722Audio: case g722_7bit: case g722_6bit: setLong(aufile + 12, 24); break; case g723_3bit: setLong(aufile + 12, 25); break; case g723_5bit: setLong(aufile + 12, 26); break; case alawAudio: setLong(aufile + 12, 27); break; default: setLong(aufile + 12, 1); } setLong(aufile + 16, info.rate); if(isMono(info.encoding)) setLong(aufile + 20, 1); else setLong(aufile + 20, 2); if(afWrite(aufile, 24) != 24) { AudioFile::close(); return; } if(info.annotation) afWrite((unsigned char *)info.annotation, (unsigned long)strlen(info.annotation) + 1); header = getAbsolutePosition(); length = getAbsolutePosition(); break; case mpeg: framing = 0; info.headersize = 4; // no crc... case raw: break; } if(framing) info.setFraming(framing); else info.set();}void AudioFile::getWaveFormat(int request){ unsigned char filehdr[24]; int bitsize; int channels; if(request > 24) request = 24; if(!afPeek(filehdr, request)) { AudioFile::close(); return; } channels = getShort(filehdr + 2); info.rate = getLong(filehdr + 4); switch(getShort(filehdr)) { case 1: bitsize = getShort(filehdr + 14); switch(bitsize) { case 8: if(channels > 1) info.encoding = pcm8Stereo; else info.encoding = pcm8Mono; break; case 16: if(info.rate == 44100) { if(channels > 1) info.encoding = cdaStereo; else info.encoding = cdaMono; break; } if(channels > 1) info.encoding = pcm16Stereo; else info.encoding = pcm16Mono; break; case 32: if(channels > 1) info.encoding = pcm32Stereo; else info.encoding = pcm32Mono; break; default: info.encoding = unknownEncoding; } break; case 6: info.encoding = alawAudio; break; case 7: info.encoding = mulawAudio; break; case 0x10: info.encoding = okiADPCM; break; case 0x17: info.encoding = voxADPCM; break; case 0x40: info.encoding = g721ADPCM; break; case 0x65: info.encoding = g722Audio; break; case 0x31: info.encoding = msgsmVoice; break; case 0x14: bitsize = getLong(filehdr + 8) * 8 / info.rate; if(bitsize == 3) info.encoding = g723_3bit; else info.encoding = g723_5bit; break; default: info.encoding = unknownEncoding; }}void AudioFile::open(const char *name, Mode m, timeout_t framing){ unsigned char filehdr[24]; unsigned int count; char *ext; unsigned channels; mpeg_audio *mp3 = (mpeg_audio *)&filehdr; mode = m; while(!afOpen(name, m)) { if(mode == modeReadAny || mode == modeReadOne) name = getContinuation(); else name = NULL; if(!name) return; } pathname = new char[strlen(name) + 1]; strcpy(pathname, name); header = 0l; info.framesize = 0; info.framecount = 0; info.encoding = mulawAudio; info.format = raw; info.order = 0; ext = strrchr(pathname, '.'); if(!ext) goto done; if(!stricmp(ext, ".ul") || !stricmp(ext, ".ulaw") || !stricmp(ext, ".mulaw")) { info.encoding = mulawAudio; goto done; } if(!stricmp(ext, ".al") || !stricmp(ext, ".alaw")) { info.encoding = alawAudio; goto done; } if(!stricmp(ext, ".sw") || !stricmp(ext, ".raw") || !stricmp(ext, ".pcm")) { info.encoding = pcm16Mono; goto done; } if(!stricmp(ext, ".vox")) { info.encoding = voxADPCM; goto done; } if(!stricmp(ext, ".adpcm")) { info.encoding = g721ADPCM; goto done; } if(!stricmp(ext, ".a24")) { info.encoding = g723_3bit; goto done; } if(!stricmp(ext, ".a40")) { info.encoding = g723_5bit; goto done; } if(!stricmp(ext, ".cda")) { info.order = __LITTLE_ENDIAN; info.encoding = cdaStereo; goto done; } strcpy((char *)filehdr, ".xxx"); if(!afPeek(filehdr, 24)) { AudioFile::close(); return; } if(!strncmp((char *)filehdr, "RIFF", 4)) { info.format = riff; info.order = __LITTLE_ENDIAN; } if(!strncmp((char *)filehdr, "RIFX", 4)) { info.order = __BIG_ENDIAN; info.format = riff; } if(!strncmp((char *)filehdr + 8, "WAVE", 4) && info.format == riff) { header = 12; for(;;) { if(!afSeek(header)) { AudioFile::close(); return; } if(!afPeek(filehdr, 8)) { AudioFile::close(); return; } header += 8; if(!strncmp((char *)filehdr, "data", 4)) break; count = getLong(filehdr + 4); header += count; if(!strncmp((char *)filehdr, "fmt ", 4)) getWaveFormat(count); } afSeek(header); goto done; } if(!strncmp((char *)filehdr, ".snd", 4)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -