Запись потока с линейного входа
, Разделить поток линейного входа на 2 разных в первом только левое моно, а во втором только правое моно
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.217.50] |
|
|
ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
| Страницы: (4) 1 2 [3] 4 все ( Перейти к последнему сообщению ) |
Запись потока с линейного входа
, Разделить поток линейного входа на 2 разных в первом только левое моно, а во втором только правое моно
|
Сообщ.
#32
,
|
|
|
|
Цитата подумать над тем как при воспроизведении один (к примеру левый канал) сдублировать на правый(псевдо стерео)... Он и так будет псевдостерео, моно потоки по умолчанию в общий микс примешиваются в равных пропорциях в левый и правый каналы. Наоборот, для того, чтобы развести по "ушам" моно, понадобиться изменить баланс соотвествующего потока. Допустим, вы создаёте поток для воспроизведения(моно, он же псевдостерео): ![]() ![]() chan:=BASS_StreamCreate(44100,1,0,STREAMPROC_PUSH,nil); Для того, чтобы загнать его полностью в левый канал, надо изменить баланс(панораму) потока: ![]() ![]() BASS_ChannelSetAttribute(chan,BASS_ATTRIB_PAN,-1); // -1 - левый канал, +1 - правый канал. 0 - центр. Цитата затем если пользователь нажмет прослушать, то воспроизводится ослабленный либо усиленный сигнал выбранного канала. Я могу только примерно показать, как воспроизвести то, что вы записываете. Структуру программы - это вы сами. В StartRecording создайте поток для воспроизведения: ![]() ![]() chan:=BASS_StreamCreate(44100,1,0,STREAMPROC_PUSH,nil); BASS_ChannelSetAttribute(chan,BASS_ATTRIB_PAN,-1); // баланс полностью выкрутить на левый канал p:=allocmem(16384); // згнать в поток пустой буфер длительностью где-то 0.2 с Bass_StreamPutData(chan,P,16384); // для того, чтобы звук не рвался freemem(p); BASS_ChannelPlay(chan,false); // запустить воспроизведение В StopRecording освобождаете: ![]() ![]() BASS_ChannelStop(chan); BASS_StreamFree(chan); В RecordingCallback отправьте один из буферов, например, буфер левого канала, в поток воспроизведения: ![]() ![]() BASS_StreamPutData(chan,buffer_L,length div 2); Можете отправить буфер на воспроизведение до изменения уровня сигнала, или после, отправить буфер левого или правого канала. На ваш вкус. Также в любой момент вы можете менять панораму для выбранного потока (воспроизведения) при помощи BASS_ChannelSetAttribute. Добавлено Цитата вот этот кусок дает мне индикатор, корректно? Не могу знать. Не знаю, для каких конкретно данных bass считает этот уровень, в справке не нашёл. А так, теоретически, вы получаете пиковый уровень на каком-то отрезке времени. |
|
Сообщ.
#33
,
|
|
|
|
Цитата Вот то, что я накидал.. Нет, что-то вы не то делаете. Файлы создаёте как бы моно. Потоки - стерео(но тоже как бы моно), и зачем-то два(?). И в кэлбеке неправильно выбираете данные канала. |
|
Сообщ.
#34
,
|
|
|
|
Попробовал замутить в примере ваши пожелания.
Пока разбирался, столкнулся в очередной раз с интересной ситуацией. Она возникает, если использовать 2 девайса: с одного записывать, а выводить на другой. Поскольку устройства никак не синхронизированы, частоты их тактовых генераторов отличаются. Если частота тактового генератора(и частота дискретизации) устройства воспроизведения меньше частоты тактового генератора устройства записи, устройство воспроизедения не успевает воспроизводить всё, что ему отдаёт устройство записи, до получения очередной порции данных. Очередь воспроизведения постепенно и неуклонно растёт. Так получилось у меня. Выводил на блютуз нашники, записывал со встроенной карты ноутбука. В результате, за 1с в очереди воспроизведения набегает приблизительно 100 "неуспевших воспроизвестись" семплов. Очередь воспроизведения всё увеличивается, и задержка между тем, что записывается, и тем, что воспроизводится в данный момент, тоже. Оставил программу работать на сколько-то часов, и пока спал, получил вылет в Acces Violation. Чтобы это дело контролировать, специально вывел в строку статуса размер очереди воспроизведения каналов. Почитал справку по BASS_StreamPutData и выяснил примерно следущее: при каждом вызове BASS_StreamPutData сколько-то байт отправляется прямо в некий буфер воспроизведения канала(его размер можно регулировать, по умолчанию 500 мс), всё, что не влазит, записывается "в очередь" и учитывается внутри bass как-то отдельно. Поскольку в примере келбек канала записи срабатывает каждые примерно 10-50 мс, и в буфер каналов воспроизведения отсылаются кусочки такой же длительности, поначалу все данные влазят в буфер, и размер очереди(queue) каналов воспроизведения по нулям. Значения L/R_Queue по нулям. Спустя время буфер заполняется, и "хвосты" начинают появляться в queue. Если бы частота генератора устройства воспроизведения была больше, чем устройства записи, получилась бы другая картина: через время буфер воспроизведения опустел бы, и канал воспроизведения стал бы рвать звук. Чтобы избежать таких ситуаций, при работе с несколькими звуковыми картами придётся изобретать механизм "выравнивания" частот дискретизации, придётся либо прореживать периодически буфер воспроизведения, либо вставлять туда лишние семплы, в зависимости от разницы частот. Если записывать и воспроизводить на одном устройстве, таких проблем, в общем случае, не возникает. Прикреплённый файл Record_Playback_Test.rar (6.69 Кбайт, скачиваний: 223)
|
|
Сообщ.
#35
,
|
|
|
|
А ещё, даже связанные при помощи BASS_ChannelSetLink каналы, стартуют неодновременно. При прослушивании(Listen), если баланс каналов выставить по центру, на слух заметно "раздвоение" сигналов.
|
|
Сообщ.
#36
,
|
|
|
|
Подскажите пожалуйста, что не правильно?
var fTL:longint; fVolL:real; function RecordingCallbackL(Handle: HRECORD; buffer: Pointer; length: DWORD; user: Pointer): boolean; stdcall; var buffer_L: Pointer; psample: ^smallint; psample_L: ^smallint; i: cardinal; begin fTL := fTL + Length; buffer_L:=allocmem(length div 2); psample:=buffer; psample_L:=buffer_L; for i:=0 to length div 4-1 do Begin try psample_L^:=round(fVolL*psample^); except end; inc(psample); inc(psample_L); inc(psample); end; WaveStreamL.Write(buffer_L^, length div 2); freemem(buffer_L); Result := True; end; procedure TfrmMain.StartL; var s:string; begin if rchanL <> 0 then BASS_ChannelStop(rchanL); fVolL := cxVLeft.Position/100; with WaveHdr do begin wNumChannels := 1; wBlockAlign := 2; dwBytesPerSec := 88200; end; WaveStreamL := TFileStream.Create(b.RecLine1+getFileName('1'),fmcreate); WaveStreamL.Write(WaveHdr, SizeOf(WAVHDR)); rchanL := BASS_RecordStart(44100, 2, 0, @RecordingCallbackL,nil); end; Выбивает ошибку... Прикреплённый файл Безымянный.jpg (38.54 Кбайт, скачиваний: 622)
|
|
Сообщ.
#37
,
|
|
|
|
Цитата Выбивает ошибку... В каком месте? По-человески было бы балансировку громкости и собственно громкость каналов регулировать при помощи функций микшера. Я сделал так как вы просили, т.е., чтобы можно было регулировать уровень звука в потоке, потому что вы спрашивали, как это сделать, и потому что bass, похоже, ничего не знает о выходных линиях микшера(а может, я просто не разобрался). Но в принципе, не проблема добавить управление балансом и уровнем записи, если сам микшер имеет контролы для таких манипуляций. Потому что если поток изначально записан перегруженым, уменьшай-не уменьшай уровень звука в нём, звук всё равно искаженным будет. Код в тег не забывайте оборачивать. Нет, Bass всё-таки знает про выходные линии микшера записи, они обозначаются у него индексом -1(минус один). А про то, что линии микшера могут иметь индивидуальные регулировки уровня для левого/правого каналов, bass не знает. У него есть только общая регулировка уровня для линии. |
|
|
|
|
|
из за того что fTL - время я определил как longint, ну в общем заменил на double перестало...
Спасибо вам большое! Без вас бы разбирался оочень долго... Я подробно изучу то, что вы мне отправили, потом отпишусь |
|
Сообщ.
#39
,
|
|
|
|
fTL:longint;
fTL := fTL + Length; Поначалу тоже так подумал(что это неплохая идея), а потом прикинул, переполнение наступит через 6 часов записи(для беззнакового целого типа сardinal). Добавлено Цитата из за того что fTL - время я определил как longint, Странно, с чего бы... ![]() Время можно брать от часов вреального времени, а длину файлового потока из свойства tfilestream.size. Там тип int64, так что и переполнение можно не учитывать на всех вменяемых длительностях записи. Просто сначала надо было проконтролировать длительность кусочков, так и поехало. |
|
Сообщ.
#40
,
|
|
|
|
Здорова! Ты был прав, там совсем не нужно было создавать несколько Rchan... все реализовал в одном...
Еще 2 вопроса.. 1- Как отключить используя bass.dll звук линейного входа (ну к примеру запускаешь прогу на XP, и как подключил телефон через линейный выход, сразу идет вещание на выход) 2- Не понимаю почему, ооооч редко, но все же иногда вылетает исключение access violation при записи и одновременном прослушивании |
|
Сообщ.
#41
,
|
|
|
|
Цитата Как отключить используя bass.dll звук линейного входа Для микшера воспроизведения, в типовой комплектации библиотеки такой возможности не нашёл(может, плохо искал). Линии микшера записи можно дергать при помощи BASS_RecordSetInput. Включать, выключать, регулировать уровень сигнала. Цитата Не понимаю почему, ооооч редко, но все же иногда вылетает исключение access violation при записи и одновременном прослушивании |
|
|
|
|
|
Спасибо тебе большое! Выручил! Ошибка выходила из-за ошибок в собственном коде... Все работает!
|
|
Сообщ.
#43
,
|
|
|
|
prince, не могу справиться с этой ошибкой... кстати, в том примере который ты скинул она тоже есть.. может из-за того что у меня win8 x64? напиши ко мне amanat_2007@mail.ru, помоги пожалуйста online
|
|
Сообщ.
#44
,
|
|
|
|
В каком месте дебагер ошибку показывает?
|
|
Сообщ.
#45
,
|
|
|
|
там такая ситуация...
![]() ![]() form.create: rchan := BASS_RecordStart(44100, 2, 10 shl 16, @RecordingCallback, nil); function RecordingCallback(Handle: HRECORD; buffer: Pointer; length: DWORD; user: Pointer): boolean; stdcall; var buffer_L :Pointer; buffer_R :Pointer; psample :^smallint; psample_L :^smallint; psample_R :^smallint; i: cardinal; begin buffer_L:=allocmem(length div 2); buffer_R:=allocmem(length div 2); psample:=buffer; psample_L:=buffer_L; psample_R:=buffer_R; for i:=0 to length div 4-1 do Begin psample_L^:=round(psample^); inc(psample); inc(psample_L); psample_R^:=round(psample^); inc(psample); inc(psample_R); end; freemem(buffer_L); freemem(buffer_R); Result := True; end; timer(200): TimerAll.Enabled := false; try inc(i); if i>2 then i:=1; if i=1 then begin cxGK1.Down := true; cxGK1Click(nil); end; if i=2 then begin cxGK2.Down := true; cxGK2Click(nil); end; finally TimerAll.Enabled := true; end; cxGK1Click: if cxGK1.Down then cxGK2.Down := false; cxGK2Click: if cxGK2.Down then cxGK1.Down := false; Смысла не имеет данная прога... я упрощал по максимуму чтобы найти ошибку... если запустить таймер и закоментировать rchan := BASS_RecordStart(44100, 2, 10 shl 16, @RecordingCallback, nil); ошибок нет если выключить таймер ошибок так же нет я использую компоненты devexspress... у тебя в примере при отладке если нажимать быстро на checkbox listen, та же выходила... но когда я откомпилировал и перенес на комп где win7 x86, ошибок не было если можно взгляни пожалуйста по teamviewer Прикреплённый файл Безымянный.jpg (45.45 Кбайт, скачиваний: 586)
|