Реалізація черги

Черга (також відома під назвоюкільцевого буфера)це стандартне засіб, що використовується в разі, якщо споживач і джерело даних не могутсінхронізіровать свою роботу за часом B нашому випадку споживачем даних є апаратура відтворення звуку, при роботі з нею необхідно дотримувати жорсткі вимоги по часу Інша частина програми готує дані, використовуючи файловий ввід / вивід, компресію та інші операції, час виконання яких непередбачувано

Лістинг 53 Програма aplayercpp (продовження)

void AbstractPlayer::InitializeQueue(unsigned long queueSize) {

_queue = new AudioSample[queueSize]

_queueEnd = _queue+queueSize

_queueFirst = _queueLast = _queue FillQueue()

}

B операційних системах Mac OS і Windows звернення до черги походять з різних потоків При використанні багатопотокового програмування необхідна особлива акуратність Зверніть увагу, що відповідні покажчики помічені як volatile (рухливі) Крім того, необхідно відзначити, що важливий порядок, в якому проводиться оновлення вказівників При додаванні, наприклад, даних в чергу, дані спочатку копіюються в область памяті, відведену під чергу, а потім коригуються покажчики Таким чином, якщо які-небудь потоки вважають дані з черги в ході процесу додавання даних в чергу, їм будуть доступні для читання тільки ті з них, на які посилаються покажчики

He забувайте про різницю між змінними _queue і _queueEnd, які вказують на початок і кінець області памяті, займаної чергою і змінними _queueFirst і _queueLast, що посилаються на перший і останній байти активного блоку даних у цій черзі (B сутності, _queueLast вказує на перший байт, що йде після блоку активних даних) Тут потрібно розглянути два важливих випадку B ситуації, коли _queueFirst менше, ніж _queueLast, активний блок даних розташований в середині черги Якщо _queueFirst більше, ніж

_queueLast, значить чергу «загорнулася»

Важливо ніколи не допускати максимального заповнення черги B іншому

випадку ви опинитеся в складній ситуації Значення змінних _queueLast

і _queueFirst можуть бути рівними, тільки якщо чергу порожня, або зовсім

заповнена Якщо ви спробуєте максимально заповнити чергу, створиться враження, ніби вона порожня, в результаті чого ви втратите блок даних, обсяг якого в точності дорівнює розміру черги

Також врахуйте, що, оскільки при використанні декількох каналів звук записується у вигляді фреймів (див розділ «Стереозвук» в розділі 4),  необхідно стежити за тим, щоб запитуваний обсяг даних був кратним числу каналів

Лістинг 5З Програма aplayercpp (продовження)

void AbstractPlayer::FillQueue() {

if (_endOfSource &amp&amp (_queueLast &gt= _queueFirst)) {

if (_queueFirst == _queue) / / He заповнює буфер

DataToQueue(_queueEnd _queueLast 1)

else

DataToQueue(_queueEnd _queueLast)

}

if (_endOfSource &amp&amp (_queueFirst &gt (_queueLast+1))) DataToQueue(_queueFirst _queueLast 1)

}

void AbstractPlayer::DataToQueue(long samplesNeeded) {

long samplesRead

volatile AudioSample *pDest = _queueLast

/ / Засвідчуємо, що довжина

/ / Відповіді кратна числу каналів

samplesNeeded = samplesNeeded % Channels()

samplesRead = Previous()-&gtGetSamples(

const_cast&ltAudioSample*&gt(pDest),samplesNeeded)

pDest += samplesRead

if (pDest &gt= _queueEnd) pDest = _queue

_queueLast = pDest

if (samplesRead &lt samplesNeeded)

_endOfSource = true

}

Зчитуються дані з черги аналогічним чином Є тільки одне незначне зауваження Різні системні модулі управління звуком предявляють різні вимоги до розмірів відліків, які повинні подаватися їм на вхід Для простоти всі розроблені мною компоненти роботи зі звуком для зберігання вибірок використовують тип AudioSample, проте в конкретних системах може знадобитися 8-бітове або 16-бітове представлення відліків З цих міркувань нижче мною наведені дві версії методу FromQueue Розрізняються вони тільки типом використовуваного покажчика

Лістинг 5З Програма aplayercpp (продовження)

long AbstractPlayer::FromQueue(Sample16 *pDest, long destSize) {

long destRemaining = destSize

if (_queueLast &lt _queueFirst) {

int copySize = _queueEnd _queueFirst / / Кількість

/ / Доступних

/ / Відліків

if (copySize &gt destRemaining)

copySize = destRemaining DataFromQueue(pDest,copySize) destRemaining = copySize pDest += copySize

}

if ((destRemaining &gt 0) &amp&amp (_queueLast &gt _queueFirst)) {

int copySize = _queueLast _queueFirst

if (copySize &gt destRemaining)

copySize = destRemaining DataFromQueue(pDest, copySize) destRemaining = copySize pDest += copySize

}

if ((destRemaining &gt 0) &amp&amp _endOfSource)

_endOfQueue = true

return (destSize destRemaining)

}

long AbstractPlayer::FromQueue(Sample8 *pDest, long destSize) {

long destRemaining = destSize

if (_queueLast &lt _queueFirst) {

int copySize = _queueEnd _queueFirst / / Кількість

/ / Доступних відліків

if (copySize &gt destRemaining)

copySize = destRemaining DataFromQueue(pDest,copySize) destRemaining = copySize pDest += copySize

}

if ((destRemaining &gt 0) &amp&amp (_queueLast &gt _queueFirst)) {

int copySize = _queueLast _queueFirst

if (copySize &gt destRemaining)

copySize = destRemaining DataFromQueue(pDest, copySize) destRemaining = copySize pDest += copySize

}

if ((destRemaining &gt 0) &amp&amp _endOfSource)

_endOfQueue = true

return (destSize destRemaining)

}

Метод DataFromQueue просто копіює суцільний блок даних з черги

Цей метод двічі викликається з методу FromQueue

Лістинг 53 Програма aplayercpp (продовження)

/* private: */

void AbstractPlayer::DataFromQueue(Sample16 *pDest, long copySize) {

volatile AudioSample *newQueueFirst = _queueFirst

for(int i=0i&ltcopySizei++)

*pDest++ = *newQueueFirst++

&gt&gt ((sizeof(*newQueueFirst) sizeof(*pDest)) * 8 )

if (newQueueFirst &gt= _queueEnd)

newQueueFirst = _queue

_queueFirst = newQueueFirst

}

/* private: */

void AbstractPlayer::DataFromQueue(Sample8 *pDest, long copySize)

{

volatile AudioSample *newQueueFirst = _queueFirst

for(int i=0i&ltcopySizei++)

*pDest++ = *newQueueFirst++

&gt&gt ((sizeof(*newQueueFirst) sizeof(*pDest)) * 8 )

if (newQueueFirst &gt= _queueEnd)

newQueueFirst = _queue

_queueFirst = newQueueFirst

}

Джерело: Кінтцель Т Керівництво програміста по роботі зі звуком = A Programmers Guide to Sound: Пер з англ М: ДМК Пресс, 2000 432 с, іл (Серія «Для програмістів»)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*