На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела "Программирование звука"
0) Данный раздел предназначен для обсуждения проблем, возникающих при программировании задач, связанных с записью, обработкой, воспроизведением звука. Перед созданием темы подумайте, не будет ли она уместнее в разделах Разработка и тестирование программ, Наши исходники, а особенно Разовые заказы и подработки
1) На Раздел распространяются все Правила форума.Огромная просьба с ними внимательно ознакомиться.
2) Запрещается давать бессмысленные ответы вроде: "Снеси Мастдай", "ХП рулит", "Поставь Линукс" и т.д.
3) Запрещается создавать темы, в которых Вы намереваетесь получить ссылку на кряки, серийники и т.п. Также запрещено любое обсуждение p2p (peer-to-peer) сетей (BitTorrent, eDonkey и т.д.).
4) Реклама всякого рода пресекается беспощадно.
5) Используйте тэг [CODE] для выделения кода программы (непременно с указанием языка программирования - выбрать из списка. В противном случае бессмысленно!). Уважайте тех, кто будет читать ваш код!
6) Если решение вашей проблемы найдено, то не забываем помечать тему специальной функцией "Вопрос решён". Вам всего лишь требуется при написании последнего ответа поставить одну единственную галочку прямо над формой ответа.
7) Если вы хотите получить совет для конкретной платформы/языка программирования, обязательно укажите их в вопросе

8) Если не прикрепляются/не скачиваются файлы, читаем Не прикрепляется / не скачивается файл. Любые обсуждения в данном разделе проблем с приложением файлов считаются оффтопиком! Со всеми вытекающими.

9) NEW! Уважаемые новички! Мы приветствуем Ваше желание научить всех посетителей раздела правильному программированию. Но огромная просьба, перед тем, как писать поучения в старых (последний ответ - "старее" месяца, а особенно, если вопрошавший не появляется на форуме уже не первый месяц, в чем можно убедиться в его профиле) темах, хорошо подумать, будет ли кому-нибудь, кроме Вас cамих, это интересно. Попытки накрутки количества тематических сообщений за счёт поднятия древних неактуальных тем ("некрофилия") будут наказываться по велению левой пятки модераторского состава (см. пп.12, 13 Правил)



Нарушение Правил может повлечь наказание со стороны модераторов.



user posted imageFAQ Раздела user posted imageПоиск в Разделе user posted imageMSDN Library Online | Ваше мнение о модераторах: user posted imageBarazuk user posted imageRikkie
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Работа с BassAsio
    Начал изучение работы с ASIO. Взял простой пример с сайта разработчика BassAsio, немного изменил (проект прикрепил). Программа работает даже на простом ноутбуке после установки ASIO4ALL, показывает наличие микрофона и динамиков. Однако, хотя в проекте установлена Многопоточная (/MT) библиотека времени выполнения, программа работает только тогда, когда рядом (или в указанной в path директории) находится bassasio.dll, в противном случае возникают ошибки. Подскажите, пожалуйста, можно ли сделать так, чтобы dll не требовалась.
    Прикреплённый файлПрикреплённый файлBassAsio.zip (19,81 Кбайт, скачиваний: 245)
      Решил попробовать поработать с BassAsio на своей Дельте 66. За основу взял прикрепленный проект BassAsio. Информацию о входах Дельты 66 получил следующую:
      M-Audio ASIO 5078
      Количество входов: 8
      Размеры буферов (min, max, default) (количество отсчетов): 64 4096 256
      Устройство инициализировано

      --------------------- Входные устройства ASIO ----------------------

      0 Analog In 1 Delta-66
      1 Analog In 2 Delta-66
      2 Analog In 3 Delta-66
      3 Analog In 4 Delta-66
      4 SPDIF In L Delta-66
      5 SPDIF In R Delta-66
      6 Monitor L Delta-66
      7 Monitor R Delta-66

      Попробовал записать звук пока только для одного канала (канал 0), используя пример из bassasio13.zip:
      ExpandedWrap disabled
        #include <windows.h>
        #include <conio.h>
        #include <string>
        #include <vector>
        #include <iostream>
        #include "bassasio.h"
         
        #pragma comment(lib, "bassasio.lib")
         
        #define BUFSTEP 200000  // memory allocation unit
        int input=0;            // current input source
        char *recbuf=NULL;      // recording buffer
        DWORD reclen;           // recording length
        BOOL recording=FALSE;
        float level=0;
        int nKan;
        std::vector<FILE*> pf;
         
        void ErrorMes(std::string mes, int Res);
        void GetAsioInfoCyr(void);
        void RecordAsio();
         
         
        int main(int argc, char* argv[])
        {
          setlocale(LC_ALL, "");
          GetAsioInfoCyr();
          std::vector<std::string> vFileName;
          vFileName.push_back("file1");
          nKan = 1;
          for(int j = 0; j < nKan; j++)
          {
            pf.push_back(fopen((char*) (vFileName[j] + ".pcm").c_str(), "wb"));
          }
          RecordAsio();
          for(int j = 0; j < nKan; j++)
          {
            fclose(pf[j]);
          }
          system("pause");
        }
         
        void ErrorMes(std::string sMes, int Res)
        {
          std::cout << sMes << Res << std::endl;
          system("pause");
          exit(EXIT_SUCCESS);   // EXIT_SUCCESS, EXIT_FAILURE
        }
         
        void GetAsioInfoCyr(void)
        {
          int i;
          if (!BASS_ASIO_Init(0, BASS_ASIO_THREAD))
          {
            ErrorMes("Не удалось инициализировать устройство. Ошибка: ", BASS_ASIO_ErrorGetCode());
          }
          BASS_ASIO_INFO di;
          BASS_ASIO_GetInfo(&di);
          std::cout << di.name << "\t" << di.version << std::endl;
          std::cout << "Количество входов: " << di.inputs << std::endl;
          std::cout << "Размеры буферов (min, max, default) (количество отсчетов): " << di.bufmin << "\t" <<  di.bufmax
                  << "\t" << di.bufpref << std::endl;
          if(di.initflags == 1)
            std::cout << "Устройство инициализировано" << std::endl;
          else
            std::cout << "Устройство неинициализировано" << std::endl;
            BASS_ASIO_CHANNELINFO chi;
          std::cout << "\n--------------------- Входные устройства ASIO ----------------------\n" << std::endl;
            for (i = 0; BASS_ASIO_ChannelGetInfo(TRUE, i, &chi); i++)
          {
            std::cout << i << "\t" << chi.name << std::endl;
          }
          std::cout << std::endl;      
          BASS_ASIO_Free();
        }
         
        DWORD CALLBACK AsioProc(BOOL isinput, DWORD channel, void *buffer, DWORD length, void *user)
        {
            if (!recbuf) return 0;
            // increase buffer size if needed
            if ((reclen%BUFSTEP)+length>=BUFSTEP) {
                recbuf= (char*) realloc(recbuf,((reclen+length)/BUFSTEP+1)*BUFSTEP);
                if (!recbuf) {
                    ErrorMes("Не удалось выделить буфер", 1);
                    return 0;
                }
            }
            // buffer the data
            memcpy(recbuf+reclen,buffer,length);
            reclen+=length;
          while(recording == TRUE)
            fwrite(buffer, length, 1, pf[0]);
            return 0;
        }
         
         
        void RecordAsio()
        {
          if (!BASS_ASIO_Init(0, BASS_ASIO_THREAD))
          {
            ErrorMes("Не удалось инициализировать устройство. Ошибка: ", BASS_ASIO_ErrorGetCode());
          }
          WAVEFORMATEX wvFormat;
          wvFormat.wFormatTag      = WAVE_FORMAT_PCM;
          wvFormat.nChannels       = 1;
          wvFormat.nSamplesPerSec  = 44100;
          wvFormat.wBitsPerSample  = 16;
          wvFormat.nBlockAlign     = (wvFormat.nChannels*wvFormat.wBitsPerSample + 7)/8;
          wvFormat.nAvgBytesPerSec = wvFormat.nSamplesPerSec*wvFormat.nBlockAlign;
          wvFormat.cbSize          = sizeof(wvFormat);
            if (recbuf)
          { // free old recording
                BASS_ASIO_Stop(); // stop ASIO device in case it was playing
                BASS_ASIO_ChannelReset(FALSE,-1,BASS_ASIO_RESET_ENABLE); // disable outputs in preparation for recording
                free(recbuf);
                recbuf=NULL;
            }
            // allocate initial buffer and make space for WAVE header
            recbuf=(char*)malloc(BUFSTEP);
            reclen=44;
            BASS_ASIO_ChannelReset(TRUE,-1,BASS_ASIO_RESET_ENABLE); // disable all inputs, then...
            BASS_ASIO_ChannelEnable(TRUE, 0, AsioProc,0); // enable the selected
          BASS_ASIO_ChannelSetFormat(TRUE, 0, BASS_ASIO_FORMAT_16BIT); // want 16-bit data
          if (!BASS_ASIO_Start(0,0))
          {
              ErrorMes("Can't start recording", BASS_ASIO_ErrorGetCode());
              free(recbuf);
              recbuf=0;
              return;
          }
            recording=TRUE;
          _getch();
            recording=FALSE;
          BASS_ASIO_Free();
        }
      Звук с микрофона, подключенного к первому входному каналу, не записывается. Исправить программу сам не сумею, поскольку не понимаю:
      - как работает в Asio колбек функция;
      - чем отличаются друг от друга buffer и recbuf, length от length и др.;
      - как правильно добавлять свободные буферы для записи;
      - как колбек функция информирует о заполнении буфера;
      - как правильно прекратить запись;
      - как правильно освобождать буферы после окончанию записи.
      Помогите, пожалуйста, разобраться. Проект прикрепил.
      Сообщение отредактировано: tuchin -
        Забыл прикрепить файл
        Прикреплённый файлПрикреплённый файлBassAsio.zip (21,05 Кбайт, скачиваний: 233)
          Цитата
          как работает в Asio колбек функция

          Как и любая колбек функция. Адрес функции в качестве параметра передаётся в ASIO_ChannelEnable, а потом эта функция вызывается откуда-то из недр bassasio или ещё откуда-то.
          Цитата
          как правильно добавлять свободные буферы для записи

          Механизм выделения/освобождения памяти спрятан внутри bassasio, ничего добавлять не нужно, можно указать желательный размер буфера при инициализации(или использовать размер по умолчанию).
          Цитата
          как колбек функция информирует о заполнении буфера

          Сам по себе вызов функции - это и есть механизм уведомления приложения о том, что в канале записи есть данные для обработки. Адрес и размер данных передаются в качестве параметров.
          Цитата
          Звук с микрофона, подключенного к первому входному каналу, не записывается

          Активировать 1-й канал через ASIO_ChannelEnable и записывать данные канала в файл, в колбек. Только в другой файл, не в тот, куда сливаются данные 0-го канала. Будут 2 моно файла. Если необходим стерео файл, каналы объединяются посредством BASS_ASIO_ChannelJoin, тогда семплы каналов будут чередоваться в буфере.
          Цитата
          как правильно прекратить запись;

          BASS_ASIO_Stop
          BASS_ASIO_ChannelEnable
          BASS_ASIO_ChannelReset
          BASS_ASIO_ChannelPause
          BASS_ASIO_Free
          Смотря что подразумевается под "прекратить".

          Читайте справку.
          Сообщение отредактировано: Prince -
            Спасибо большое за ответы! Возникли ещё вопросы:
            - как задать размер буфера (length) в колбэк функции?
            - можно ли в азио изменять усиление по входу? Интересует максимальное усиление.
              bassasio.dll - это библиотека-обёртка над API ASIO, спрятанными в других dll, которые устанавливаются с драйвером устройства(являются его частью). Так же как библиотека bass.dll - это обёртка над API DirectSound(+ кучка дополнительных плюшек).
              Bass, bassasio упрощают работу с низкоуровневыми интерфейсами. Множество действий, выполняемых програмистом при работе с низкоуровневыми функциями, они берут на себя.
              В частности, вам не нужно выделять/освобождать память под буферы для записи. Все операции с буферами скрыты внутри bassasio.
              Размер буфера(в семплах) задаётся при старте устройства в BASS_ASIO_Start. От размера буфера, и количества задействованых каналов, будет зависеть частота вызова колбэк, соотвественно и нагрузка на проц(систему).
              Цитата
              как задать размер буфера (length) в колбэк функции

              И ещё раз. length не нужно задавать.
              Вы пишете колбэк функцию предопределенного формата и передаете адрес этой функции куда-то "вовнутрь" bassasio при вызове BASS_ASIO_ChannelEnable. Затем, после того, как устройство стартует, кто-то, откуда-то(это неважно), периодически вызывает написанный вами колбэк-код(функцию) и передаёт туда адрес и размер доступных для обработки данных(buffer, length). Ваш код эти данные обрабатывает(ну, вы что-то делаете с этими данными). Или ничего не делаете - дело ваше. Всё. Ничего задавать не нужно. Только обработать этот блок данных(записать в файл, например).
              Цитата
              можно ли в азио изменять усиление по входу?

              Нет. С этим не к ASIO.
              Хотя библиотека bassasio позволяет изменять уровень сигнала в канале при помощи функции BASS_ASIO_ChannelSetVolume. Но, функция не имеет отношения к настройкам железа. Она изменяет значения семплов, т.е., производит манипуляцию над данными, поступающими от устройства(при записи) или к устройству(при воспроизведении).

              В MME есть функции для управления аппаратным микшером устройства. Функции группы MixerXXX.
              Сообщение отредактировано: Prince -
                Спасибо за подробные объяснения.
                При определении параметров устройства я получил несколько значений буфера:
                Размеры буферов (min, max, default) (количество отсчетов): 64 4096 256
                В связи с этим я подумал, что можно задавать значение буфера.
                Хотел бы уточнить следующее:
                1. ASIO в принципе не позволяет управлять входным аппаратным усилением (в отличие от MME) или это не умеет делать bassasio (в обертке это не предусмотрено)?
                2. Если я в результате экспериментов вижу, что заданное по умолчанию значение буфера не подходит (сейчас у меня 512), как же я могу снизить нагрузку на процессор, частоту вызова колбэк функции и др.
                  Проверил возможность изменения размера буфера в Start. Все работает. Вопрос 2 снимаю как глупый. Тем более, что Вы уже это объяснили.
                    Цитата
                    ASIO в принципе не позволяет управлять входным аппаратным усилением

                    По моим сведениям - нет.
                    ASIO Interface Specification v 2.0
                    Сообщение отредактировано: Prince -
                      Спасибо за ответы!
                        Попробовал определить программно некоторые допустимые параметры Delta 66:
                        ExpandedWrap disabled
                          #include <string>
                          #include <iostream>
                          #include "bassasio.h"
                           
                          #pragma comment(lib, "bassasio.lib")
                           
                          using namespace std;
                           
                          void GetAsioInfo(void);
                          void ErrorMes(string sMes, int Res);
                           
                          int main(int argc, char* argv[])
                          {
                            setlocale(LC_ALL, "");
                            GetAsioInfo();
                            system("pause");
                            return(EXIT_SUCCESS);
                          }
                           
                          void ErrorMes(string sMes, int Res)
                          {
                            cout << sMes << Res << endl;
                            system("pause");
                            exit(EXIT_SUCCESS);  
                          }
                           
                          void GetAsioInfo(void)
                          {
                            if (!BASS_ASIO_Init(0, BASS_ASIO_THREAD))
                            ErrorMes("Не удалось инициализировать устройство. Ошибка: ", BASS_ASIO_ErrorGetCode());
                            int nSamplesPerSec[] = {44100, 48000, 64000, 88200, 96000, 192000, 1600000};  
                            cout << "\n---------- Определение поддерживаемой дискретизации ------------\n" << endl;
                            for(int i = 0; i < sizeof(nSamplesPerSec)/sizeof(int); i++)
                            {
                              if(BASS_ASIO_ChannelSetRate(TRUE, 0, (double) nSamplesPerSec[i]) == FALSE)
                              {
                                cout << "\n!!! Ошибка при установке дискретизации " << nSamplesPerSec[i] << endl << endl;
                                break;
                              }
                              cout << "Установлена дискретизация " << BASS_ASIO_ChannelGetRate(TRUE, 0) << endl;
                            }
                            cout << "\n---------- Определение поддерживаемой разрядности ------------\n" << endl;
                            int nBitsPerSample[] = {BASS_ASIO_FORMAT_16BIT, BASS_ASIO_FORMAT_24BIT, BASS_ASIO_FORMAT_32BIT,
                                                    BASS_ASIO_FORMAT_FLOAT, BASS_ASIO_FORMAT_DSD_LSB, BASS_ASIO_FORMAT_DSD_MSB};
                            for(int i = 0; i < sizeof(nBitsPerSample)/sizeof(int); i++)
                            {
                              if(BASS_ASIO_ChannelSetFormat(TRUE, 0, nBitsPerSample[i]) == FALSE)
                              {
                                cout << "\n !!! Ошибка при установке разрядности: элемент массива nBitsPerSample номер " << i << endl << endl;
                                break;
                              }
                              cout << "Установлена дискретизация " << BASS_ASIO_ChannelGetFormat(TRUE, 0) << endl;
                            }
                            cout << "\n---------- Определение поддерживаемого усиления -------------\n" << endl;
                            float volume = 1.0e32;
                            if(BASS_ASIO_ChannelSetVolume(TRUE, 0, volume) == FALSE)
                              cout << "\n !!! Ошибка при установке усиления: " << volume << endl << endl;
                            cout << "Установлено усиления: " << BASS_ASIO_ChannelGetVolume(TRUE, 0) << endl << endl;
                            cout << "\n---------- Определение размера буфера -------------\n" << endl;
                            int nBuf = 8192;
                            if(BASS_ASIO_Start(nBuf, 0) == FALSE)
                              cout << "\n !!! Ошибка при установке размера буфера: " << nBuf << endl << endl;
                            BASS_ASIO_INFO di;
                            BASS_ASIO_GetInfo(&di);
                            cout << "Установлен размер буфера: " << di.bufpref << endl << endl;
                            BASS_ASIO_Free();
                          }
                        В результате получил следующее:
                        ---------- Определение поддерживаемой дискретизации ------------

                        Установлена дискретизация 44100
                        Установлена дискретизация 48000
                        Установлена дискретизация 64000
                        Установлена дискретизация 88200
                        Установлена дискретизация 96000
                        Установлена дискретизация 192000
                        Установлена дискретизация 1.6e+006

                        ---------- Определение поддерживаемой разрядности ------------

                        Установлена дискретизация 16
                        Установлена дискретизация 17
                        Установлена дискретизация 18
                        Установлена дискретизация 19

                        !!! Ошибка при установке разрядности: элемент массива nBitsPerSample номер 4


                        ---------- Определение поддерживаемого усиления -------------

                        Установлено усиления: 1e+032


                        ---------- Определение размера буфера -------------


                        !!! Ошибка при установке размера буфера: 8192

                        Установлен размер буфера: 4096

                        Получается:
                        - BASS_ASIO_ChannelSetRate ошибки не дает (в отличие от BASS_ASIO_ChannelSetFormat и установки размера буфера) и дискретизацию можно задавать любую;
                        - BASS_ASIO_ChannelSetVolume ошибки не дает даже при очень большом значении усиления.

                        В отношении усиления: я попробовал записать сигнал с первого входа при усилении 100. В файл записывается действительно усиленный сигнал. Вы объяснили, что это программное усиление, а не аппаратное. Но какое-то ограничение на усиление ведь должно же быть?

                        В отношении частоты дискретизации вообще непонятно, почему нет срабатывания функции ее установки при безумном значении частоты.

                        Почему такое происходит?
                          Для проверки поддерживаемых частот дискретизации устройства есть функция BASS_ASIO_CheckRate.
                          Для установки частоты дискретизации устройства есть функция BASS_ASIO_SetRate.
                          Ну и загляните в настройки драйвера, какая частота установлена(если установлена) там.
                          Если устройство не поддерживает желаемую частоту, но вы очень хотите именно такую, тогда вы устанавливаете корректную нативную частоту в BASS_ASIO_SetRate и используете BASS_ASIO_ChannelSetRate для установки желаемой(для конкретного канала). При таком раскладе, bassasio будет выполнять передискретизацию данных из нативной частоты устройства в установленную для этого канала, "на лету". Такая фишка может быть полезна, но сведёт на нет одно из преимуществ ASIO, а именно возможность получать данные от устройства "как есть", без промежуточных преобразований(как в системном микшере виндовс). И, возможность отдавать устройству данные в его родном формате, также без промежуточных преобразований. За что ASIO "уважают" аудиофилы. Передискретизация также дополнительно нагружает систему.

                          Для проверки нативных форматов(формата) семпла - BASS_ASIO_ChannelGetInfo. Аналогично, если желаемый формат отличается от нативного, и вы его устанавливаете в BASS_ASIO_ChannelSetFormat, bassasio выполняет преобразование формата и отдаёт вам уже не совсем то, что прилетает от устройства.

                          Всё есть в справке.

                          Эта инфа ни к чему не обязывает, думайте сами, решайте сами. Правильный выбор частоты/формата - субъективен. Если вам не важна "точность передачи", а только "многоканальность" ASIO, можно устанавливать любые удобные частоту дискретизации и формат семпла(естественно, поддерживаемые bassasio).

                          Цитата
                          Но какое-то ограничение на усиление ведь должно же быть

                          Ну, конечно. Допустим, формат 16 бит, а значение семпла 1000. Умножив его на 100, получите 100000, т.е., переполнение 16 битного числа, и как результат - искажение звука. Кроме того, при таком програмном "усилении", вы усиливаете шум аудиотракта, вместе с полезным сигналом.
                          Сообщение отредактировано: Prince -
                            Спасибо большое, все понял. Попробую BASS_ASIO_CheckRate и BASS_ASIO_SetRate, надеюсь, они дадут правильные результаты.
                              На всякий пожарный, BASS_ASIO_GetRate возвращает текущую частоту дискретизации, заданную в настройках драйвера вручную, или через BASS_ASIO_SetRate.
                                Спасибо за дополнения
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0444 ]   [ 21 queries used ]   [ Generated: 19.03.24, 02:07 GMT ]