Russian Qt Forum
Сентябрь 22, 2024, 01:48 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Преобразование типов для QAudioOutput  (Прочитано 5391 раз)
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 байт. Как мне провернуть такой фокус с чтением и записью?

Надеюсь понятно объяснил суть проблемы. Если что - спрашивайте.
Заранее спасибо
Записан
Странник
Гость
« Ответ #1 : Октябрь 28, 2011, 18:19 »

то есть вы спрашиваете, как 32-битный звук преобразовать в 16-битный или 8-битный? лишние младшие биты отбрасываются (в беззнаковом целочисленном представлении).
« Последнее редактирование: Октябрь 28, 2011, 18:22 от Странник » Записан
Impuls
Гость
« Ответ #2 : Октябрь 28, 2011, 19:19 »

то есть вы спрашиваете, как 32-битный звук преобразовать в 16-битный или 8-битный? лишние младшие биты отбрасываются (в беззнаковом целочисленном представлении).
Ну с целочисленным более или менее все ясно. Разбить его на n-восьмибитных фрагментов особого труда не составит. А как с вещественным? Там биты размазаны по всему числу (значение, мнтиса, степень). Тут так просто число уже не преобразуешь. Вот я и хотел узнать как это делает qt в своем классе QAudioInput.
Т.е. в QByteArray идет 2 последовательных байта. Мы их прочитали, и сказали что это float. А вместо этого читаются 4 байта и они интерпретируются как float.
Записан
Странник
Гость
« Ответ #3 : Октябрь 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) для правильной интерпретации.
« Последнее редактирование: Октябрь 28, 2011, 21:10 от Странник » Записан
Impuls
Гость
« Ответ #4 : Октябрь 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), потому что биты для кодирования вещественного числа размазаны по всему числу, а не идут по порядку.
Уфффф... Надеюсь понятно объяснил.
« Последнее редактирование: Октябрь 28, 2011, 22:49 от Impuls » Записан
Странник
Гость
« Ответ #5 : Октябрь 29, 2011, 11:56 »

числа с плавающей точкой половинной точности не поддерживаются.
варианты:
1. использовать другой входной формат
2. реализовывать побитово самому
3. искать готовую реализацию

проблема с вариантами 2 или 3?
Записан
Impuls
Гость
« Ответ #6 : Октябрь 29, 2011, 13:02 »

числа с плавающей точкой половинной точности не поддерживаются.
варианты:
1. использовать другой входной формат
2. реализовывать побитово самому
3. искать готовую реализацию

проблема с вариантами 2 или 3?
Но qt в своих недрах как-то это делает? QAudioInput как-то же пишет данные. А QAudioOutput их как-то интерпретирует. Причем интерпретируется все правильно. Вот и интересует меня вопрос: Как?
Записан
Странник
Гость
« Ответ #7 : Октябрь 29, 2011, 13:36 »

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Октябрь 29, 2011, 14:59 »

..что мне нужно float 32b преобразовать к float 16b (прости господи за ересь).

[/offtop]Это не ересь, 2-х байтовый формат float изобретен давно (причем ILM, компанией с глубокими карманами) и используется достаточно широко и успешно
Записан
Impuls
Гость
« Ответ #9 : Октябрь 31, 2011, 19:14 »

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

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


Страница сгенерирована за 0.051 секунд. Запросов: 23.