Главная » iPhone » Пример: проигрыватель РСМ iPhone

0

Поскольку платформа Audio Toolbox проживает в стране С, то имеется неплохая возможность привести пример для iPhone, который не использует Objective-C или же платформу UIKit. В данном примере применяется старый добрый С, а сам пример запускается из командной строки с именем файла. Он загружает необработанный файл РСМ, а затем воспроизводит его с помощью аудиоочереди Audio Toolbox. Поскольку ваше приложение, скорее всего, будет само порождать данные, и не использовать файл, то мы сначала будем читать файл в память буфера, а затем воспроизводить его из памяти буфера, чтобы проиллюстрировать практический принцип. Это должно послужить основанием для большинства приложений принять подобную архитектуру.

Поскольку необработанный файл РСМ не содержит какую-либо информацию о частоте или размере фрейма, то данный пример вынужден будет присвоить свои собственные значения. Мы будем использовать формат для 16-битных 44 кГц несжатых моноданных РСМ. Это задается тремя определениями, сделанными в самом верху программы:

#define BYTES_PER_SAMPLE 2 16-bit = 2 bytes

#define SAMPLE RATE 44100

44,100 samples per second =44 KHz typedef unsigned short sampleFrame;

unsigned short равен двум байтам (на дорожку).

Если вы не можете найти необработанный файл РСМ для выполнения этого примера, то можете использовать \\а\-файл при условии, что он закодирован в 16-битном 44-килогерцовом необработанном формате РСМ. Иначе вы можете адаптировать этот пример для использования другой кодировки, изменив mFormatid внутри структуры аудиоочереди. Этот пример не будет пытаться произвести разбор заголовков vvav-файла, он всего лишь предполагает, что предоставляемые вами данные являются необработанными, т. е. такими, какие предоставляют игры или приложения другого типа. Заголовки \vav- файла будут передаваться в аудиоканал с остальными данными, поэтому, возможно, вы будете слышать легкий щелчок или хлопок перед началом воспроизведения необработанных звуковых данных внутри файла.

Чтобы скомпилировать данный пример с помощью пакета инструментов, воспользуйтесь командной строкой:

$ arm-apple-darwinS-gcc -о playpcm playpcm.c

-framework AudioToolbox -framework CoreAudio

-framework CoreFoundation ^

-DMAC_OS_X_versIon_MAX_ALLOWED=MAC_OS_X VERSion_l0_5 Ь -DMAC_OS_X_versION_MIN_REQUIRED=MAC_os_ X_VERS10N_10_5

Поскольку Leopard также включает в себя платформу Audio Toolbox, то данный пример может быть скомпилирован и на настольной системе:

$ gcc -о playpcm playpcm.c

ramework AudioToolbox -framework CoreAudio -framework CoreFoundation

В листинге 6.3 приведен сам код.

«include  <stdio.h>

"include  <stdlib.h>

=include  <errno.h>

=include  <sys/stat.h>

* include <AudioToolbox/AudioQueue.h>

#define BYTES_PER_SAMPLE 2 ^define SAMPLE_RATE 44100 typedef unsigned short sampleFrame;

#define FRAME_COUNT 735 #define AUDIO_BUFFERS 3

typedef struct AQCallbackStruct { AudioQueueRef queue; UInt32 frameCount;

AudioQueueBufferRef mBuffers[AUDIO_BUFFERS]; AudioSt reamBas icDescription mDataFormat; UInt32 playPtr; UInt32 sampleLen; sampleFrame *pcmBuffer; } AQCallbackStruct;

void *loadpcm(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[l];

pcmbuffer = loadpcm(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 *finstruct 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, "rb"); ‘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 aqc; UInt32 err, bufferSize; int i;

aqc.mDataFormat.mSampleRate = SAMPLE_RATE;

aqc.mDataFormat.mFormatID = kAudioFormatLinearPCM;

aqc.mDataFormat.mFormatFlags = kLinearPCMFormatFlaglsSignedlnteger

I kAudioFormatFlaglsPacked; aqc.mDataFormat.mBytesPerPacket = 4; aqc.mDataFormat.mFramesPerPacket = 1; aqc.mDataFormat.mBytesPerFrame = 4; aqc.mDataFormat.mChanneIsPerFrame = 2; aqc.mDataFormat.mBitsPerChannel = 16; aqc.frameCount = FRAME_COUNT; aqc.sampleLen = len / BYTES_PER_SAMPLE; aqc.playPtr = 0; aqc.pcmBuffer = pcmbuffer;

err = AudioQueueNewOutput(&aqc.mDataFormat, AQBufferCallback,

&aqc, NULL, kCFRunLoopCommonModes, 0, &aqc.queue);

if (err) return err;

aqc.frameCount = FRAME_COUNT;

bufferSize = aqc.frameCount * aqc.mDataFormat.mBytesPerFrame; for (i=0; i<AUDIO_BUFFERS; i++) {

err = AudioQueueAllocateBuffer(aqc.queue, bufferSize,

&aqc.mBuffers[i]); if (err)

return err;

AQBufferCallback(&aqc, aqc.queue, aqc.mBuffers[i]);

}

err = AudioQueueStart(aqc.queue, NULL); if (err)

return err;

while(aqc.playPtr < aqc.sampleLen)

{ select(NULL, NULL, NULL, NULL, 1.0); }

sleep(1); return 0;

)

void AQBufferCallback(void *in, AudioQueueRef inQ,

AudioQueueBufferRef outQB)

{

AQCallbackStruct *aqc; short *coreAudioBuffer; short sample; int i;

aqc = (AQCallbackStruct *) in; coreAudioBuffer = (short*) outQB->mAudioData;

printf("Sync: Id / %ld\n", aqc->playPtr, aqc->sampleLen); if (aqc->playPtr >= aqc->sampleLen) { AudioQueueDispose(aqc->queue, true); return;

if (aqc->frameCount >0) {

outQB->mAudioDataByteSize = 4 * aqc->frameCount; for(i=0; i<aqc->frameCount*2; i+=2) {

if (aqc->playPtr > aqc->sampleLen || aqc->playPtr < 0)

sample = 0; else

sample = (aqc->pcmBuffer[aqc->playPtr]); coreAudioBuffer[i] = sample; coreAudioBuffer[i+1] = sample; aqc->playPtr++;

}

AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL);

;

Как это работает

Вот как работает программа playpcm:

1.    В начале программы вызывается функция приложения mainO, которая извлекает имя файла из списка аргументов (передаваемого в командной строке).

2.     Функция mainO вызывает loadpcm(), которая определяет длину аудиофайла и загружает его в память, возвращая этот буфер функции main о .

3.      Вызывается функция playbufferO с содержимым этой памяти и ее длиной. Эта функция создает нашу определяемую пользователем структуру AQCaiibackstruct, чья конструкция декларируется в начале программы. Эта структура хранит указатели на аудиоочередь, звуковые буферы и память. хранящую содержимое загруженного файла. Кроме того, она содержит длину дорожки и целое число playPtr. которое выступает в роли записывающей иглы, определяя последнюю дорожку, скопированную в звуковой буфер.

4.      Инициализируется и запускается новая звуковая очередь. Чтобы синхронизировать первые дорожки в памяти, вызывается функция обратного вызова по одному разу для каждого используемого звукового буфера. Затем стартует аудиоочередь. После этого программа сидит и ждет, когда закончится воспроизведение текущей дорожки.

5.      По мере воспроизведения аудио один за другим опустошаются звуковые буферы. Каждый раз. когда какому-либо буферу необходимы еще звуковые данные, вызывается функция AQBufferCallback.

6.     Функция AQBufferCallback увеличивает playPtr и копирует следующие звуковые фреймы из памяти для воспроизведения в звуковой буфер. Поскольку необработанные дорожки РСМ являются моно. то одинаковые данные копируются как в левый, так и в правый выходной канал.

7.     Когда playPtr превысит длину звуковой дорожки, то цикл ожидания в playpcm о разорвется, в результате чего функция вернется обратно к mainO для освобождения ресурсов и выхода.

Для дальнейшего изучения

Постарайтесь выполнить следующие задания.

? Модифицируйте этот пример для воспроизведения 8-битного звука РСМ, изменив тип данных sampleFrame и bytes per sample. Также вам придется увеличить уровень громкости, поскольку звуковая дорожка теперь имеет длин) в один байт, а канал аудиоочереди имеет длину в два байта.

? Проверьте наличие AudioQueue.li в Mac OS X Leopard на настольной системе. Вы сможете найти его в папке /System/Library/Frameworks/ AudioToolbox. framework/Headers/.

Источник: Здзиарски Дж. iPhone. Разработка приложений с открытым кодом: Пер„с англ. — 2-е изд., перераб. и доп. — СПб.: БХВ-Петербург, 2009. — 368 е.: ил.

По теме:

  • Комментарии