Для этого нужно написать анализатор спектра, а для него, в свою очередь, нужно получить буфер сэмплов звука.
Стал пробовать решить эту задачу через VB6 + DirectShow.
В DX_SDK8.1 есть интерфейс для бейсика и даже пара примеров, но документации нету.
Создаю стандартный DirectShow-фильтр SampleGrabber, подключаю его в граф фильтров перед Default DirectSound Device.
Музыка играет, то есть граф работает. Вот такой код получился:
- Код: Выделить всё
Option Explicit
Dim graphManager As New FilgraphManager
Dim filterChain As New Collection
Private Sub Form_Load()
Dim filter As IFilterInfo
Dim pin As IPinInfo
' Добавляем источник (mp3-файл) и рендерим его pin
' Все необходимые фильтры при этом создаются и подключаются автоматически
Dim fileName As String
fileName = "C:\music.mp3"
graphManager.AddSourceFilter fileName, filter
filterChain.Add filter
filter.Pins.Item 0, pin
pin.Render
' Пробегаемся по связям фильтров и запоминаем их последовательность
Do
If pin Is Nothing Then Exit Do
If pin.ConnectedTo Is Nothing Then Exit Do
Set filter = pin.ConnectedTo.FilterInfo
filterChain.Add filter, filter.Name
Set pin = GetDirectionPin(filter, 1)
Loop
' Размыкаем 2 последних фильтра
Dim inFilter As IFilterInfo
Dim outFilter As IFilterInfo
Set outFilter = filterChain(filterChain.Count)
Set inFilter = filterChain(filterChain.Count - 1)
GetDirectionPin(inFilter, 1).Disconnect
' Создаём SampleGrabber фильтр и вклиниваем между ними
Dim grabberFilter As IFilterInfo
Dim regFilter As IRegFilterInfo
For Each regFilter In graphManager.RegFilterCollection
If regFilter.Name = "SampleGrabber" Then
regFilter.filter grabberFilter
filterChain.Add grabberFilter, grabberFilter.Name, outFilter.Name
Exit For
End If
Next
ConnectFilters inFilter, grabberFilter
ConnectFilters grabberFilter, outFilter
' Выводим на экран получившуюся цепочку
For Each filter In filterChain
infoList.AddItem filter.Name
Next
' Запускаем граф
Dim objPosition As IMediaPosition
Set objPosition = graphManager
objPosition.CurrentPosition = 0
graphManager.Run
End Sub
' Соединяет два фильтра
Function ConnectFilters(inFilter As IFilterInfo, outFilter As IFilterInfo)
GetDirectionPin(inFilter, 1).ConnectDirect GetDirectionPin(outFilter, 0)
End Function
' Возвращает первый найденный pin у фильтра в нужном направлении
Function GetDirectionPin(filter As IFilterInfo, direction As Integer) As IPinInfo
Dim pin As IPinInfo
For Each pin In filter.Pins
If pin.direction = direction Then
Set GetDirectionPin = pin
Exit Function
End If
Next
End Function
По идее, дальше нужно настроить CallBack'и для SampleGrabber'a, но как к нему обратиться из VB - непонятно.
В VB его тип Unknown, но известен интерфейс (описан в SDK) и даже можно найти GUID:
- Код: Выделить всё
static const IID IID_ISampleGrabber = // {6B652FFF-11FE-4fce-92AD-0266B5D7C78F}
static const CLSID CLSID_SampleGrabber = // {C1F400A0-3F08-11d3-9F0B-006008039E37}
Вот здесь описан способ, как можно создавать экземпляры этого класса и работать с ними:
http://www.vbstreets.ru/VB/Articles/65974.aspx
Но в нашем случае экземпляр уже есть, его можно достать из read-only свойства grabberFilter.filter
Как действовать в этом случае? Понятно, что нужно начать как-то так:
- Код: Выделить всё
Dim pMe As Long
Dim MyGuid As modOLECommon.Guid, tmpInterface As modOLECommon.Guid
modOLECommon.CLSIDFromString StrConv(CLSID_SampleGrabber, vbUnicode), MyGuid
modOLECommon.IIDFromString StrConv(IID_ISampleGrabber, vbUnicode), tmpInterface
modOLECommon.CoCreateInstance MyGuid, 0, 1, tmpInterface, pMe
А дальше?