ModuleSoundSystem

Anwendungen, Tools, Userlibs und anderes nützliches.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

ModuleSoundSystem

Beitrag von NicTheQuick »

Hi @ all!

Ich bin gerade dabei einen kleinen Synthesizer zu basteln, den man
irgendwann dann auch mal komfortabel in kleine PureBasic-Projekte
einbinden kann und ein bisschen Musik machen kann.

Den kompletten Quellcode gibt es jetzt noch nicht, weil das ganze noch
lange nicht fertig ist. Aber ein kleiner Vorgeschmack als EXE-Datei und
externer fmodex.dll gibt es hier:
- fmodex.dll
- MSS.exe

Einfach beides in einen Ordner herunterladen und starten. Es öffnet sich
ein Mausklavier, ein Debug-Fenster ohne Debug-Informationen und ein
schwarzes Fenster. Beim Drücken einer Taste sollte dann ein Ton ertönen
und im scharzen Fenster die Welle angezeigt werden. Mit der Tastatur geht
es übrigens auch.

Das Signal ist ein Rechtecksignal (Square), das mit einem Dreiecksignal
(Triangle) amplitudenmoduliert und einem Sinussignal (Sine)
frequenzmoduliert ist. Die Frequenz der Amplitudenmodulation liegt bei
einem Hertz. Die Frequenz der Frequenzmodulation liegt bei 3 Hertz und
ihre Amplitude ist abhängig von der Frequenz des Rechtecksignals mit dem
Multiplikator 0,05.

Soviel zu dem Klang. Hier noch ein Code-Ausschnitt der Main.pb des
Programmes.

Code: Alles auswählen

Procedure AmplitudeCallback(time.d, Amplitude.d, Velocity.d, *result.Double)
  
EndProcedure

Procedure.d FrequencyCallback(time.d, Frequency.d, inFrequency.d, Velocity.d)
  
EndProcedure

Procedure EnumMixerInputs(*Wave.MSS_WaveForm)
  ProcedureReturn #True
EndProcedure

Macro Quote
  "
EndMacro
Macro DebugVar(a)
  Debug Quote#a#Quote + ": " + Str(a)
EndMacro
Macro OK(a)
  Debug Quote#a#Quote
  Result = a
  If Result
    Debug FMOD_ErrorString(Result)
    End
  EndIf
EndMacro

Define *IS.ImageScreen, *Keys.Keys
Define Width.l = 1000, Height.l = 400
Define Samplerate.l, Channels.l, exinfo.FMOD_CREATESOUNDEXINFO
Global Dim OnNotes.b(127), Dim NoteSample.l(127), Dim *RefreshOut(127), Dim *FMODOut(127)
Global *Wave.MSS_WaveForm, *Mix.MSS_Mixer

Samplerate = 44100
Channels = 1

Procedure KeyCallback(*Keys.Keys, Note.b, Velocity.b, UserData.l)
  OnNotes(Note) = Velocity
  NoteSample(Note) = 0
EndProcedure
DataSection ;{ Tasten
  Tasten:
    Data.l 25 ;Anzahl aufeinander folgender Noten
    Data.l #VK_Y, #VK_S, #VK_X, #VK_D, #VK_C, #VK_V, #VK_G, #VK_B, #VK_H, #VK_N, #VK_J, #VK_M
    Data.l #VK_Q, #VK_2, #VK_W, #VK_3, #VK_E, #VK_R, #VK_5, #VK_T, #VK_6, #VK_Z, #VK_7, #VK_U, #VK_I
    Data.l -1, -1  ;eins höher/tiefer (-1 = ignorieren)
    Data.l #VK_UP, #VK_DOWN ;eine oktave höher/tiefer
EndDataSection ;}

Procedure RefreshWindow(*IS.ImageScreen)
  Protected x.l, Width.l = *IS\Width(), Height.l = *IS\Height(), yoff.l = Height / 2, oldy.l = yoff, y.d, a.l
  Protected Input.MSS_Input
  Static *Out
  
  If *Out = 0 : *Out = *Wave\NewOut() : EndIf
  
  *IS\StartDraw()
    Box(0, 0, Width, Height, 0)
    For xl = 0 To Width
      y = 0
      For a = 0 To 127
        If OnNotes(a) > 0
          Input\Velocity = OnNotes(a) / 127
          Input\Frequency = 220 * Pow(2, (a - 68) / 12)
          Input\sample = xl * 44100 / Width
          y + *Wave\Out(@Input, *RefreshOut(a))
        EndIf
      Next
      y * -yoff + yoff
      LineXY(xl - 1, oldy, xl, y, $FFFFFF)
      oldy = y
    Next
  *IS\StopDraw()
  
  *IS\ShowChanges()
EndProcedure

Procedure.l Buffercallback(*Sound, *BufferPointer, length.l)
  Protected float.f, *sample.Float, *sample_last, mpos.POINT, a.l
  Protected Input.MSS_Input
  Static *Out
  Shared Channels.l, Samplerate.l
  *sample_last = length + *BufferPointer
  *sample = *BufferPointer
  
  If *Out = 0 : *Out = *Wave\NewOut() : EndIf
  
  Repeat
    float = 0
    For a = 0 To 127
      If OnNotes(a) > 0
        Input\Velocity = OnNotes(a) / 127
        Input\Frequency = 440 * Pow(2, (a - 68) / 12)
        Input\sample = NoteSample(a)
        float + *Wave\Out(@Input, *FMODOut(a))
        NoteSample(a) + 1
      EndIf
    Next
    
    For offset = 1 To Channels
      *sample\f = float
      
      *sample + SizeOf(Float)
    Next
  Until *sample => *sample_last
  
  ProcedureReturn #FMOD_OK
EndProcedure

;{- Wave-Fenster und Keyboard

*IS = IS_New()
*IS\Open(0, 0, Width, Height, "ModuleSoundSystem", 0, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

*Keys = Keys_New("Mausklavier")
*Keys\Resize(300, 0, 600, 40)
*Keys\AutoAspectRatio(#True)
*Keys\Hide(#False)
*Keys\Callback(@KeyCallback(), 0)
*Keys\SyncInput(#True)
*Keys\SetKeyboard(?Tasten)
*Keys\KeyNote(60)

;}

;{- Waveformen
Define.MSS_WaveForm *Wave1a, *Wave1b, *Wave1, *Wave4
Define.MSS_Mixer *Mix1, *Mix2

*Wave1a = MSS_WaveForm_New()
*Wave1a\Type(#MSS_WaveForm_Sine) ;Sinussignal
*Wave1a\Samplerate(Samplerate)
*Wave1a\Frequency(3) ;Frequenz
*Wave1a\FrequencyType(#MSS_Frequency_Static) ;Frequenz mit Eingangsfrequenz multiplizieren 
*Wave1a\Amplitude(0.05) ;Amplitudenhöhe
*Wave1a\AmplitudeType(#MSS_Amplitude_FrequencyMult) ;Amplitudenhöhe mit Eingangsfrequenz multiplizieren
DebugVar(*Wave1a)

*Wave1b = MSS_WaveForm_New()
*Wave1b\Type(#MSS_WaveForm_Triangle) ;Sinussignal
*Wave1b\Samplerate(Samplerate)
*Wave1b\Frequency(1) ;Frequenz
*Wave1b\FrequencyType(#MSS_Frequency_Static) ;Frequenz multiplizieren mit Eingangsfrequenz
*Wave1b\Amplitude(1) ;Amplitudenhöhe
*Wave1b\AmplitudeType(#MSS_Amplitude_Static) ;Amplitudenhöhe mit Eingangslautstärke multiplizieren
*Wave1b\Phase(0.75)
DebugVar(*Wave1b)

*Wave1 = MSS_WaveForm_New()
*Wave1\Type(#MSS_WaveForm_Square) ;Sinussignal
*Wave1\Samplerate(Samplerate)
*Wave1\Frequency(1) ;Frequenz
*Wave1\FrequencyType(#MSS_Frequency_WaveFormAddI) ;Waveform addieren zu Eingangsfrequenz
*Wave1\SetFrequencyCallback(*Wave1a)
*Wave1\Amplitude(0.25) ;Amplitudenhöhe
*Wave1\AmplitudeType(#MSS_Amplitude_WaveformAddVxA) ;Amplitudenhöhe mit Eingangslautstärke multiplizieren
*Wave1\SetAmplitudeCallback(*Wave1b)
DebugVar(*Wave1)

; *Mix1 = MSS_Mixer_New()
; *Mix1\Type(#MSS_Mixing_Average) ;Durchschnittswert aus allen Eingängen nehmen
; *Mix1\Voices(128)
; ;*Mix1\Volume(0.25)
; ;*Mix1\AddInput(*Wave1b, #MSS_Input_WaveForm)
; *Mix1\AddInput(*Wave2, #MSS_Input_WaveForm)
; ;*Mix1\AddInput(*Wave3, #MSS_Input_WaveForm)
; *Mix1\AddInput(*Wave4, #MSS_Input_WaveForm)
; DebugVar(*Mix1)

*Wave = *Wave1
;}

Define a.l
For a = 0 To 127
  *RefreshOut(a) = *Wave\NewOut()
  *FMODOut(a) = *Wave\NewOut()
Next

;{ FMOD initialisieren und Sound starten
Init_FMOD()

OK(FMOD_System_Create(@*System)) ;System erstellen

OK(FMOD_System_Init(*System, Channels, #FMOD_INIT_NORMAL, 0)) ;System initialisieren

With exinfo
  \cbSize = SizeOf(FMOD_CREATESOUNDEXINFO)
  \Numchannels = Channels                     ;Anzahl Kanäle (Stereo)
  \defaultfrequency = Samplerate              ;Die Samplerate (44100)
  \Format = #FMOD_SOUND_FORMAT_PCMFLOAT       ;Das Format (Float)
  \length = Samplerate                        ;Die Länge des Samples (1 Sekunde)
  \decodebuffersize = Samplerate / 20         ;Die Anzahl an Samples pro Callback-Aufruf (25 ms)
  \pcmreadcallback = @Buffercallback()        ;Der Pointer zum Callback
EndWith

;Sample erstellen (2D-Sound, Software-Rendering, Loop)
OK(FMOD_System_CreateSound(*System, 0, #FMOD_2D | #FMOD_OPENUSER | #FMOD_SOFTWARE | #FMOD_CREATESTREAM | #FMOD_LOOP_NORMAL, @exinfo, @*Sound))

;Sound abspielen
OK(FMOD_System_PlaySound(*System, #FMOD_CHANNEL_FREE, *Sound, #False, @*channel))
;}

Repeat
  EventID = WindowEvent()
  *Keys\Event(EventID)
  Select EventID
    Case #PB_Event_CloseWindow
      Break
    
    Case 0
      RefreshWindow(*IS)
      Delay(10)
  EndSelect
  FMOD_System_Update(*System)
ForEver

;{ Sound stoppen und FMOD deinitialisieren
OK(FMOD_Channel_Stop(*channel))
OK(FMOD_Sound_Release(*Sound))
OK(FMOD_System_Release(*System))

*IS\Kill()
*Wave1\Kill()

End
;}
Zuletzt geändert von NicTheQuick am 23.08.2007 15:03, insgesamt 1-mal geändert.
Bild
Benutzeravatar
dige
Beiträge: 1182
Registriert: 08.09.2004 08:53

Beitrag von dige »

Schon mal ganz putzig das Ganze. Der hohe Ton klingt aber wie ein
altes Radio beim Sender suchen ;-)
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Benutzeravatar
Tafkadasom2k5
Beiträge: 1577
Registriert: 13.08.2005 14:31
Kontaktdaten:

Beitrag von Tafkadasom2k5 »

dige hat geschrieben:Schon mal ganz putzig das Ganze. Der hohe Ton klingt aber wie ein
altes Radio beim Sender suchen ;-)
Das liegt an deiner Soundkarte zusammen mit deinen Boxen. Wenn die Tonhöhe die deiner Soundkombi überschreitet, versucht die Hardware das so zu oktavieren, das es klappt. Die Schwingungen, die du dabei vernimmst, klingen halt komisch. ABer wenn du genau hinhörst ist es der gleiche Ton, nur eben auf anderer Tonbasis.

Gr33tz
Tafkadasom2k5
OpenNetworkConnection() hat geschrieben:Versucht eine Verbindung mit dem angegebenen Server aufzubauen. 'ServerName$' kann eine IP-Adresse oder ein voller Name sein (z.B.: "127.0.0.1" oder "ftp.home.net").
php-freak hat geschrieben:Ich hab die IP von google auch ned rausgefunden!
Benutzeravatar
bobobo
jaAdmin
Beiträge: 3857
Registriert: 13.09.2004 17:48
Kontaktdaten:

Beitrag von bobobo »

und ich suche gerade ein DigitalPiano ..
@Nick wenn Dein Programm fertig ist dann schenkst Du mir sicher Dein
Yamaha CLP irgendwas, oder?
‮pb aktuell5.7 - windoof aktuell und sowas von 10
Ich hab Tinnitus im Auge. Ich seh nur Pfeifen.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Beitrag von NicTheQuick »

Mein YAMAHA CLP? Hab ich keins. Oder gibts das gar net? <)

Ich hab jetzt noch ein Mixer-Modul gebaut, dann kommt noch ein Sampler
und ein Hüllkurvenmodul.
Mal schauen, was mir noch so alles einfällt. :D

Danach kommt eine kleine GUI, mit der man sich dann ein paar Sounds
zusammenstöpseln kann. Und dann eine Art Play-Befehl, mit der man Musik
spielen lassen kann. :)
Bild
Benutzeravatar
dllfreak2001
Beiträge: 2925
Registriert: 07.09.2004 23:44
Wohnort: Bayern

Beitrag von dllfreak2001 »

Kommt dieser Effekt nicht eher dadurch das die Abtastrate zu gering ist?

Naja, an den Boxen liegt es jedenfalls nicht, nur an der Soundkarte.
I´a dllfreak2001
Benutzeravatar
DarkSoul
Beiträge: 689
Registriert: 19.10.2006 12:51

Beitrag von DarkSoul »

Naja, an den Boxen liegt es jedenfalls nicht, nur an der Soundkarte.
em ste ich voll zu, denn die boxen spucken nur das aus, was elektrisch reinkommt, nur halt lauter :wink: Die kennen keine Abtastraten oder Bitzahlen, nur nen frequenzgang (von wo bis wo), ne ohmzahl (bei pc-boxen unwchtig, da da schon ne endstufe drinne is), nen wirkungsgrad (die wichtigste angabe) und ne wattzahl (wieviel strom das ganze verschlingt, nicht unbedingt lautstärkerelevant)
Es sei denn man hat digitale eingänge, aber das sind höherwertigere, die whl kaum die blechdosen-22050hz x 8bit als maximum haben
Bild
Antworten