BassBox insightYou will find under this post the latest patch:
bassbox_01.zip that is provided without any mp3 file.
This patch introduces new features like "
interprocess communication" (see below
WM_COPYDATA)
- Latest zskin.inc (skin engine source code compatible VISTA / XP)
- New AudioFX (add audio effects to BASS.dll from Ian Luck).
- BassBox.mp3 (royalty free mp3 for demo purpose).
Using BassBox- BassBox is an audio player compatible with 2000, XP, and VISTA.
- You can start it from the command line, providing the name of one or several audio files.
- It accepts an unlimited number of files, or folders, when using drag and drop from the Explorer.
- You can also drag file(s), or folders, directly onto the BassBox desktop shortcut if any, but then you are limited to the maximum lpCommand length size (something around 6000 bytes).
- Use left and right arrow buttons to navigate the audio list (when multiple audio files are being used).
- The Play button, starts playing or resume from pause, the "Pause" button pauses audio.
- The VOL trackbar allows to setup the "local" application's audio volume.
- DirectSound audio effects: reverberation, chorus, flanger, echo, sound rotation.
BASS.DLLAll the details about this fantastic audio library, from
Ian Luck, can be found there:
www.un4seen.comWM_COPYDATAThis message is very handy when you need to perform "interprocess communication",
zskin.inc has two new functions,
zSendPrivateMsg and
zGetPrivateMsg, for this purpose:
TYPE COPYDATASTRUCT
dwData AS DWORD
cbData AS DWORD
lpData AS DWORD
END TYPE
%ZM_STRINGDATA = 0
FUNCTION zSendPrivateMsg(BYVAL hFound AS LONG, BYVAL UseMsg AS LONG, BYVAL sBuff AS STRING) AS LONG
LOCAL cds AS COPYDATASTRUCT, LenBuff AS LONG
LenBuff = LEN(sBuff)
REDIM Buf(LenBuff) AS BYTE
POKE$ VARPTR(Buf(0)), sBuff
cds.dwData = UseMsg
cds.cbData = UBOUND(Buf) - LBOUND(Buf) + 1
cds.lpData = VARPTR(Buf(0))
FUNCTION = SendMessage(hFound, %WM_COPYDATA, LenBuff, VARPTR(cds))
END FUNCTION
FUNCTION zGetPrivateMsg(BYREF sPrivateMsg AS STRING, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
LOCAL cds AS COPYDATASTRUCT
REDIM Buf(wParam) AS BYTE
CALL MoveMemory(cds, BYVAL lParam, SIZEOF(cds))
CALL MoveMemory(buf(0), BYVAL cds.lpData, cds.cbData)
sPrivateMsg = PEEK$(VARPTR(buf(0)), wParam)
FUNCTION = cds.dwData
END FUNCTION
and the
WM_COPYDATA that must be handled into the main winproc:
CASE %WM_COPYDATA
' wParam holds the string length
' lParam holds the Byte array address
dwData = zGetPrivateMsg(sDataString, wParam, lParam)
IF dwData = %ZM_STRINGDATA THEN
IF LEN(sDataString) THEN
nCount = PARSECOUNT(sDataString, $zLim)
hList = zGetMainItem(%ID_PlayList)
CALL ListDeleteAll(hList)
FOR K = 1 TO nCount
ListAdd(hList, PARSE$(sDataString, $zLim, K))
NEXT
CALL ListSelectPlus(hList, 1)
gzAudioFile = ListGetText(hList, 1)
CALL BassChannelPlay()
IF nCount > 1 THEN
CALL EnableWindow(zGetMainItem(%ID_LEFTBUTTON), %TRUE)
CALL zUpdateWindow(zGetMainItem(%ID_LEFTBUTTON), 0)
CALL EnableWindow(zGetMainItem(%ID_RIGHTBUTTON), %TRUE)
CALL zUpdateWindow(zGetMainItem(%ID_RIGHTBUTTON), 0)
ELSE
CALL EnableWindow(zGetMainItem(%ID_LEFTBUTTON), %FALSE)
CALL zUpdateWindow(zGetMainItem(%ID_LEFTBUTTON), 0)
CALL EnableWindow(zGetMainItem(%ID_RIGHTBUTTON), %FALSE)
CALL zUpdateWindow(zGetMainItem(%ID_RIGHTBUTTON), 0)
END IF
END IF
END IF
FUNCTION = 1: EXIT FUNCTION
OpenGLThis demo uses OpenGL to render graphicaly the stereo audio levels, everything is embedded into the provided source code (no need to use a third party OpenGL addon).
If you try it with VISTA you will see absolutly no difference with DirectX, performances are the same despite what some people say over the NET.
All the hard stuff to decode the audio channel is done there:
'// Init the color array
SUB ColorInit()
DIM gColor(1 TO 33) AS LONG
gColor(1) = RGB(32,32,32)
gColor(2) = RGB(0,44,233)
gColor(3) = RGB(0,67,210)
gColor(4) = RGB(0,89,187)
gColor(5) = RGB(0,112,164)
gColor(6) = RGB(0,135,142)
gColor(7) = RGB(0,159,117)
gColor(8) = RGB(0,183,88)
gColor(9) = RGB(0,207,58)
gColor(10) = RGB(0,231,29)
gColor(11) = RGB(26,234,26)
gColor(12) = RGB(52,237,23)
gColor(13) = RGB(79,240,20)
gColor(14) = RGB(105,243,17)
gColor(15) = RGB(126,245,14)
gColor(16) = RGB(147,248,11)
gColor(17) = RGB(168,250,8)
gColor(18) = RGB(189,253,5)
gColor(19) = RGB(210,255,2)
gColor(20) = RGB(233,255,0)
gColor(21) = RGB(255,255,0)
gColor(22) = RGB(255,251,0)
gColor(23) = RGB(255,235,0)
gColor(24) = RGB(255,215,0)
gColor(25) = RGB(255,196,0)
gColor(26) = RGB(255,176,0)
gColor(27) = RGB(255,156,0)
gColor(28) = RGB(253,137,0)
gColor(29) = RGB(255,117,0)
gColor(30) = RGB(255,97,0)
gColor(31) = RGB(255,78,0)
gColor(32) = RGB(255,58,0)
gColor(33) = RGB(255,0,0)
END SUB
FUNCTION LevelColr(BYVAL nLevel AS LONG) AS LONG
LOCAL nColor AS LONG
nLevel = nLevel + 1: IF nLevel > 33 THEN nLevel = 33
nColor = 0: IF nLevel > 0 THEN nColor = gColor(nLevel)
FUNCTION = nColor
END FUNCTION
FUNCTION SolvePeak(BYVAL nValue AS LONG, BYVAL nTotal AS LONG) AS LONG
LOCAL nRet AS LONG
nRet = 0: IF nTotal THEN nRet = (nValue * 100) / nTotal
FUNCTION = nRet
END FUNCTION
FUNCTION BassChannelGetLevel () AS LONG
LOCAl nRet AS LONG
IF gnAudioPause = %FALSE THEN
IF gnAudioChannel THEN
nRet = BASS_ChannelGetLevel(gnAudioChannel)
END IF
END IF
FUNCTION = nRet
END FUNCTION
and the OpenGL drawing is done there:
SUB RenderOpenGL(BYVAL glCtrl AS LONG)
LOCAL nLevel, nLValue, nRValue, glDC, RGBColor AS LONG
LOCAL pulse AS DOUBLE, R1, G1, B1, R2, G2, B2 AS BYTE
STATIC rXangle, rYangle, rZangle AS DOUBLE
glDC = GetDC(glCtrl)
IF glRC THEN
nLevel = BassChannelGetLevel()
nLValue = (SolvePeak(LO(WORD, nLevel), 128) / 700)
nRValue = (SolvePeak(HI(WORD, nLevel), 128) / 768)
rXangle = rXangle + 0.3 '// grDXangle
rYangle = rYangle + 0.5 '// grDYangle
rZangle = rZangle + 0.7 '// grDZangle
pulse = MAX(nLValue, nRValue) / 7
'// Pulsating section
CALL glMatrixMode(%GL_PROJECTION)
CALL glLoadIdentity()
CALL gluPerspective(35.0 - pulse, 1.25, 0.1, 150.0)
CALL glMatrixMode(%GL_MODELVIEW)
'// Velocity section
pulse = ABS(pulse / 4)
rXangle = rXangle + pulse '// grDXangle
rYangle = rYangle + pulse '// grDYangle
rZangle = rZangle + pulse '// grDZangle
'// Very important we must reassign glRC to the new glDC
'// Note: don't use permanent DC, this produce better and smoother display
CALL wglMakeCurrent(glDC, glRC)
CALL glClear(%GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT)
CALL glLoadIdentity()
CALL gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
CALL glRotated(rXangle, 1.0, 0.0, 0.0)
CALL glRotated(rYangle, 0.0, 1.0, 0.0)
CALL glRotated(rZangle, 0.0, 0.0, 1.0)
'// Draw Diamond
RGBColor = LevelColr(nLValue)
R2 = zGetRValue(RGBColor)
G2 = zGetGValue(RGBColor)
B2 = zGetBValue(RGBColor)
RGBColor = LevelColr(nRValue)
R1 = zGetRValue(RGBColor)
G1 = zGetGValue(RGBColor)
B1 = zGetBValue(RGBColor)
'//Up
CALL glBegin(%GL_TRIANGLE_FAN)
CALL glColor3ub( R2, G2, B2): CALL glVertex3d( 0.0, 1.414, 0.0)
CALL glColor3ub( R1, G1, B1): CALL glVertex3d( 1.0, 0.0, 1.0)
CALL glColor3ub( 0, 0, 0): CALL glVertex3d( 1.0, 0.0,-1.0)
CALL glColor3ub( R1, G1, B1): CALL glVertex3d(-1.0, 0.0,-1.0)
CALL glColor3ub( 0, 0, 0): CALL glVertex3d(-1.0, 0.0, 1.0)
CALL glColor3ub( R1, G1, B1): CALL glVertex3d( 1.0, 0.0, 1.0)
CALL glEnd()
'//Down
CALL glBegin( %GL_TRIANGLE_FAN)
CALL glColor3ub( R2, G2, B2): CALL glVertex3d( 0.0,-1.414, 0.0)
CALL glColor3ub( R1, G1, B1): CALL glVertex3d( 1.0, 0.0, 1.0)
CALL glColor3ub( 64, 64, 64): CALL glVertex3d(-1.0, 0.0, 1.0)
CALL glColor3ub( R1, G1, B1): CALL glVertex3d(-1.0, 0.0,-1.0)
CALL glColor3ub( 64, 64, 64): CALL glVertex3d( 1.0, 0.0,-1.0)
CALL glColor3ub( R1, G1, B1): CALL glVertex3d( 1.0, 0.0, 1.0)
CALL glEnd()
'//Refresh display
CALL SwapBuffers(glDC)
CALL zUpdateWindow(glCtrl, 0)
END IF
CALL ReleaseDC(glCtrl, glDC)
END SUB
When used on
VISTA it is very important to perform a
zUpdateWindow after
SwapBuffers to force
DWM to refresh its internal buffer (or the OpenGL display seems to crawl).
'//Refresh display
CALL SwapBuffers(glDC)
CALL zUpdateWindow(glCtrl, 0)Smooth animationI am using my TIMER technic to perform smooth animation
without using the common message pump that hogs the CPU:
CALL SetTimer(hMain, %OPENGL_TIMER, 0, %NULL) WHILE GetMessage(Msg, %NULL, 0, 0) ' SK_MILLISECOND
IF IsDialogMessage(hMain, Msg) = %FALSE THEN
CALL TranslateMessage(Msg)
CALL DispatchMessage(Msg)
END IF
WEND
CALL KillTimer(hMain, %OPENGL_TIMER) Patrice Terrier
www.zapsolution.com