iPhone應(yīng)用開(kāi)發(fā)中關(guān)于PCM播放器源碼學(xué)習(xí)
iPhone應(yīng)用開(kāi)發(fā)中關(guān)于PCM播放器源碼學(xué)習(xí)是本文要介紹的內(nèi)容,由于原始PCM文件不能容納任何關(guān)于其自身頻率或者幀大小之類的信息,本例將不得不對(duì)此自行設(shè)置。
我們會(huì)使用一種為經(jīng)過(guò)壓縮的PCM數(shù)據(jù)格式,具體參數(shù)喂16位、44KHz、單聲道。這些信息通過(guò)程序頂部的三個(gè)預(yù)定義值指定:
- #define BYTES_PER_SAMPLE 2
16位等于兩個(gè)字節(jié)
- #define SAMPLE_PATE 44100
每秒采樣率44100次等于44KHz
- typedef unsigned short sampleFrame;
- 一個(gè)unsigned short 等于兩個(gè)字節(jié)(每個(gè)采樣)
- #include <stdio.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <AudioToolbox/AudioQueue.h>
- #define BYTES_PER_SAMPLE 2
- #define SAMPLE_PATE 44100
- typedef unsigned short sampleFrame;
- #define FRAME_COUNT 735
- #define AUDIO_BUFFERS 3
- typedef struct AQCallbackStruct{
- AudioQueueRef queue;//播放隊(duì)列
- UInt32 FrameCount;
- AudioQueueBufferRef mBuffers[AUDIO_BUFFERS];
- AudioStreamBasicDescription mDataFormat;
- UInt32 sampleLen;
- UInt32 playPtr;
- sampleFrame *pcmBuffer;
- }AQCallbackStruct;
- void *loadpacm(const char *filename,unsigned long *len);
- int playbuffer(void *pcm,unsigned long len);
- void AQBufferCallback(void *in,AudioQueueRef inQ,AudioQueueBufferRef outQB);
- int main(int argc,char *argv[])
- {
- char *filename;
- unsigned long len;
- void *pcmBuffer;
- int ret;
- if (argc<2)
- {
- fprintf(stderr, "Syntax: %s [filename]\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- filename = argv[1];
- pcmBuffer = loadpacm(filename, &len);
- if (!pcmBuffer)
- {
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
- exit(EXIT_FAILURE);
- }
- ret = playbuffer(pcmBuffer,len);
- free(pcmBuffer);
- return ret;
- }
- void *loadpcm(const char *filename,unsigned long *len)
- {
- FILE *file;
- struct stat s;
- void *pcm;
- if (stat(filename,&s)) {
- return NULL;
- *len = s.st_size;
- }
- pcm = (void *) malloc(s.st_size);
- if (!pcm) {
- return NULL;
- file = fopen(filename,"sb");
- }
- if(!file)
- {
- free(pcm);
- return NULL;
- }
- fread(pcm,s.st_size,1,file);
- fclose(file);
- return pcm;
- }
- int playbuffer(void *pcmBuffer,unsigned long len)
- {
- AQCallbackStruct agc;
- UInt32 err,bufferSize;
- int i;
- agc.mDataFormat.mSampleRate = SAMPLE_PATE;
- agc.mDataFormat.mFormatID = kAudioFormatLinearPCM;
- agc.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
- agc.mDataFormat.mBytesPerPacket = 4;
- agc.mDataFormat.mFramesPerPacket = 1;
- agc.mDataFormat.mBytesPerFrame = 4;
- agc.mDataFormat.mChannelsPerFrame = 2;
- agc.mDataFormat.mBitsPerChannel = 16;
- agc.FrameCount = FRAME_COUNT;
- agc.sampleLen = len/BYTES_PER_SAMPLE;
- agc.playPtr = 0;
- agc.pcmBuffer = pcmBuffer;
- err = AudioQueueNewOutput(&agc.mDataFormat,AQBufferCallback,&agc,NULL,
- kCFRunLoopCommonModes,0,&agc.queue);
- if(err) return err;
- agc.FrameCount = FRAME_COUNT;
- bufferSize = agc.FrameCount * agc.mDataFormat.mBytesPerFrame;
- for (i=0; i<AUDIO_BUFFERS; i++)
- {
- err = AudioQueueAllocateBuffer(agc.queue,bufferSize,&agc.mBuffers[i]);
- if(err) return err;
- AQBufferCallback(&agc,agc.queue,agc.mBuffers[i]);
- }
- err = AudioQueueStart(agc.queue,NULL);
- if(err) return err;
- while (agc.playPtr<agc.sampleLen)
- {
- select(NULL,NULL,NULL,NULL,1.0);
- }
- sleep(1);
- return 0;
- }
- void AQBufferCallback( void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB)
- {
- AQCallbackStruct *agc;
- short *coreAudiobuffer;
- short sample;
- int i;
- agc=(AQCallbackStruct *) in;
- coreAudiobuffer =(short*) outQB->mAudioData;
- printf("Sync:%i / %i \n",agc->playPtr,agc->sampleLen);
- if (agc->FrameCount >0)
- {
- outQB->mAudioDataByteSize = 4*agc->FrameCount;
- for (i=0; i<agc->FrameCount*2; i++)
- {
- if(agc->playPtr > agc->sampleLen || agc->playPtr<0)
- {
- sample =0;
- }
- else
- {
- sample = (agc->pcmBuffer[agc->playPtr]);
- }
- coreAudiobuffer[i] = sample;
- coreAudiobuffer[i+1] = sample;
- agc->playPtr++;
- }
- AudioQueueEnqueueBuffer(inQ,outQB,0,NULL);
- }
}如果你無(wú)法找到一個(gè)原始的PCM元數(shù)據(jù),你可以用.wav格式文件代替,制藥以16位44KHz原始PCM編碼的就行。
編譯命令:
- $ gcc -o playpcm playpcm.c \
- -framework AudioToolbox -framework CoreAudio -framework CoreFoundation
小結(jié):iPhone應(yīng)用開(kāi)發(fā)中關(guān)于PCM播放器源碼學(xué)習(xí)的內(nèi)容介紹完了,希望通過(guò)本文的學(xué)習(xí)能對(duì)你有所幫助!