dabudabu Posted February 17, 2011 Share Posted February 17, 2011 Hi to all of you. This is my first post, so I hope you will be mercifully with me. The matter is I badly need to know the input level of some ASIO device input channels (namely a digidesign MBOX2 and a EMU 0404 externalUSB, but I think this is not so important). As the examples for collecting input samples and reading the peak level from BASS ASIO devices I would able to come across to were less than a few, the development of a little piece of AutoIt software which could handle this topic is driving me mad :-( At the moment I only tried using "purely" BASS_ASIO calls, but this really doesn't matter to me, what I only need is to read the peak level of an ASIO input channel from an ASIO device or, as an alternative, get the samples in an array and calculate it, so in any way it could be done it will be great! The snippet I wrote tries to read this info by using a callback invoked by BASS_ASIO_ChannelEnable, but, as you can guess, it doesn't work, crashing as soon as the code reaches the end of the callback function. To make things a bit more parametric, I developed a tiny GUI, which lets you insert both the device and the input channel numbers. Using it, I first of all set up device and input channel, then I press the "INIT" button to initializate BASS_ASIO (which seems to me runs smoothly), and, at last, I supposed the reading of the input channel would be done by pressing the "START" button, which actually makes the program crashes. I inserted some debug consolewrite to trace what is going on inside the code, and it seems the sleep function inside the callback "helps" the program to crash, as well as the attempt to write the read peak level onto the GUI, as they conflict with the ASIO core. Furthermore it is not clear to me I would have to organize the code to read the input level continuously, suppose for 10 minutes, like looking at an input V-Meter, which is what this software is aimed to. Is the callback called continuously? Have I to put an infinite loop in the callback itself? Unfortunately this also is not clear to me. Finally I have to say I'm using "BASSASIO for ALL" to test my script (so I've never tested it with the two audio cards I own) reading its device and channel numbers by using the "list.exe" little program which comes together with the BASS and BASS_ASIO packages and putting these values in the GUI. To be honest, I'm much more interested in targeting my goal: to get the input peak value (or getting it by the samples array coming from an ASIO device input channel), rather than investigating in where I'm wrong, even if it could be interesting. Indeed, this development is just a little piece of an huge audio research I've been doing from the last 4 years, and at this stage I only, even if badly, need a very precise numeric V-Meter to exactly read the audio input level (in case using the samples array to calculate it), so all of this is no more than an unavoidable stuff to get it. Forgive me for this so long and perhaps boring description, for sure any help would be really appreciated as at the moment I'm lost in the middle of nowhere and this is delaying my research, which absolutely needs this instrument to go on. Thank you so much to all of you for your help and support, Daniele, Rome, Italy Here follows my AutoIt script: #include <BASS.au3> #include <BASSConstants.au3> #include <BASSAsio.au3> #include <BASSAsioConstants.au3> #include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form=d:\measure\au3\asio sin meter\asiosinmeterform.kxf $frmAsioInputMeter = GUICreate("Asio Input Meter", 302, 192, 192, 114) $cmdAsioStart = GUICtrlCreateButton("START", 184, 48, 49, 41, $WS_GROUP) $cmdAsioStop = GUICtrlCreateButton("STOP", 241, 48, 49, 41, $WS_GROUP) $txtChannelLevel = GUICtrlCreateInput("", 8, 96, 281, 81, BitOR($ES_CENTER,$ES_AUTOHSCROLL,$ES_READONLY)) GUICtrlSetFont(-1, 48, 800, 0, "Times New Roman") GUICtrlSetColor(-1, 0x0A246A) $txtDevice = GUICtrlCreateInput("", 8, 64, 49, 21, BitOR($ES_CENTER,$ES_AUTOHSCROLL)) $txtChannel = GUICtrlCreateInput("", 64, 64, 49, 21, BitOR($ES_CENTER,$ES_AUTOHSCROLL)) $lblDevice = GUICtrlCreateLabel("Device", 11, 47, 38, 17) $lblChannel = GUICtrlCreateLabel("Channel", 65, 47, 43, 17) $lblTitle = GUICtrlCreateLabel("Asio Input Meter", 9, 2, 291, 41) GUICtrlSetFont(-1, 24, 400, 0, "MS Sans Serif") $cmdAsioInit = GUICtrlCreateButton("INIT", 127, 48, 49, 41, $WS_GROUP) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### $IsInput = 1 $UsesCurrentBufferLen = 0 global $cbSamplesBuffer = DllStructCreate("int Buffer[2048]") global $cbSamplesBufferPTR = DllStructGetPtr($cbSamplesBuffer ) global $cblen = DllStructCreate("DWORD len") global $cbChannel = DllStructCreate("DWORD cbChannel") global $cbIsInput = DllStructCreate("DWORD cbIsInput") global $cbDummyData = 0 global $cbDummyDataPTR = DllStructGetPtr($cbDummyData) _BASS_STARTUP() _BASS_ASIO_STARTUP() While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit case $cmdAsioInit Assert(_BASS_ASIO_Stop(), "_BASS_ASIO_Stop") Assert(_BASS_ASIO_Free(), "_BASS_ASIO_Free") $Device = GUICtrlRead($txtDevice) $Channel = GUICtrlRead($txtChannel) Assert(_BASS_ASIO_STARTUP(), "_BASS_ASIO_STARTUP") Assert(_BASS_ASIO_Init($Device), "_BASS_ASIO_Init") Assert(_BASS_ASIO_SetRate(44100.0), "_BASS_ASIO_SetRate") Assert(_BASS_ASIO_ChannelSetFormat($IsInput, 0, $BASS_ASIO_FORMAT_16BIT), "_BASS_ASIO_ChannelSetFormat") Assert(_BASS_ASIO_ChannelSetRate($IsInput, $Channel, 44100.0), "_BASS_ASIO_ChannelSetRate") Assert(_BASS_ASIO_ChannelEnable($IsInput, $Channel, "cbAsioShowInputLevel", $cbDummyData), "_BASS_ASIO_ChannelEnable") $cbIsInput = $IsInput $cbChannel = $Channel case $cmdAsioStart Assert(_BASS_ASIO_Start($UsesCurrentBufferLen), "_BASS_ASIO_Start") ConsoleWrite("now out from callback" & @CRLF) case $cmdAsioStop Assert(_BASS_ASIO_Stop(), "_BASS_ASIO_Stop") Assert(_BASS_ASIO_Free(), "_BASS_ASIO_Free") EndSwitch WEnd Func cbAsioShowInputLevel($cbIsInput, $cbChannel, $cbSamplesBufferPTR, $cblen, $cbDummyDataPTR) $n = 1 ;while 1 ConsoleWrite($n & ".1 cbSamplesBuffer = " & DllStructGetData ($cbSamplesBuffer, 1) & @CRLF) $V = _BASS_ASIO_ChannelGetLevel($cbIsInput, $cbChannel) ;GUICtrlSetData($txtChannelLevel, $V) ConsoleWrite($n & ".2 wrote " & $V & " on GUI" & @CRLF) ;;Sleep(50) ConsoleWrite($n & ".3 callback sleept a bit" & @CRLF) $n = $n +1 ;wend EndFunc Func Assert($retVal, $CalledFunction) If @error Then MsgBox(0, $CalledFunction & " ERROR: " & @error, $CalledFunction) Exit Else ConsoleWrite("OK " & $CalledFunction & @CRLF) EndIf EndFunc Link to comment Share on other sites More sharing options...
eukalyptus Posted February 18, 2011 Share Posted February 18, 2011 HiDownload http://rapidshare.com/files/412849347/Bass_new.zip (unofficial beta)and take a look at the asio examples.Sorry, I can´t give better support at the moment...E DirectSound UDF Direct2D UDF Link to comment Share on other sites More sharing options...
dabudabu Posted February 27, 2011 Share Posted February 27, 2011 (edited) Hi Download http://rapidshare.com/files/412849347/Bass_new.zip (unofficial beta) and take a look at the asio examples. Sorry, I can´t give better support at the moment... E Dear Eukalyptus, you cannot imagine how your help has been important to me. Without your support I would be still lost, due to the exact measurement of the asio input level is crucial to my research. Having had the opportunity to take a look at your example scripts made me able to definitively work out the solution I so desperately needed and, at last, got. To be honest, it is still not perfectly clear to me the exact way in which your _Bass_Asio_ChannelGetLevel gets the result, but anyway it works, doing it damn well! So, hoping this will be useful to any of you, I built up a GUI around your _Bass_Asio_ChannelGetLevel and added a bit of logic to manage the asio input device, the recorded file and the input channel levels, even if the core, which makes the piece of sw useful, is completely yours and I only made some minor changes to it, just to make the script more readable. When compiled, this script exactly realizes what it is aimed to, a small, stand alone application to exactly show the asio device input levels. I also added the visualization of the current maximum input level, which is hold for roughly one second. It could be needed to change the directories in the #include statements to point to the position of the _BASS include files and, of course, the dlls must be in the script folder in order to make it works. One more time, thank you. Should one day my research be complete, please let me quote your help (together with Ian, the author of the terrific bass dlls set), and in case I will ask you your permission to do so, asking you some further details other than a nick name on this forum to make people know more about you. expandcollapse popup;;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 ;#include-once ;#include "Bass.au3" #include "D:\Measure\au3\BASS_New By Eucaliptus\BASS\Bass.au3" ;#include "BassAsio.au3" #include "D:\Measure\au3\BASS_New By Eucaliptus\BASS_ASIO\BassAsio.au3" ;#include "BassExt.au3" #include "D:\Measure\au3\BASS_New By Eucaliptus\BASS_EXT\BassExt.au3" ;#include "BassEnc.au3" #include "D:\Measure\au3\BASS_New By Eucaliptus\BASS_ENC\BassEnc.au3" #include <ButtonConstants.au3> #include <ComboConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <ProgressConstants.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form=d:\measure\au3\asio sin meter\formasiosinmeter.kxf $frmAsioInputMeter = GUICreate("16 BIT 44.100 Hz ASIO DEVICE INPUT METER", 557, 185, 193, 114) $cmbDevice = GUICtrlCreateCombo("", 72, 8, 337, 25) $txtChannel1Level = GUICtrlCreateInput("", 8, 104, 249, 45, BitOR($ES_CENTER,$ES_AUTOHSCROLL,$ES_READONLY)) GUICtrlSetFont(-1, 24, 800, 0, "MS Sans Serif") GUICtrlSetColor(-1, 0x800080) $txtChannel2Level = GUICtrlCreateInput("", 296, 104, 249, 45, BitOR($ES_CENTER,$ES_AUTOHSCROLL,$ES_READONLY)) GUICtrlSetFont(-1, 24, 800, 0, "MS Sans Serif") GUICtrlSetColor(-1, 0x800080) $ProgressChannel1 = GUICtrlCreateProgress(8, 158, 249, 17) $ProgressChannel2 = GUICtrlCreateProgress(296, 158, 249, 17) $cmdStop = GUICtrlCreateButton("Stop", 484, 6, 60, 25, $WS_GROUP) $cmdStart = GUICtrlCreateButton("Start", 416, 6, 60, 25, $WS_GROUP) $txtRecordFile = GUICtrlCreateInput("", 71, 38, 425, 21) $lblAsioDevice = GUICtrlCreateLabel("Asio device", 9, 12, 59, 17) $cmdBrowseRecFile = GUICtrlCreateButton("...", 503, 36, 41, 25, $WS_GROUP) GUICtrlSetFont(-1, 14, 800, 0, "MS Sans Serif") $lblRecordInto = GUICtrlCreateLabel("Record into", 7, 40, 59, 17) $lblChannel1 = GUICtrlCreateLabel("Value - Max Ch 1", 7, 82, 119, 20) GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif") GUICtrlSetColor(-1, 0x800080) $lblChannel2 = GUICtrlCreateLabel("Value - Max Ch 2", 431, 82, 119, 20) GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif") GUICtrlSetColor(-1, 0x800080) $txtSamplingRate = GUICtrlCreateInput("", 192, 64, 65, 21, BitOR($ES_CENTER,$ES_AUTOHSCROLL,$ES_READONLY)) $lblSamplingRate = GUICtrlCreateLabel("Sample Rate", 127, 68, 65, 17) $lblBitDepth = GUICtrlCreateLabel("Bit depth", 367, 68, 46, 17) $txtBitDepth = GUICtrlCreateInput("", 296, 64, 65, 21, BitOR($ES_CENTER,$ES_AUTOHSCROLL,$ES_READONLY)) $ProgressCPU = GUICtrlCreateProgress(268, 104, 17, 45, $PBS_VERTICAL) $lblCPU = GUICtrlCreateLabel("CPU", 265, 86, 26, 17) $txtCPULevel = GUICtrlCreateInput("", 262, 158, 29, 17, BitOR($ES_CENTER,$ES_AUTOHSCROLL,$ES_READONLY)) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### OnAutoItExitRegister("_FreeBass") HotKeySet("{ESC}", "_Exit") Global $hEncoder, $ReadSampleRate, $InputSampleRate, $hAsioBuffer, $aPipe[6], $aInfo Global $NoFlags, $AppName, $OneChannel, $NoFlags, $Channel1, $Channel2, $IsAnInputChannel Global $BitDepth, $BitDepthFullScale, $MilliSecMaxValueRetemption, $TwoChannels, $MilliSecForCycle Global $MaxChannel1, $MaxChannel2, $MilliSecElapsed $AppName = "ASIO Input Meter" $NoFlags = 0 $Channel1 = 0 $Channel2 = 1 $IsAnInputChannel = True $BitDepth = 16 $BitDepthFullScale = 32767 $TwoChannels = 2 $MilliSecForCycle = 50 $MilliSecMaxValueRetemption = 1000 StartApp() $Start = False $MilliSecElapsed = 0 While 1 $CanStart = GUICtrlRead( $txtRecordFile ) <> "" and GUICtrlRead( $cmbDevice ) <> "" and $Start = False if $CanStart Then GUICtrlSetState($cmdStop, $GUI_DISABLE) GUICtrlSetState($cmdStart, $GUI_ENABLE) Else GUICtrlSetState($cmdStop, $GUI_ENABLE) GUICtrlSetState($cmdStart, $GUI_DISABLE) endif $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $cmdBrowseRecFile if $Start = False Then $RecordFile = FileSaveDialog("Choose WAV record file", @ScriptDir, "Wav file (*.wav)", 16) if $RecordFile = "" Then $RecordFile = @ScriptDir & "\" & "asioinputmeter.wav" endif GUICtrlSetData($txtRecordFile, $RecordFile) EndIf Case $cmdStop $Start = False _FreeBass() Case $cmdStart $sDevice = GUICtrlRead($cmbDevice) $Device = int(StringRight($sDevice, 1)) $Start = True MeterStart($Device, $RecordFile, 44100) EndSwitch Sleep($MilliSecForCycle) $MilliSecElapsed += $MilliSecForCycle if $Start then $Ch1Level = round( _BASS_ASIO_ChannelGetLevel(True, $Channel1) * $BitDepthFullScale, 0) $Ch2Level = round( _BASS_ASIO_ChannelGetLevel(True, $Channel2) * $BitDepthFullScale, 0) if $Ch1Level > $MaxChannel1 Then $MaxChannel1 = $Ch1Level $MilliSecElapsed = 0 EndIf if $Ch2Level > $MaxChannel2 Then $MaxChannel2 = $Ch2Level $MilliSecElapsed = 0 EndIf if $MilliSecElapsed > $MilliSecMaxValueRetemption Then $MilliSecElapsed = 0 $MaxChannel1 = $Ch1Level $MaxChannel2 = $Ch2Level EndIf GUICtrlSetData($txtChannel1Level, $Ch1Level & "-" & $MaxChannel1 ) GUICtrlSetData($txtChannel2Level, $Ch2Level & "-" & $MaxChannel2 ) GUICtrlSetData($ProgressChannel1, $Ch1Level * 100 / $BitDepthFullScale ) GUICtrlSetData($ProgressChannel2, $Ch2Level * 100 / $BitDepthFullScale ) GUICtrlSetData($txtSamplingRate, _BASS_ASIO_ChannelGetRate(True, $Channel1) ) $CPU = Round( _BASS_ASIO_GetCPU()*100, 1) GUICtrlSetData($ProgressCPU, $CPU ) GUICtrlSetData($txtCPULevel, $CPU ) GUICtrlSetData($txtBitDepth, $BitDepth & "/" & $BitDepthFullScale ) else GUICtrlSetData($txtChannel1Level, "" ) GUICtrlSetData($txtChannel2Level, "" ) GUICtrlSetData($ProgressCPU, 0 ) GUICtrlSetData($txtCPULevel, "" ) GUICtrlSetData($ProgressChannel1, 0 ) GUICtrlSetData($ProgressChannel2, 0 ) EndIf Wend Func _Exit() Exit EndFunc ;==>_Exit Func _FreeBass() Assert(0, "Stopping Asio Input Meter:" & @CRLF ) Assert( _BASS_Encode_Stop($hEncoder), " _BASS_Encode_Stop" ) Assert( _BASS_ASIO_Stop(), " _BASS_ASIO_Stop()" ) Assert( _BASS_ASIO_Free(), " _BASS_ASIO_Free()" ) Assert( _BASS_Free(), " _BASS_Free()" ) EndFunc ;==>_FreeBass Func ___DeBug($iError, $sAction) Switch $iError Case -1 ConsoleWrite(@CRLF & "-" & $sAction & @CRLF) Case -2 ConsoleWrite(@CRLF & ">" & $sAction & @CRLF) Case 0 ;;ConsoleWrite(@CRLF & "+" & $sAction & " - OK" & @CRLF) ConsoleWrite("OK " & $sAction & @CRLF) Case Else ConsoleWrite(@CRLF & "!" & $sAction & " - FAILED, @error: " & $iError & @CRLF) Exit EndSwitch EndFunc ;==>___DeBug Func Assert($retVal, $sAction) If @error Then MsgBox(0, $AppName, $sAction & " ERROR: " & @error, $sAction) Exit Else Consolewrite("OK " & $sAction & @CRLF) EndIf EndFunc Func StartApp() Assert(0, "Initializing App loading BASS dll" & @CRLF ) ;;*********************STARTUP BASS ********************************* Assert (_BASS_Startup(), " _BASS_Startup(): load bass.dll") ;; ___Debug(@error, "load bass.dll") Assert( _BASS_ASIO_Startup(), " _BASS_ASIO_Startup(): load bassasio.dll") ;; ___Debug(@error, "load bassasio.dll") Assert( _BASS_ENCODE_Startup(), " _BASS_ENCODE_Startup(): load bassenc.dll") ;; ___Debug(@error, "load bassenc.dll") Assert( _BASS_EXT_STARTUP(), " _BASS_EXT_STARTUP(): load bassext.dll") ;; ___Debug(@error, "load bassext.dll") ;;*********************STARTUP BASS ********************************* ;;Fill the device combo box $iDevice = 0 $lstDevice = "" While 1 $aDeviceInfoInfo = _BASS_ASIO_GetDeviceInfo($iDevice) If @error Then ExitLoop Else $lstDevice = $lstDevice & $aDeviceInfoInfo[1] & " - Device " & $iDevice & "|" $iDevice += 1 EndIf Wend GUICtrlSetData($cmbDevice, $lstDevice) EndFunc Func MeterStart($Device, $RecordFile, $InputSampleRate) Assert(0, "Starting Asio Input Meter:" & @CRLF ) Assert( _BASS_ASIO_Init($Device), " _BASS_ASIO_Init device: initialize asio device number " & $Device ) ;;___Debug(@error, "initialize asio") Assert( _Bass_ASIO_SetRate($InputSampleRate), " _Bass_ASIO_SetRate: set Asio sample rate at " & $InputSampleRate & " Hz") ;;___Debug(@error, "set asio samplerate: " & $InputSampleRate) $ReadSampleRate = _BASS_ASIO_GetRate() ___Debug(@error, " _BASS_ASIO_GetRate: get asio samplerate: " & $ReadSampleRate & " Hz") Assert( _BASS_Init($NoFlags, -1, $ReadSampleRate), " _BASS_Init: initialize bass (same samplerate as asio)" ) ;;___Debug(@error, "initialize bass (same samplerate as asio)") $hAsioBuffer = _BASS_StreamCreate($ReadSampleRate, $TwoChannels, $NoFlags, $STREAMPROC_PUSH, 0) ___Debug(@error, " _BASS_StreamCreate: create push stream to act as buffer for asio in") Assert( _BASS_ChannelSetAttribute($hAsioBuffer, $BASS_ATTRIB_VOL, 0), " _BASS_ChannelSetAttribute: mute channel" ) ;;___Debug(@error, "mute channel") Assert( _BASS_ChannelPlay($hAsioBuffer, False), " _BASS_ChannelPlay: start channel - data is sent to encoder when buffer is filled") ;; ___Debug(@error, "start channel - data is sent to encoder when buffer is filled") $hEncoder = _BASS_Encode_Start($hAsioBuffer, $RecordFile, BitOR($BASS_ENCODE_PCM, $BASS_ENCODE_FP_16BIT)) ___Debug(@error, " _BASS_Encode_Start: set encoder on the stream") $aInfo = _BASS_ASIO_GetInfo() ___Debug(@error, " _BASS_ASIO_GetInfo: get asio infos") $aPipe = _BASS_EXT_StreamPipeCreate($hAsioBuffer, $BASS_EXT_STREAMPROC_PUSH) ___Debug(@error, " _BASS_EXT_StreamPipeCreate: using created push stream as buffer for asio in") Assert( _BASS_ASIO_ChannelEnable($IsAnInputChannel, $Channel1, $BASS_EXT_AsioProc, $aPipe[0]), " _BASS_ASIO_ChannelEnable: enable asio input channel 1" ) ;; ___Debug(@error, "enable asio input channel 1") Assert( _BASS_ASIO_ChannelSetFormat($IsAnInputChannel, $Channel1, $BASS_ASIO_FORMAT_16BIT), " _BASS_ASIO_ChannelSetFormat: set asio input channel 1 sampleformat to 16 bit" ) ;; ___Debug(@error, "set asio input channel 1 sampleformat to 16bit") Assert( _BASS_ASIO_ChannelSetRate($IsAnInputChannel, $Channel1, $ReadSampleRate), " _BASS_ASIO_ChannelSetRate: set asio input channel 1 samplerate to " & $ReadSampleRate ) ;; ___Debug(@error, "set asio input channel 1 samplerate to " & $ReadSampleRate) Assert( _BASS_ASIO_ChannelJoin($IsAnInputChannel, $Channel2, $Channel1), " _BASS_ASIO_ChannelJoin: join asio input channel 2 and 1" ) ;; ___Debug(@error, "join asio input channel 2 and 1") Assert( _BASS_ASIO_Start($aInfo[5]), " _BASS_ASIO_Start: start asio processing" ) ;; ___Debug(@error, "start asio processing") ___Debug(-2, "Recording to " & $RecordFile) ___Debug(-1, "press ESC to quit") GUICtrlSetData($txtSamplingRate, $ReadSampleRate) EndFunc Edited February 27, 2011 by dabudabu Link to comment Share on other sites More sharing options...
Zip Posted March 20, 2011 Share Posted March 20, 2011 (edited) This is great stuff! As I am quite new to it all, I was wondering if anyone knows: on _BASS_CD_GetInfo; - [4] = The drive's reading and writing capabilities, a combination of the following flags ... when reading this array value you get a number like : 2138374207 so I need to find out how to interpret it. so if one is trying to figure out how to query a specific 'rwflags' capability, say, $BASS_CD_RWFLAG_READDVDR, etc, Is there a way to do that? Edited March 20, 2011 by Zip Link to comment Share on other sites More sharing options...
XY16 Posted March 31, 2011 Share Posted March 31, 2011 hi, i am trying to write a simple script to start recording at the press of a hotkey and stop when the key is pressed again. i have tried for days to get the bass recording functions to work, but no luck. could someone please post a short example of how to start recording, then stop and save to a file? if someone could do that i would be most appreciative as i need the functionality for a voice chat server i have written. thanks in advance. Please note: If you plan on submitting any code snippits to my posts, please refrain from using the code tags as i use a screen reader and can't read the code properly, let alone copy it the way it should be.Thanks for your understanding.Best regardsXY16 Link to comment Share on other sites More sharing options...
BrettF Posted April 5, 2011 Author Share Posted April 5, 2011 This is great stuff! As I am quite new to it all, I was wondering if anyone knows: on _BASS_CD_GetInfo; - [4] = The drive's reading and writing capabilities, a combination of the following flags ... when reading this array value you get a number like : 2138374207 so I need to find out how to interpret it. so if one is trying to figure out how to query a specific 'rwflags' capability, say, $BASS_CD_RWFLAG_READDVDR, etc, Is there a way to do that? _BASS_CD_GetInfo($drive) should return an array and I assume you are going and retrieving the 4 element in the array successfuly. You should be able to do something like... If BitAnd ($RetturnValue[4], $flag) <> 0 Then ... or something similar. hi, i am trying to write a simple script to start recording at the press of a hotkey and stop when the key is pressed again. i have tried for days to get the bass recording functions to work, but no luck. could someone please post a short example of how to start recording, then stop and save to a file? if someone could do that i would be most appreciative as i need the functionality for a voice chat server i have written. thanks in advance. I'll try find my example for recording. I think eukalyptus might have one too? I'll ask him for you and if I can't find one, then I'll make one. Cheers, Brett Vist my blog!UDFs: Opens The Default Mail Client | _LoginBox | Convert Reg to AU3 | BASS.au3 (BASS.dll) (Includes various BASS Libraries) | MultiLang.au3 (Multi-Language GUIs!)Example Scripts: Computer Info Telnet Server | "Secure" HTTP Server (Based on Manadar's Server)Software: AAMP- Advanced AutoIt Media Player | WorldCam | AYTU - Youtube Uploader Tutorials: Learning to Script with AutoIt V3Projects (Hardware + AutoIt): ArduinoUseful Links: AutoIt 1-2-3 | The AutoIt Downloads Section: | SciTE4AutoIt3 Full Version! Link to comment Share on other sites More sharing options...
Zip Posted July 10, 2011 Share Posted July 10, 2011 BrettF , thanks man! I had a talk with Ian from un4seen for a while about adding some BassCD features & fixing some issues ,and now the new BASSCD version has the fixes. But, I have a hard time translating the new code /funcs to Autoit . These are the NEW funcs & constants from the VB File: expandcollapse popupGlobal Const BASS_CDID_CDDB_QUERY = &H200 Global Const BASS_CDID_CDDB_READ = &H201 ' + entry # Global Const BASS_CDID_CDDB_READ_CACHE = &H2FF ' BASS_CD_GetTOC modes Global Const BASS_CD_TOC_TIME = &H100 ' TOC structures Type BASS_CD_TOC_TRACK res1 As Byte adrcon As Byte ' ADR + control track As Byte ' track number res2 As Byte lba As Long ' start address (logical block address) End Type Type BASS_CD_TOC size As Integer ' size of TOC first As Byte ' first track last As Byte ' last track tracks(0 To 99) As BASS_CD_TOC_TRACK ' up to 100 tracks End Type ' BASS_CD_TOC_TRACK "adrcon" flags Global Const BASS_CD_TOC_CON_PRE = 1 Global Const BASS_CD_TOC_CON_COPY = 2 Global Const BASS_CD_TOC_CON_DATA = 4 ' CDDATAPROC "type" values Global Const BASS_CD_DATA_SUBCHANNEL = 0 Global Const BASS_CD_DATA_C2 = 1 Declare Function BASS_CD_GetTOC Lib "basscd.dll" (ByVal drive As Long, ByVal mode As Long, ByRef toc As BASS_CD_TOC) As Long Declare Function BASS_CD_SetOffset Lib "basscd.dll" (ByVal drive As Long, ByVal offset As Long) As Long Declare Function BASS_CD_StreamCreateEx Lib "basscd.dll" (ByVal drive As Long, ByVal track As Long, ByVal flags As Long, ByVal proc As Long, ByVal user As Long) As Long Declare Function BASS_CD_StreamCreateFileEx Lib "basscd.dll" (ByVal f As String, ByVal flags As Long, ByVal proc As Long, ByVal user As Long) As Long ' callback functions Sub CDDATAPROC(ByVal handle As Long, ByVal pos As Long, ByVal type_ As Long, ByVal buffer As Long, ByVal length As Long, ByVal user As Long) 'CALLBACK FUNCTION !!! ' Sub-channel/C2 reading callback function. ' handle : The CD stream handle ' pos : The position of the data ' type : The type of data (BASS_CD_DATA_xxx) ' buffer : Buffer containing the data. ' length : Number of bytes in the buffer ' user : The 'user' parameter value given when calling BASS_CD_StreamCreate/FileEx End Sub And these 2 Structure Examples are also New, from the New Help File, How do these translate to Autoit, I noticed the struct type defs are sometimes different in Bass/CD.AU3 BASS_CD_TOC Structure Used with BASS_CD_GetTOC to retrieve the TOC from a CD: typedef struct { WORD size; BYTE first; BYTE last; BASS_CD_TOC_TRACK tracks[100]; } BASS_CD_TOC; another example (I don't know what this UNION is, & I couldnt see it in the VB defs above, so really confused now) typedef struct { BYTE res1; BYTE adrcon; BYTE track; BYTE res2; union { DWORD lba; BYTE hmsf[4]; }; } BASS_CD_TOC_TRACK; Does anyone know how to translate it to Autoit? Thanks for reading this, All the best. Link to comment Share on other sites More sharing options...
eukalyptus Posted July 10, 2011 Share Posted July 10, 2011 Added to BASS-UDF v.10download here: http://www.autoit.de/index.php?page=Thread&postID=215291#post215291it was a bit tricky, because of the union structure, but it should work...E DirectSound UDF Direct2D UDF Link to comment Share on other sites More sharing options...
Zip Posted July 10, 2011 Share Posted July 10, 2011 Ahh Eukalyptus man, you are awesome friend, thank you so much, sounds like you should update the version to 10.01! I am learning programming with Autoit as a hobby, & people like you guys are an inspiration for me. Thanks a LOT for everything. Link to comment Share on other sites More sharing options...
Zip Posted July 10, 2011 Share Posted July 10, 2011 Eukalyptus, I will be going through it at my own pace, & hopefully get some insight using it, is it ok I report some feedback to you here? Link to comment Share on other sites More sharing options...
Zip Posted July 10, 2011 Share Posted July 10, 2011 (edited) Eukalyptus, just plain great !some feedback:This should be added to the BASSCDconstants.au3 , to check for C2 support.Global Const $BASS_CD_RWFLAG_READC2 = 0x10000000Just tried the _BASS_CD_GetTOC , works great,If I am using $mode=$BASS_CD_TOC_TIME,however if set to 0 the LBA output seems wrong, & I am not sure it is a problem in the Dll, maybe you can have a look,insert a CD, & tell me if you get something like:[00] |10 |1 |9 | | | | LBA ------ [01] |1 |0 |1 |0 | | | [02] |1 |0 |2 |130 | | | [03] |1 |0 |3 |220 | | | [04] |1 |0 |4 |320 | | | [05] |1 |0 |5 |450 | | | [06] |1 |0 |6 |564 | | | [07] |1 |0 |7 |665 | | | [08] |1 |0 |8 |752 | | | [09] |1 |4 |9 |948 | | | [10] |1 |4 |170 |1274 | | |even weirder, try $mode=-1 to get some different but still funky results from the dll. Edited July 10, 2011 by Zip Link to comment Share on other sites More sharing options...
eukalyptus Posted July 12, 2011 Share Posted July 12, 2011 hmmm - a little bug in BassCD.au3: change line 264 $tTemp = DllStructCreate("dword", $pTOC + 4 + ($i - 1) * 8 + 5) to: $tTemp = DllStructCreate("dword", $pTOC + 4 + ($i - 1) * 8 + 4) "Global Const $BASS_CD_RWFLAG_READC2 = 0x10000000" will be added next time - thx E DirectSound UDF Direct2D UDF Link to comment Share on other sites More sharing options...
Zip Posted July 12, 2011 Share Posted July 12, 2011 (edited) Eukalyptus, great, that fixed it !On another matter: Saving BassCD stream to wave file:1. I was looking through the examples & functions, could not find/figure out a method to save to file. -However, I did note the _Bass_Encode functions, & using em I did work something out, but I have to use _BASS_Init for it to work. Q: As from what I managed to figure out so far, _BASS_Init, initializes an output device, is this a must when only trying to save a cd track to wav file without playing it? Q: Is that the right way to do it using _BASS_Encode ? what is the best way to go about saving the cd stream to a wave file ?2. If you noticed there are now BASS_CD_StreamCreateEx, BASS_CD_StreamCreateFileEx , both capable of optionally providing a callback function to receive sub-channel data and/or C2 error info. so effectively this will enable seeing C2 errors on the fly, potentially displayed graphically in a gui, when reading a cd track, seeing your excellent examples, maybe you can figure out an example that can help me figure out how to go about it, thanks! Edited July 12, 2011 by Zip Link to comment Share on other sites More sharing options...
eukalyptus Posted July 12, 2011 Share Posted July 12, 2011 You can call _BASS_Init with device = 0 (= no sound) there are more ways to rip an audiotrack from CD to wav. example 1 using BassEnc: #AutoIt3Wrapper_UseX64=n #include "BASSCD.au3" #include "BassEnc.au3" HotKeySet("{ESC}", "_Exit") Global $tBuffer = DllStructCreate("byte[100000]") Global $pBuffer = DllStructGetPtr($tBuffer) Global $iBuffer = DllStructGetSize($tBuffer) _BASS_Startup() _BASS_CD_Startup() _BASS_Encode_Startup() _BASS_Init(0, 0, 44100) Global $hStream = _BASS_CD_StreamCreate(0, 0, $BASS_STREAM_DECODE) Global $hEncoder = _BASS_Encode_Start($hStream, "Test.wav", $BASS_ENCODE_PCM) Global $iLength = _BASS_ChannelGetLength($hStream, $BASS_POS_BYTE) Global $iRead = 0 While _BASS_ChannelIsActive($hStream) $iRead += _BASS_ChannelGetData($hStream, $pBuffer, $iBuffer) If @error Then ExitLoop ConsoleWrite("> " & Floor($iRead * 100 / $iLength) & "% done" & @CRLF) WEnd _Exit() Func _Exit() _BASS_Encode_Stop($hEncoder) _BASS_StreamFree($hStream) _BASS_Free() Exit EndFunc ;==>_Exit example 2 using BassExt: #AutoIt3Wrapper_UseX64=n #include "BASSCD.au3" #include "BassExt.au3" HotKeySet("{ESC}", "_Exit") _BASS_Startup() _BASS_CD_Startup() _BASS_EXT_Startup() _BASS_Init(0, 0, 44100) Global $hStream = _BASS_CD_StreamCreate(0, 0, $BASS_STREAM_DECODE) Global $iLength = _BASS_ChannelGetLength($hStream, $BASS_POS_BYTE) Global $tBuffer = DllStructCreate("byte[" & $iLength & "]") Global $pBuffer = DllStructGetPtr($tBuffer) Global $iBuffer = DllStructGetSize($tBuffer) ConsoleWrite("! please wait - reading audiotrack to memory..." & @CRLF) _BASS_ChannelGetData($hStream, $pBuffer, $iBuffer) ConsoleWrite("! saving wav file to disk..." & @CRLF) Global $tWave = _BASS_EXT_MakeWave(DllStructGetData($tBuffer, 1)) _BASS_EXT_SaveWave($tWave, "Test2.wav") _Exit() Func _Exit() _BASS_StreamFree($hStream) _BASS_Free() Exit EndFunc ;==>_Exit to get the percentage in the second example you could use a smaller buffer (like example 1) and fill the data to the final buffer (_Bass_Ext_MemoryBuffer-functions...) and you can write your own callback function to write the wav file - take a look at "Using callback functions" in the help file E DirectSound UDF Direct2D UDF Link to comment Share on other sites More sharing options...
Zip Posted July 12, 2011 Share Posted July 12, 2011 Great examples, thank you so much.I will definitely read & try to learn the call back functions & get a grip on it.Now that I have your examples I'll try figuring out a way to use the BASS_CD_StreamCreateEx, BASS_CD_StreamCreateFileEx ,both capable of optionally providing a callback function to receive sub-channel data and/or C2 error info.My goal is:I am hoping to get something working for seeing C2 errors on the fly,when reading a cd track,so further action can be decided upon the error count, etc.I will try to figure out a way to do it graphically (displaying C2 read errors/correction graphically in a gui), after learning how to use the callback function for it as you advised.Eternal gratitude Eukalyptus! Link to comment Share on other sites More sharing options...
eukalyptus Posted July 15, 2011 Share Posted July 15, 2011 (edited) example to get C2 errors while ripping to wav (or mp3/ogg...): expandcollapse popup#AutoIt3Wrapper_UseX64=n #include "BASSCD.au3" #include "BassEnc.au3" HotKeySet("{ESC}", "_Exit") Global $sC2_Error = "" Global $tBuffer = DllStructCreate("byte[235200]") Global $pBuffer = DllStructGetPtr($tBuffer) Global $iBuffer = DllStructGetSize($tBuffer) _BASS_Startup() _BASS_CD_Startup() _BASS_Encode_Startup() _BASS_Init(0, 0, 44100) Global $hProc = DllCallbackRegister("_Callback", "none", "dword;int;dword;ptr;dword;ptr") Global $hStream = _BASS_CD_StreamCreateEx(0, 0, BitOR($BASS_STREAM_DECODE, $BASS_CD_C2ERRORS), DllCallbackGetPtr($hProc)) Global $hEncoder = _BASS_Encode_Start($hStream, "Test3.wav", $BASS_ENCODE_PCM) Global $iLength = _BASS_ChannelGetLength($hStream, $BASS_POS_BYTE) Global $iRead = 0 While _BASS_ChannelIsActive($hStream) $iRead += _BASS_ChannelGetData($hStream, $pBuffer, $iBuffer) If @error Then ExitLoop ConsoleWrite("> " & Floor($iRead * 100 / $iLength) & "% done" & @CRLF) WEnd _Exit() Func _Callback($hHandle, $iPos, $iType, $pBuffer, $iLength, $pUser) If $iType <> $BASS_CD_DATA_C2 Then Return Local $iC2_Count = $iLength / 296 ; <- a C2-error block is 296 bytes long (2352 bytes audiodata / 8 bit) ;ConsoleWrite($iC2_Count & " C2_error_infos in buffer" & @CRLF) Local $tC2, $iOR_Byte, $iPos_Bytes For $i = 0 To $iC2_Count - 1 $tC2 = DllStructCreate("byte[296];", $pBuffer + $i * 296) ; <- create struct to read from the buffer $iOR_Byte = DllStructGetData($tC2, 1, 295) ; <- if OR-Byte is set then there was an error in the last 2352 bytes of audiodata If $iOR_Byte Then For $j = 1 To 294 ; <- check every byte $iByte = DllStructGetData($tC2, 1, $j) If $iByte Then For $k = 0 To 7 ; <- check every bit in the byte If BitAND($iByte, 2^$k) Then $iPos_Bytes = $iPos + $i * 2352 + ($j - 1) * 8 + $k ; <- calc position of error $sC2_Error &= "C2 error at byte: " & $iPos_Bytes & " / " & _Sec2Time(_BASS_ChannelBytes2Seconds($hHandle, $iPos_Bytes)) & @CRLF EndIf Next EndIf Next EndIf Next EndFunc ;==>_Callback Func _Sec2Time($fSec) Local $iSec, $iH, $iM, $iS, $iC $iSec = Floor($fSec) $iC = Floor(($fSec * 100) - ($iSec * 100)) $iH = Int($iSec / 3600) $iSec = Mod($iSec, 3600) $iM = Int($iSec / 60) $iS = Mod($iSec, 60) Return StringFormat("%02s:%02s:%02s,%02s", $iH, $iM, $iS, $iC) EndFunc ;==>_Sec2Time Func _Exit() _BASS_Encode_Stop($hEncoder) _BASS_StreamFree($hStream) DllCallbackFree($hProc) _BASS_Free() Local $hFile = FileOpen(@ScriptDir & "\C2_Error.txt", 2) FileWrite($hFile, $sC2_Error) FileClose($hFile) ShellExecute(@ScriptDir & "\C2_Error.txt") Exit EndFunc ;==>_Exit E Edited July 15, 2011 by eukalyptus DirectSound UDF Direct2D UDF Link to comment Share on other sites More sharing options...
Zip Posted July 17, 2011 Share Posted July 17, 2011 wow, I have to give this a try, looking at your example, I see how far I am from getting anywhere near this, Thank you so much Eukalyptus! Link to comment Share on other sites More sharing options...
Andreik Posted July 18, 2011 Share Posted July 18, 2011 I saw this nice example in example folder of BASS-UDF v10, see link above by eukalyptus. This is the code: expandcollapse popup#AutoIt3Wrapper_UseX64=n #include "Bass.au3" #include "BassMix.au3" #include "BassFX.au3" Opt("GUIOnEventMode", 1) $iFreq_Lo = 500; Hz $iFreq_Hi = 5000; Hz HotKeySet("{ESC}", "_Exit") $hGui = GUICreate("BassMix/FX Test", 200, 100) GUISetOnEvent(-3, "_EXIT") $hCB_Lo = GUICtrlCreateCheckbox("Play Low Frequency", 10, 10, 180, 20) GUICtrlSetState(-1, 1) GUICtrlSetOnEvent(-1, "_Enable") $hCB_Mi = GUICtrlCreateCheckbox("Play Mid Frequency", 10, 40, 180, 20) GUICtrlSetState(-1, 1) GUICtrlSetOnEvent(-1, "_Enable") $hCB_Hi = GUICtrlCreateCheckbox("Play High Frequency", 10, 70, 180, 20) GUICtrlSetState(-1, 1) GUICtrlSetOnEvent(-1, "_Enable") GUISetState() $sFile = FileOpenDialog("Open...", "..\audiofiles", "playable formats (*.MP3;*.MP2;*.MP1;*.OGG;*.WAV;*.AIFF;*.AIF)") _BASS_Startup() _BASS_MIX_Startup() _BASS_FX_Startup() _BASS_Init(0, -1, 44100, 0, "") $hStream = _BASS_StreamCreateFile(False, $sFile, 0, 0, $BASS_STREAM_DECODE) $hSplit_Lo = _BASS_Split_StreamCreate($hStream, $BASS_STREAM_DECODE, 0) $hLFX_Lo = _BASS_ChannelSetFX($hSplit_Lo, $BASS_FX_BFX_BQF, 1) _BASS_FXSetParameters($hLFX_Lo, $BASS_BFX_BQF_LOWPASS & "|" & $iFreq_Lo & "|0|1|0|0|" & $BASS_BFX_CHANALL) $hSplit_Mi = _BASS_Split_StreamCreate($hStream, $BASS_STREAM_DECODE, 0) $hLFX_MiLo = _BASS_ChannelSetFX($hSplit_Mi, $BASS_FX_BFX_BQF, 1) _BASS_FXSetParameters($hLFX_MiLo, $BASS_BFX_BQF_HIGHPASS & "|" & $iFreq_Lo & "|0|1|0|0|" & $BASS_BFX_CHANALL) $hLFX_MiHi = _BASS_ChannelSetFX($hSplit_Mi, $BASS_FX_BFX_BQF, 1) _BASS_FXSetParameters($hLFX_MiHi, $BASS_BFX_BQF_LOWPASS & "|" & $iFreq_Hi & "|0|1|0|0|" & $BASS_BFX_CHANALL) $hSplit_Hi = _BASS_Split_StreamCreate($hStream, $BASS_STREAM_DECODE, 0) $hLFX_Hi = _BASS_ChannelSetFX($hSplit_Hi, $BASS_FX_BFX_BQF, 1) _BASS_FXSetParameters($hLFX_Hi, $BASS_BFX_BQF_HIGHPASS & "|" & $iFreq_Hi & "|0|1|0|0|" & $BASS_BFX_CHANALL) $aInfo = _BASS_ChannelGetInfo($hStream) $hMixer = _BASS_Mixer_StreamCreate($aInfo[0], $aInfo[1], 0) _BASS_Mixer_StreamAddChannel($hMixer, $hSplit_Lo, 0) _BASS_Mixer_StreamAddChannel($hMixer, $hSplit_Mi, 0) _BASS_Mixer_StreamAddChannel($hMixer, $hSplit_Hi, 0) _BASS_ChannelPlay($hMixer, True) While _BASS_ChannelIsActive($hMixer) Sleep(10) WEnd _Exit() Func _Enable() Switch @GUI_CtrlId Case $hCB_Lo If GUICtrlRead($hCB_Lo) = 1 Then _BASS_ChannelSetAttribute($hSplit_Lo, $BASS_ATTRIB_VOL, 1) Else _BASS_ChannelSetAttribute($hSplit_Lo, $BASS_ATTRIB_VOL, 0) EndIf Case $hCB_Mi If GUICtrlRead($hCB_Mi) = 1 Then _BASS_ChannelSetAttribute($hSplit_Mi, $BASS_ATTRIB_VOL, 1) Else _BASS_ChannelSetAttribute($hSplit_Mi, $BASS_ATTRIB_VOL, 0) EndIf Case $hCB_Hi If GUICtrlRead($hCB_Hi) = 1 Then _BASS_ChannelSetAttribute($hSplit_Hi, $BASS_ATTRIB_VOL, 1) Else _BASS_ChannelSetAttribute($hSplit_Hi, $BASS_ATTRIB_VOL, 0) EndIf EndSwitch EndFunc ;==>_Enable Func _Exit() _BASS_ChannelStop($hMixer) _BASS_Free() Exit EndFunc ;==>_Exit What I want is to use instead of $hStream = _BASS_StreamCreateFile(False, $sFile, 0, 0, $BASS_STREAM_DECODE) a stream already created but without $BASS_STREAM_DECODE, like this: $hStream = _BASS_StreamCreateFile(False, $sFile, 0, 0, 0) Is this possible? When the words fail... music speaks. Link to comment Share on other sites More sharing options...
eukalyptus Posted July 19, 2011 Share Posted July 19, 2011 Hmm... I don´t know how to explain If you use a stream, that get it´s samples from another stream, then the source-stream has to be a decoding-channel only "top-level-streams" are non-decoding e.g.: $hStream = _BASS_StreamCreateFile(False, $sFile, 0, 0, $BASS_STREAM_DECODE) $hTempo = _BASS_FX_TempoCreate($hStream, $BASS_SAMPLE_LOOP) _BASS_ChannelPlay($hTempo, 1) $hTempo is playing and gets the sampledata from $hStream, so $hStream has to be a decoding-channel, otherwise not all of it´s samples would reach $hTempo If you want to add a tempo effect to the example above, the tempo-stream has to be a decoding-channel too! $hStream -> $hTempo -> $hSplit $hSplit is playing, reading the samples from $hTempo and $hTempo is reading from $hStream What do you want to do? maybe there is another solution it´s possible to read the samples from the source (non decoding) stream and put to another - see _Bass_ChannelGetData and _Bass_StreamPutData E DirectSound UDF Direct2D UDF Link to comment Share on other sites More sharing options...
Andreik Posted July 19, 2011 Share Posted July 19, 2011 I have created a MP3 player using bass.dll functions but after I saw so nice examples I want to make it more nice by add the possiblity to play just low, middle or high freq. The problem is that my code it's now very complicated using a global variable that store the handle of playing stream. I was thining to use the same stream to not have to stop the main stream and create another one for this task but now I understand how things works and I will try to find a good solution for my project. Thanks for your help. When the words fail... music speaks. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now