Page 1 of 1

Long splitting into signed hiword and loword (FMOD DSP unit)

Posted: Sat Jul 12, 2003 12:21 am
by Thorsten
Hello ...

How can I split a signed long into two signed .w (words)?

This procedure's from Danilo do it unsigned:

Code: Select all

Procedure LOWORD(Value) 
  ProcedureReturn Value & $FFFF 
EndProcedure 

Procedure HIWORD(Value) 
  ProcedureReturn (Value >> 16) & $FFFF 
EndProcedure 

Procedure MAKELONG(low, high)
  ProcedureReturn low | (high<<16) 
EndProcedure 
How are this three but with signed word's?
Unsigned: 0 to 65535
Signed: -32767 to +32768

Posted: Sat Jul 12, 2003 4:33 pm
by matthew180
I'm guessing that no one has replied to you because they can't figure out exactally what you want to do, myself included.

You understand that a 'long' is 32-bits, right? And that the sign-bit is bit 31 (most significate bit.) And the only difference between a signed and unsigned number is that the language looks at bit-31 to represent + or -.

So, if you split a signed long (32-bits) into words (16-bit each), what happens to the sign? By default it will stay with the word that was made from bits 16-31 (high word), but what about the word that is made from bits 0-15 (low word)? If you apply the sign from bit-31 to bit-15, then you might change the value of the the low word... So, if you change the value, then you lose anything achieved by splitting the 32-bit long. Eample:

+2,000,000,000 = 01110111001101011001010000000000

Split that in half and you get:

+30,517 = 0111011100110101 (High word, positive sign like the original long)
-5,120 = 1001010000000000 (Low word, considered negative because bit-15 is a '1')

You could change bit-15 of the low word and make it +5,120, but even 5,120 is not the value of what the low-16 bits of the original 32-bit number was. For that you would have to treat the low word as an unsigned number, which would be +37,888.

So, what this all comes down to is, what exactally are you trying to do by splitting a 32-bit signed long into two 16-bit words?

Matthew

Posted: Sat Jul 12, 2003 5:50 pm
by Thorsten
Hmmm okay :(

I want to write my own DSP (Digital Signal Processing) - Unit for FMOD.
FMOD --> http://www.fmod.org

Inside each DSP unit I get from the FMOD system a pointer to a
sound buffer with 1024 samples / 25 ms :idea:

I must divide each sample into a left and right audio channel...

Here a little example:

Code: Select all

Procedure.l Lowpass(ptOriginalbuffer.l, ptNewbuffer.l, Length.l, Param.l) 
  
  Protected ptNewbuffer 
  Protected ptOriginalbuffer 
  Protected Length 
  Protected Param 
    
  Dim Daten.l(Length) 
  CopyMemory(ptNewbuffer, @Daten(), 4 * Length) 
  
    
  For Counter = 0 To Length - 1 
    
    Debug Daten(Counter) 
      
  Next Counter 
    
  ProcedureReturn @Daten() 
  
EndProcedure 
And now, I want to divide - like this: (inside the For - Next loop)

Code: Select all

    ;========================================= 
    ;Divide the data to left and right channel 
    ;========================================= 
    Left = LOWORD(Daten(Counter)) 
    Right = HIWORD(Daten(Counter))    
And after do something with it - combine:

Code: Select all

    ;===================== 
    ;Combine the channels 
    ;===================== 
    Daten(Counter) = MAKELONG(Left, Right)

But with the procedure's by Danilo (see at top) I get for left and
right only numbers > 0 ... but can you play a sine without numbers < 0? :wink:

You want a complete example? Get first the DLL for PureBasic here:
http://www.fmod.de/files/fmod363stdcall.zip

Then use this code I have made:

Code: Select all

Declare MAKELONG(low, high)
Declare HIWORD(Value) 
Declare LOWORD(Value) 
Declare Unload()
Declare Stop()
Declare.l Lowpass(ptOriginalbuffer.l, ptNewbuffer.l, Length.l, Param.l)
Declare FFT() 

Global Volume.l
Global Quit.l
Global Play.l
Global Stream_ID.l
Global LowPassID.l
Global FFTFrequenz.l
Global Wert.l

Volume = 25
Wert = 2000
Quit = #False
Play = #False
Pause.l = #False
FFT_ID.l = #Null
Stream_ID = #Null
LowPassID = #Null
FFTUnit_ID.l = #Null
LowpassUnit_ID.l = #Null
Temp.s = ""
FFTFrequenz = 30

Soundfile.s = ""

Structure fftarray 
  Value.f[512] 
EndStructure

If OpenWindow(1,0,0,520,350,#PB_Window_SystemMenu|#PB_Window_ScreenCentered, "FMOD FFT-Spectrum Visualization") <> #False
  
  If FSOUND_SetBufferSize(125) <> #False
    If FSOUND_Init(44100, 32, 0) <> #False
      If CreateMenu(1, WindowID(1)) <> #False And CreateGadgetList(WindowID(1)) <> #False
        MenuItem(1, "Open") 
        MenuItem(2, "Play") 
        MenuItem(3, "Stop")    
        MenuItem(4, "Pause")
        OpenSubMenu("Spectrum Analyzer")
        OpenSubMenu("Frequenz") 
        MenuItem(5, "10 Hz")
        MenuItem(6, "30 Hz")
        MenuItem(7, "50 Hz")
        MenuItem(8, "70 Hz")
        MenuItem(9, "90 Hz")
        CloseSubMenu()
        CloseSubMenu()
        
        SetMenuItemState(1, 6, #True)
        
        CreateImage(1, 513, 201)
        
        TrackBarGadget(1, 4, 215, 513, 20, 0, 255)
        TrackBarGadget(2, 4, 245, 513, 20, 0, 5000)
        TrackBarGadget(3, 4, 275, 513, 20, 1, 2000)
        SetGadgetState(1, Volume) 
        SetGadgetState(3, 2000)
        
        FFT_ID = CreateThread(@FFT(), #Null)
        
        If FFT_ID <> 0
          
          Repeat 
            Event = WaitWindowEvent() 
            
            Select Event  
              Case #PB_EventMenu 
                
                Select EventMenuID() 
                  Case 1 ;(Open) 
                    
                    Stop()
                    
                    Temp = OpenFileRequester("", "c:\music\club\", "Music (*.mp3, *.wav, *.mp2, *.ogg, *.raw)|*.mp3;*.wav;*.mp2;*.ogg;*.raw|*.*|*.*", #Null, #Null)
                    
                    If Temp <> ""
                      Soundfile = Temp 
                    EndIf 
                    
                  Case 2 ;(Play) 
                    
                    Stream_ID = FSOUND_Stream_OpenFile(Soundfile, 0, 0) ;open the soundfile 
                    
                    If Stream_ID <> 0
                      
                      FFTUnit_ID = FSOUND_DSP_GetFFTUnit()
                      FSOUND_DSP_SetActive(FFTUnit_ID, #True) ;activate the FastFourierTransformation-DSP-Unit  
                      
                      LowpassUnit_ID = FSOUND_DSP_Create(@Lowpass(), FSOUND_DSP_GetPriority(FFTUnit_ID) - 1, #Null)
                      FSOUND_DSP_SetActive(LowpassUnit_ID, #True)
                      
                      FSOUND_Stream_Play(1, Stream_ID) ;play the stream on channel 1
                      Play = #True
                      
                      ;Lautstärke setzen 
                      FSOUND_SetVolume(1, GetGadgetState(1))
                    EndIf 
                    
                  Case 3 ;(Stop)  
                    Stop()
                    
                  Case 4 ;(Pause)
                    If Pause <> #True
                      FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream 
                      Play = #False
                      Pause = #True
                      
                      FSOUND_DSP_SetActive(FFTUnit_ID, #False)
                      FSOUND_DSP_SetActive(LowpassUnit_ID, #False)
                      FSOUND_DSP_Free(LowpassUnit_ID) 
                    Else 
                      If Stream_ID <> 0
                        
                        Pause = #False
                        
                        FFTUnit_ID = FSOUND_DSP_GetFFTUnit()
                        FSOUND_DSP_SetActive(FFTUnit_ID, #True) ;activate the FastFourierTransformation-DSP-Unit  
                        
                        LowpassUnit_ID = FSOUND_DSP_Create(@Lowpass(), FSOUND_DSP_GetPriority(FFTUnit_ID) - 1, #Null)
                        FSOUND_DSP_SetActive(LowpassUnit_ID, #True)
                        
                        FSOUND_Stream_Play(1, Stream_ID) ;play the stream on channel 1
                        Play = #True
                        
                        ;Lautstärke setzen 
                        FSOUND_SetVolume(1, GetGadgetState(1))
                        
                        ;Position setzen
                        FSOUND_Stream_SetPosition(Stream_ID, Int((FSOUND_Stream_GetLength(Stream_ID) / 5000) * GetGadgetState(2)))
                        
                      EndIf 
                    EndIf 
                    
                  Case 5
                    FFTFrequenz = 10
                    SetMenuItemState(1, 5 ,#True)
                    SetMenuItemState(1, 6 ,#False)
                    SetMenuItemState(1, 7 ,#False)
                    SetMenuItemState(1, 8 ,#False)
                    SetMenuItemState(1, 9 ,#False)
                    
                  Case 6
                    FFTFrequenz = 30
                    SetMenuItemState(1, 5 ,#False)
                    SetMenuItemState(1, 6 ,#True)
                    SetMenuItemState(1, 7 ,#False)
                    SetMenuItemState(1, 8 ,#False)
                    SetMenuItemState(1, 9 ,#False)
                    
                  Case 7
                    FFTFrequenz = 50
                    SetMenuItemState(1, 5 ,#False)
                    SetMenuItemState(1, 6 ,#False)
                    SetMenuItemState(1, 7 ,#True)
                    SetMenuItemState(1, 8 ,#False)
                    SetMenuItemState(1, 9 ,#False)
                    
                  Case 8 
                    FFTFrequenz = 70
                    SetMenuItemState(1, 5 ,#False)
                    SetMenuItemState(1, 6 ,#False)
                    SetMenuItemState(1, 7 ,#False)
                    SetMenuItemState(1, 8 ,#True)
                    SetMenuItemState(1, 9 ,#False)
                    
                  Case 9
                    FFTFrequenz = 90
                    SetMenuItemState(1, 5 ,#False)
                    SetMenuItemState(1, 6 ,#False)
                    SetMenuItemState(1, 7 ,#False)
                    SetMenuItemState(1, 8 ,#False)
                    SetMenuItemState(1, 9 ,#True)
                    
                EndSelect 
                
              Case #PB_Event_Gadget
                Select EventGadgetID()
                  Case 1
                    If Play <> #False
                      ;Lautstärke setzen 
                      FSOUND_SetVolume(1, GetGadgetState(1))
                    EndIf
                    
                  Case 2
                    If Play <> #False
                      ;Position ändern 
                      FSOUND_Stream_SetPosition(Stream_ID, Int((FSOUND_Stream_GetLength(Stream_ID) / 5000) * GetGadgetState(2)))
                    EndIf
                    
                  Case 3
                    Wert = GetGadgetState(3)
                    
                EndSelect
                
              Case #PB_Event_CloseWindow
                Unload()
                
              Case #WM_QUIT
                Unload()
                
            EndSelect   
          Until Quit <> #False
        EndIf
      EndIf
    EndIf
  EndIf
EndIf 
End

Procedure FFT() 
  
  Protected TimeStart.l
  Protected Time.l
  Protected hfft.fftarray
  Protected x.l
  Protected y.l
  Protected Value.f
  Protected Color.l 
  Protected Periodendauer.l
  
  Repeat 
    
    If Play <> #False And FSOUND_DSP_GetActive(FSOUND_DSP_GetFFTUnit()) <> 0
      
      TimeStart = GetTickCount_() 
      
      Periodendauer = Int((1 / FFTFrequenz) * 1000) 
      CopyMemory(FSOUND_DSP_GetSpectrum(), hfft, 4*512) 
      
      UseImage(1) 
      StartDrawing(ImageOutput()) 
      
      For i = 0 To 511 Step 4
        Value = 199 - Pow(0.0000001, hfft\Value[i]) * 199 
        
        ;Jeder der 512 Frequenzen kann sich von 0 bis 200 erstrecken
        ;Jeder "Block" ist 5 Pixel hoch, deshalb in 5er Schritten
        For y = 0 To 200 Step 5
          
          ;Die Farbe für jeden 5er Schritt berechnen
          ;Formel by Froggerprogger
          Color = (255 - y) * $000100 + y * $000001
          
          ;Wenn der aktuelle "Block" aktiv ist
          If Value > y 
            
            ;Den Block mit der dynamischen Farbe füllen  
            Box(i + 1, 200 - y, 3, 6, Color)
            
          ;ist der "Block" leer, ...
          ElseIf actfftvalue < y
            
            ;... muss er mit grauer Farbe gefüllt werden
            Box(i + 1, 205 - y, 3, y - 200, RGB($B0,$CF,$F4))
            y = 200
            
          EndIf 
          
        ;Next block
        Next y
        
      ;Next Frequenz
      Next i
      
      StopDrawing()
      
      UseWindow(1)
      StartDrawing(WindowOutput())
      DrawImage(UseImage(1), 4, 10)
      StopDrawing()
      
      ;Positionen berechnen 
      SetGadgetState(2, Int((FSOUND_Stream_GetPosition(Stream_ID) / FSOUND_Stream_GetLength(Stream_ID)) * 5000))
      
      If FSOUND_Stream_GetPosition(Stream_ID) = FSOUND_Stream_GetLength(Stream_ID)
        
        FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream 
        Play = 0
        
        FSOUND_DSP_Free(LowpassUnit_ID)
        FSOUND_DSP_Free(FFTUnit_ID)
        
        SetGadgetState(2, 1)
      EndIf
      
      Time = Int(Periodendauer - (GetTickCount_() - TimeStart))
      If Time > 0 And Time < Periodendauer
        Delay(Time)
      EndIf 
      
    Else
      
      ;Wenn keine Musik aktiv ist
      
      UseImage(1) 
      StartDrawing(ImageOutput()) 
      Box(0, 0, 512, 200)
      
      For i = 0 To 511 Step 4 
        Box(i + 1, 0, 3, 201, RGB($B0,$CF,$F4))
      Next i
      
      StopDrawing()
      
      UseWindow(1)
      StartDrawing(WindowOutput())
      DrawImage(UseImage(1), 4, 10)
      StopDrawing()
      
      Delay(50)
      
    EndIf 
  Until Quit = #True 
EndProcedure 

Procedure.l Lowpass(ptOriginalbuffer.l, ptNewbuffer.l, Length.l, Param.l)
  
  Protected ptNewbuffer
  Protected ptOriginalbuffer
  Protected Length
  Protected Param
  
  Protected Counter.l
  Protected Left.l
  Protected Right.l 
  
  Dim Daten.l(Length)
  CopyMemory(ptNewbuffer, @Daten(), 4 * Length) 
  
  For Counter = 0 To Length - 1 
    Debug Daten(Counter) 
  Next Counter 
  
  ProcedureReturn @Daten()
  
EndProcedure

Procedure Stop()
  
  Shared Stream_ID, Volume, Play, FFTUnit_ID, LowpassUnit_ID 
  
  ;Fadeout
  For i = Volume To 0 Step -1 ;a small fast fade-out to prevent a clipping-sound 
    FSOUND_SetVolume(1, i)
    Delay(5)
  Next 
  
  FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream 
  Play = #False
  
  FSOUND_DSP_SetActive(FFTUnit_ID, #False)
  FSOUND_DSP_SetActive(LowpassUnit_ID, #False)
  FSOUND_DSP_Free(LowpassUnit_ID)  
  
  SetGadgetState(2, 1)
EndProcedure

Procedure Unload()
  Quit = #True 
  WaitThread(FFT_ID) 
  
  FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream 
  FSOUND_DSP_SetActive(FFTUnit_ID, #False) ;set the FFT-DSP-Unit inactive 
  FSOUND_DSP_SetActive(LowpassUnit_ID, #False)
  FSOUND_DSP_Free(LowpassUnit_ID)
  FSOUND_Close() ;shut down FSOUND  
EndProcedure

Procedure LOWORD(Value) 
  ProcedureReturn Value & $FFFF 
EndProcedure 

Procedure HIWORD(Value) 
  ProcedureReturn (Value >> 16) & $FFFF 
EndProcedure 

Procedure MAKELONG(low, high)
  ProcedureReturn low | (high<<16) 
EndProcedure
Ohh - sorry, but some comments inside the code wrote at german,
because english is not my natural speech :wink: But the main
thing, the lowpass callback are in english...

The first TrackBarGadget are the volume and the 2. are the position
at the song. The 3. for some testing ... and later for the cutoff frequency :wink:

Posted: Sun Jul 13, 2003 11:32 am
by Thorsten
Okay - I have done it myself :roll:

Here the three procedure's - with signed word's:

Code: Select all

Procedure.w LOWORD(Value.l) 
  ProcedureReturn Value & $FFFF  
EndProcedure 

Procedure.w HIWORD(Value.l) 
  ProcedureReturn (Value >> 16) & $FFFF 
EndProcedure 

Procedure MAKELONG(low.w, high.w) 
  ProcedureReturn (high * $10000) | (low & $FFFF)
EndProcedure 
Very simple 8)