Russian Qt Forum

Qt => Мультимедиа => Тема начата: Impuls от Октябрь 28, 2011, 15:35



Название: Преобразование типов для QAudioOutput
Отправлено: Impuls от Октябрь 28, 2011, 15:35
Доброго времени суток уважаемые эксперты.
Возник такой вопрос:
Немного упрощу задачу:
1. Читаю данные с микрофона QAudioInput
2. На выходе получаю QByteArray
3. Преобразую QByteArray в массив отсчетов (В зависимости от настроек: UnsignedInt, SignedInt, Float).
4. Производим манипуляции с данными
5. Преобразовать данные обратно в QByteArray и передать на QAudioOutput
И тут начинаются касяки:
1. Если размер отсчета 32 бита - все круто. Просто читаем и пишем данные из/в QByteArray.
2. Если размер отсчета меньше 32 бит, возникает вопрос по обрезанию типов данных до нужного размера (16 8 бит).
Допустим данные во float. sizeof(float) = 4, а размер отсчета всего 2, а то и 1 байт. Как мне провернуть такой фокус с чтением и записью?

Надеюсь понятно объяснил суть проблемы. Если что - спрашивайте.
Заранее спасибо


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Странник от Октябрь 28, 2011, 18:19
то есть вы спрашиваете, как 32-битный звук преобразовать в 16-битный или 8-битный? лишние младшие биты отбрасываются (в беззнаковом целочисленном представлении).


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Impuls от Октябрь 28, 2011, 19:19
то есть вы спрашиваете, как 32-битный звук преобразовать в 16-битный или 8-битный? лишние младшие биты отбрасываются (в беззнаковом целочисленном представлении).
Ну с целочисленным более или менее все ясно. Разбить его на n-восьмибитных фрагментов особого труда не составит. А как с вещественным? Там биты размазаны по всему числу (значение, мнтиса, степень). Тут так просто число уже не преобразуешь. Вот я и хотел узнать как это делает qt в своем классе QAudioInput.
Т.е. в QByteArray идет 2 последовательных байта. Мы их прочитали, и сказали что это float. А вместо этого читаются 4 байта и они интерпретируются как float.


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Странник от Октябрь 28, 2011, 21:03
ну зачем же так буквально все воспринимать. отбрасывание младших разрядов суть есть целочисленное деление, дописывание в младшие разряды нулей - умножение.
амплитуда сигнала может принимать следующие значения в зависимости от типа сэмпла (могу быть не точен, давно в этой кухне не варился):
unsigned 8 bit: 0 - 255
signed 8 bit: -128 - 127
unsigned 16 bit: 0 - 65535
signed 16 bit: -32768 - 32767
float: -1 - 1 (в случае, если значение нормализовано)
ваша задача - просто провести масштабное преобразование. то есть - домножить/разделить на нужное число разрядов и при необходимости преобразовать знаковое в беззнаковое и наоборот.

например, чтобы преобразовать из float в unsigned 16 необходимо:
1. домножить значение float на 32767 с округлением до целого (чтобы получить значение в диапазоне от -32767 до 32767)
2. прибавить к результату 32767 (чтобы получить беззнаковое 0 - 65534)

p.s.
забыл добавить, необходимо учитывать так же порядок следования бит (big-endian или little-endian) для правильной интерпретации.


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Impuls от Октябрь 28, 2011, 22:44
...например, чтобы преобразовать из float в unsigned 16 необходимо:
1. домножить значение float на 32767 с округлением до целого (чтобы получить значение в диапазоне от -32767 до 32767)
2. прибавить к результату 32767 (чтобы получить беззнаковое 0 - 65534)

p.s.
забыл добавить, необходимо учитывать так же порядок следования бит (big-endian или little-endian) для правильной интерпретации.
Нет. Ну так это то понятно, вопрос в том, что мне нужно float 32b преобразовать к float 16b (прости господи за ересь). Т.е. имеется ввиду что для воспроизведения QAudioOutput требует 2 байтный float, а не 2-байтный int. Как же объяснить-то?
Значит так:
Код:
QAudioFormat f;
    f.setFrequency(8000);
    f.setChannels(1);
    f.setSampleType(QAudioFormat::Float);
    f.setSampleSize(16);
    f.setByteOrder(QAudioFormat::LittleEndian);
    f.setCodec("audio/pcm");
    QByteArray arr;
    QBuffer b(&arr);
    b.open(QIODevice::WriteOnly);
QAudioDeviceInfo devInfo = QAudioDeviceInfo::defaultInputDevice();
....
    audio = new QAudioInput(*devInfo, *f, this);
    audio.start(&b);
...
    audio.stop();
В результате в arr будут лежать данные, прочитанные с микрофона. Параметры данных:
1. Данные кодируются 16 битами на отсчет
2. Контейнером для 16 бит является float

Далее мне нужно прочитать данные из arr в массив отсчетов (дабы эти отсчеты потом менять - фильтовать и т.д.)
Так вот. Так прочитать не получится:
Код:
QBuffer b(&arr);
QDataStream str(&b);
b.open(QIODevice::ReadOnly);
float f;
str>>f;
ибо автоматически из arr будет прочтено 4 байта, вместо необходимых мне 2-х
Такая же дурная ситуация получается и при обратной операции, когда мне нужно в arr записать 2 байта, но записывается 4.
Ну и естественно что тоже самое будет актуально и для 8 бит на отсчет. Без всяких проблем данные будут прочитаны только при 32 битах на отсчет.
И естественно нельзы сделать read(&f,2), потому что биты для кодирования вещественного числа размазаны по всему числу, а не идут по порядку.
Уфффф... Надеюсь понятно объяснил.


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Странник от Октябрь 29, 2011, 11:56
числа с плавающей точкой половинной точности не поддерживаются.
варианты:
1. использовать другой входной формат
2. реализовывать побитово самому
3. искать готовую реализацию

проблема с вариантами 2 или 3?


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Impuls от Октябрь 29, 2011, 13:02
числа с плавающей точкой половинной точности не поддерживаются.
варианты:
1. использовать другой входной формат
2. реализовывать побитово самому
3. искать готовую реализацию

проблема с вариантами 2 или 3?
Но qt в своих недрах как-то это делает? QAudioInput как-то же пишет данные. А QAudioOutput их как-то интерпретирует. Причем интерпретируется все правильно. Вот и интересует меня вопрос: Как?


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Странник от Октябрь 29, 2011, 13:36
Но qt в своих недрах как-то это делает? QAudioInput как-то же пишет данные. А QAudioOutput их как-то интерпретирует. Причем интерпретируется все правильно. Вот и интересует меня вопрос: Как?
есть у меня серьезные сомнения, что занимается этим Qt, а не аудиосистема. но если у вас иное мнение - посмотрите исходники, дурное дело нехитрое.

на вопрос "как?" ответ прост - побитово, встроенного типа данных чисел с плавающей запятой половинной точности С++ не имеет. 1 бит знак, 5 бит экспонента, 10 бит мантисса - можете реализовать сами.


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Igors от Октябрь 29, 2011, 14:59
..что мне нужно float 32b преобразовать к float 16b (прости господи за ересь).

[/offtop]Это не ересь, 2-х байтовый формат float изобретен давно (причем ILM, компанией с глубокими карманами) и используется достаточно широко и успешно


Название: Re: Преобразование типов для QAudioOutput
Отправлено: Impuls от Октябрь 31, 2011, 19:14
Но qt в своих недрах как-то это делает? QAudioInput как-то же пишет данные. А QAudioOutput их как-то интерпретирует. Причем интерпретируется все правильно. Вот и интересует меня вопрос: Как?
есть у меня серьезные сомнения, что занимается этим Qt, а не аудиосистема. но если у вас иное мнение - посмотрите исходники, дурное дело нехитрое.

на вопрос "как?" ответ прост - побитово, встроенного типа данных чисел с плавающей запятой половинной точности С++ не имеет. 1 бит знак, 5 бит экспонента, 10 бит мантисса - можете реализовать сами.
Ну спасибо. Буду пробовать что-нибудь делать. Спасибо.