FmodEx Frage

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

FmodEx Frage

Beitrag von Grillmeister »

Hallo zusammen !

Ich hoffe Ihr könnt mir helfen:
Ich versuche gerade von Fmod auf FmodEx umzusteigen.

Beim "alten" Fmod gab es eine schöne Funktion zum Bau eines Levelmeters. Die nannte sich: "FSOUND_GetCurrentLevels"
Beschreibung: "Returns a left and right VU/Level reading at the current position of the specified channel.
Levels are are only supported for software channels."

Beim FmodEx kann ich eine solche Funktion aber nicht finden :|
Muss ich mir das da echt aus der Funktion "FMOD_Channel_GetSpectrum" herausfriemeln, oder gibt es da auch eine andere Möglichkeit?

Danke und Gruß
Grillmeister
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Musste auch grad ne Weile suchen, aber das hier könnte es sein:
Channel::getAudibility
Returns the combined volume of the channel after 3d sound, volume, channel group volume and geometry occlusion calculations have been performed on it.
Sonst vielleicht auch (recht umständlich, aber mächtiger) per
Channel::getWaveData
Retrieves a pointer to a block of PCM data that represents the currently playing waveform on this channel. This function is useful for a very easy way to plot an oscilliscope.
!UD2
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

Beitrag von Grillmeister »

Danke für die Tips.
Channel::getAudibility
kommt nicht in Frage, da ich bei einem Levelmeter gerne den rechten und den linken Kanal getrennt anzeigen lassen möchte.
Channel::getWaveData
Ja, das ist in der Tat recht umständlich - aber anscheinend die einzige Möglichkeit das irgendwie umzusetzen (das war mit dem alten FMOD doch erheblich simpler - aber einfach kann ja jeder :wink: )
Muss mal ein wenig rumprobieren...
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

Beitrag von Grillmeister »

@Froggerprogger: Wenn ich die getWaveData Funktion benutze, meldet mir Purebasic einen IMA in Deiner Include:
ProcedureReturn CallFunction(fmodLib, "FMOD_Channel_GetWaveData", channel.l, *Wavearray.f, Numvalues.l, Channeloffset.l)
Die Include-Datei ist die:
FMODEX-include for fmodex 4.06.06...by Froggerprogger, 27.02.2007
Meine Purebasic-Version ist die 4.30.

Hier mal der Code den ich zum Testen der Funktion benutzt habe:

Code: Alles auswählen

IncludeFile "fmodex.pb"

Init_FMOD()

FMOD_System_Create(@fmodsystem)
FMOD_System_Init(fmodsystem, 32, 0, 0)

str.s = OpenFileRequester("Choose a soundfile", "", "*.*|*.*", 0)


FMOD_System_CreateStream(fmodsystem, @str, #FMOD_SOFTWARE, 0, @sound)
FMOD_System_PlaySound(fmodsystem, 0, sound, 0, @channel)

Dim Arr.f(512)

If OpenConsole()
    PrintN("Druecke Escape zum Beenden.")

Repeat

  KeyPressed$ = Inkey()

   FMOD_Channel_IsPlaying(channel, @isPlaying)

   FMOD_Channel_GetWaveData(channel, Arr(512), 512, 0)
      
   Debug "Test-Level:" + StrF(Arr(0),2) + " " + StrF(Arr(1), 2)
   
  Delay(250)
Until KeyPressed$ = Chr(27) Or isPlaying = #False

EndIf

FMOD_System_Release(fmodsystem)
...schon eichelartig... :?
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Kanns grad nicht testen, aber

Code: Alles auswählen

FMOD_Channel_GetWaveData(channel, Arr(512), 512, 0) 
müsste falsch sein. Es wird die Adresse des Arraybeginns erwartet, also eher:

Code: Alles auswählen

FMOD_Channel_GetWaveData(channel, @Arr(0), 512, 0) 
Ist übrigens wohl wirklich die Art und Weise um an die 'Lautstärke' zu kommen: http://www.fmod.org/forum/viewtopic.php?t=10870

Für die Lautstärke kannst Du dann entweder (Absolut)Maximum oder Durchschnitt der (Absolut)werte nehmen, oder noch komplizierter für z.B. RMS-Pegel.
!UD2
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

Beitrag von Grillmeister »

Ja Cool, Du hast mir die Osterfeiertage gerettet :D
FMOD_Channel_GetWaveData(channel, @Arr(0), 512, 0)
Funktioniert super :allright:

Habe gerade in der Hilfe gesehen, dass dort sogar erwähnt ist, dass man diese Funktion benutzen soll:
Where is FSOUND_GetCurrentLevels?
Use System::getWaveData or Channel::getWaveData. It is far more flexible.
Naja, dass das flexibler ist, glaube ich schon - aber nicht wirklich leichter /:->

Jetzt muss ich mal schau`n wie ich die Werte anwenden kann.

Worin besteht eigentlich der Unterschied zwischen:
FMOD_Channel_GetWaveData
und:
FMOD_System_GetWaveData
?

Nochmals tausend Dank für Deine Hilfe und natürlich auch für die Include :allright:
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Der Unterschied ist die Stelle im 'Signalfluss', an der die Wave-Daten abgegriffen werden. System::getWaveData liefert den Endmix, also nach dem Zusammenmischen aller Channels.

Den RMS-Pegel erhälst Du als:
RMS := Sqrt(1/N * Summe(Samplewert^2)), also:

Code: Alles auswählen

N = 512
rms.f = 0
For i=0 to N-1
  rms = rms + (Arr(i)*Arr(i))
Next
rms = Sqrt(rms / N)
Der reagiert deutlich weicher, als das Peak-Meter (Absolutmaximum):

Code: Alles auswählen

peak.f = 0
For i=0 to N-1
  a.f = Abs(Arr(i))
  If a > peak
    peak = a
  EndIf
Next
Häufig sieht man in Anzeigen auch ein Peakmeter, das schnell zappelt, und darin eingezeichnet einen trägeren Strich auf Höhe des RMS-Pegels.

Und last but not least: So rechnest Du nach dB um (1.0 = 0 dB, 0.0 = -inf dB). Allgemein per [dB] = 10 * log_e(P1/P2) mit P1, P2 die beiden Vergleichswerte.

Code: Alles auswählen

For i=10 To 0 Step -1
  rms.f = 10 / i ; rms = 1.0, 0.9, ..., 0.0
  dB.f = 10*Log(1.0/rms) ; alternativ 10*Log(rms) für pos. Vorzeichen
  Debug dB  
Next
Dezibel eignet sich aufgrund der logarithmischen Stauchung besser für die Anzeige.
!UD2
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

Beitrag von Grillmeister »

Wow ! :allright:

Da habe ich jetzt ja was zum Probieren :)

Vielen lieben Dank nochmal und schöne Osterfeiertage !
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

Beitrag von Grillmeister »

Nabend !

Beim Levelmeter habe ich mich für die rms Ausgabe entschieden - das sieht für mich am "schönsten" aus und funktioniert prima :mrgreen:

Tja und schon bin ich beim nächsten Problem angekommen, das ich nicht so recht gelöst bekomme:

Beim "alten" Fmod gab es zum Auslesen der Metadaten eine schöne Callback-Funktion:

Code: Alles auswählen

FSOUND_Stream_Net_SetMetadataCallback
Diese gibt es so ähnlich auch in der neuen Version:

Code: Alles auswählen

FMOD_CODEC_METADATACALLBACK
Der Syntax sollte ungefähr so aussehen:

Code: Alles auswählen

FMOD_RESULT F_CALLBACK FMOD__FMOD_CODEC_METADATACALLBACK(
   *  ,
  FMOD_CODEC_STATE *  codec_state, 
  FMOD_TAGTYPE  type, 
  char *  name, 
  void *  data, 
  unsigned int  datalen, 
  FMOD_TAGDATATYPE  datatype, 
  int  unique
);

Wenn ich das richtig sehe, ist diese Funktion in Deiner Include nicht enthalten. Ich habe aber momentan (vielleicht liegt es auch an der Uhrzeit) absolut keinen Plan, wie ich sie direkt aufrufe.

Beim "alten" Fmod mit dem Wrapper sah der Code dafür so aus:

Code: Alles auswählen

Global artist.s, title.s
Global metanum.l

Procedure.l metacallback(name.l, value.l, userdata.l)
    m_lpstrValue.s = PeekS(name)
    If (m_lpstrValue = "ARTIST")
      artist = PeekS(value)
      ProcedureReturn #True     
    EndIf
   
    If (m_lpstrValue = "TITLE")
      title = PeekS(value)
      metanum + 1
      ProcedureReturn #True     
    EndIf
   
  ProcedureReturn #True
EndProcedure

FSOUND_Init(44100, 32, 0)
 
  hstream = FSOUND_Stream_Open("http://scfire-dll-aa03.stream.aol.com:80/stream/1040",0,0,0)
 
  If hstream <> 0
    FSOUND_Stream_Play(1,hstream)
  EndIf

hWnd=OpenWindow(0,-1,-1,200,25,"TAG-Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  CreateGadgetList(WindowID(0))
 
For i = 0 To 6

FSOUND_Stream_GetTagField(hstream, i, @type, @name, @titel, @length)

Debug "Inhalt: " + PeekS(titel)
Debug "Type: " + Str(type)
Debug "Name: " + PeekS(name)
Debug "Laenge:" + Str(length)

Next i

metanum.l = 0
 
Repeat

  FSOUND_Stream_Net_SetMetadataCallback(hstream, @metacallback(), 0)
 
   If (metanum)
     Debug "Titel: "+title
     Debug "Artist: "+artist           
     metanum = 0
   EndIf
   
  Delay(16)
Until WindowEvent()=#PB_Event_CloseWindow

CloseWindow(0)
FSOUND_Close()
End
Benutzeravatar
Grillmeister
Beiträge: 23
Registriert: 17.04.2008 09:54
Wohnort: Hannover
Kontaktdaten:

Beitrag von Grillmeister »

Nee, auch heute wo ich etwas "wacher" bin, bekomme ich das mit dem Callback net hin.

Habe aber eine andere Lösung gefunden (im englischen Forum):

Code: Alles auswählen

IncludeFile "fmodex.pb"

Init_FMOD()
FMOD_System_Create(@System)
FMOD_System_Init(System,1,#FMOD_INIT_NORMAL,#Null)

File$ = OpenFileRequester("Open media:","","",0)

If File$
  Define TagCount, i, Tag.FMOD_TAG
  FMOD_System_CreateStream(System,@File$,#FMOD_DEFAULT,#Null,@Sound)
  FMOD_Sound_GetNumTags(Sound,@TagCount,#Null)
  Debug "Number of tags: " + Str(TagCount)
  For i=0 To TagCount-1
    FMOD_Sound_GetTag(Sound,0,i,@Tag)
    Debug "TAG Struct:"
    Debug Tag\type
    Debug Tag\datatype
    Debug Tag\name
    Debug Tag\_data
    Debug Tag\datalen
    Debug Tag\udated
    Debug PeekS(Tag\name) + " : " + PeekS(Tag\_data, Tag\datalen)
    Debug ""
  Next
EndIf

FMOD_Sound_Release(Sound)
FMOD_System_Release(System) 
Das funktioniert auch mit InternetStreams. Das frage ich dann halt alle paar Sekunden ab und bekomme dann die aktuelle Streaminfo.
Funktioniert wunderbar :D

Eine letzte klitzekleine Frage hätte ich aber dennoch:

Wenn ich den Buffer (Debug percent) abfrage während der Stream läuft:

Code: Alles auswählen

FMOD_Sound_GetOpenState(sound, @openstate, @percent, @starving)
...schwanken die Werte doch ganz erheblich zwischen 50-98.

Wenn ich den Buffer verändere mit:

Code: Alles auswählen

FMOD_System_SetStreamBufferSize
...dauert es extrem lange bis der Stream startet und die "percent"-Werte schwanken noch genaus so :?

Beim alten FMod gab es:

Code: Alles auswählen

FSOUND_Stream_Net_SetBufferProperties
und da hat sich der Buffer relativ lange stabil bei knapp 100% gehalten.

Wieso funktioniert das beim fmodex nicht ?

Hier mein Beispielcode:

Code: Alles auswählen

IncludeFile "fmodex.pb"

Init_FMOD()

FMOD_System_Create(@fmodsystem)
FMOD_System_Init(fmodsystem, 32, 0, 0)

str.s = "http://scfire-mtc-aa06.stream.aol.com:80/stream/1074"


FMOD_System_CreateStream(fmodsystem, @str, #FMOD_SOFTWARE, 0, @sound)
FMOD_System_PlaySound(fmodsystem, 0, sound, 0, @channel)

Dim Arr.f(512)

If OpenConsole()
    PrintN("Druecke Escape zum Beenden.")

Repeat

  KeyPressed$ = Inkey()

   FMOD_Channel_IsPlaying(channel, @isPlaying)
   FMOD_Sound_GetOpenState(sound, @openstate, @percent, @starving)
   
   Debug percent


   
  Delay(250)
Until KeyPressed$ = Chr(27) Or isPlaying = #False

EndIf

FMOD_System_Release(fmodsystem)
Antworten