Как вручную преобразовать 8,24-битный лишенный чередования lpcm в 16-битный lpcm? - PullRequest
6 голосов
/ 16 марта 2011

У меня есть блок данных (void *), который составляет 2 канала, 44100 Гц, 8,24-битное целое число со знаком с прямым порядком байтов 'lpcm', с чередованием.Мне нужно записать этот кусок в файл как 2-канальное, 44100 Гц, 16-разрядное целое число с прямым порядком байтов 'lpcm'.

Как преобразовать данные?Я могу представить, что мне нужно сделать что-то вроде этого:

uint dataByteSize = sizeof(UInt32) * samplesCount;
UInt32* source = ...;
UInt32* dest = (UInt32*)malloc(dataByteSize);
for (int i = 0; i < samplesCount; ++i) {
    UInt32 sourceSample = source[i];
    UInt32 destSample = sourceSample>>24;
    dest[i] = destSample;
}

Но как мне преобразовать деинтерлейс в чередование?

Ответы [ 4 ]

11 голосов
/ 22 марта 2011

Хорошо, я потратил некоторое время на изучение проблемы и понял, что вопрос содержит слишком мало информации, чтобы ответить =) Так вот, сделка:

Во-первых, о не чередующемся: я изначально думал, что этовыглядело бы так: l1 l2 l3 l4 ... ln r1 r2 r3 r4 ... rn Но оказалось, что в моих данных правый канал просто отсутствовал.Оказалось, что это были не чередующиеся данные, а просто простые моно данные.И да, это всегда должно быть несколько буферов на случай, если данные фактически не чередуются.Если это чередование, это должно быть l1 r1 l2 r2 l3 r3 l4 r4 ...

Во-вторых, о фактическом преобразовании: все зависит от диапазона выборок.В моем случае (и в любом случае, когда задействовано ядро, если я прав), значения с фиксированной точкой 8,24 должны находиться в диапазоне (-1, 1), тогда как 16-битные значения со знаком должны находиться в диапазоне (-32768, 32767).Таким образом, значение 8.24 всегда будет иметь свои первые 8 битов равными 0 (если оно положительное) или 1 (если оно отрицательное).Эти первые 8 бит должны быть удалены (с сохранением знака c).Также вы можете удалить столько конечных битов, сколько захотите - это просто уменьшит качество звука, но не испортит звук.В случае преобразования в 16-битный формат со знаком биты 8-22 (15 битов) будут фактически содержать данные, которые мы должны использовать для SInt16.Бит 7 может использоваться как знаковый бит.Таким образом, чтобы преобразовать 8.24 в SInt16, вам просто нужно сместить 9 бит вправо (9, потому что вам нужно сохранить знак) и привести к SInt16

11111111 10110110 11101110 10000011 -> 11111111 11111111 (11011011 01110111)
0000000001101111 00000000 11000001 -> 00000000 00000000 (00110111 10000000)

Вот и все.Ничего больше, чем перебирать массив и сдвигать биты вправо.Надеюсь, это спасет кого-то пару часов.

3 голосов
/ 16 марта 2012

Я прочитал следующий клип в аудиографе https://github.com/tkzic/audiograph

/* convert sample vector from fixed point 8.24 to SInt16 */
void fixedPointToSInt16( SInt32 * source, SInt16 * target, int length ) {    
    int i;

    for(i = 0;i < length; i++ ) {
        target[i] =  (SInt16) (source[i] >> 9);        
    }    
}
0 голосов
/ 03 июля 2014

Я протестировал популярный метод со сдвигом 9 битов и по какой-то причине он не работает для меня, так как я далее использую результат для кодирования в ogg. Полученный огг был очень шумным. Что сработало, так это функция, основанная на методе, который я нашел в аудиографе https://github.com/tkzic/audiograph

void ConvertInputToInt16(AudioStreamBasicDescription inFormat, void *buf, void *outputBuf, size_t capacity) {
    AudioConverterRef converter;
    OSStatus err;

    size_t bytesPerSample = sizeof(SInt16);
    AudioStreamBasicDescription outFormat = {0};
    outFormat.mFormatID = kAudioFormatLinearPCM;
    outFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    outFormat.mBitsPerChannel = 8 * bytesPerSample;
    outFormat.mFramesPerPacket = 1;
    outFormat.mChannelsPerFrame = 1;
    outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket;
    outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame;
    outFormat.mSampleRate = inFormat.mSampleRate;

    NSLog(@"description for in format: %@", descriptionForAudioFormat(inFormat));
    NSLog(@"description for out format: %@", descriptionForAudioFormat(outFormat));

    UInt32 inSize = capacity*sizeof(SInt32);
    UInt32 outSize = capacity*sizeof(SInt16);

    // this is the famed audio converter

    err = AudioConverterNew(&inFormat, &outFormat, &converter);
    if(noErr != err) {
        NSLog(@"error in audioConverterNew: %d", (int)err);
    }


    err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf);
    if(noErr != err) {
        NSLog(@"error in audioConverterConvertBuffer: %d", err);
    }

}
0 голосов
/ 27 марта 2014

Лучшее описание можно найти на http://lists.apple.com/archives/coreaudio-api/2011/Feb/msg00083.html

Итак,

8.24 числа интерпретируются как от -128.000000000000 до + 127.999999940393

Но!

В iOS / CoreAudio существует соглашение, согласно которому значения от -1,000000000000 до +0,999969482421875 считаются неотрезанными значениями, которые не превышают полный масштаб для 16-разрядных аналоговых аудиопреобразователей.*

Хорошо?

...