Selbst generierten Sound aus RAM abspielen?

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
PureLust
Beiträge: 1144
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Selbst generierten Sound aus RAM abspielen?

Beitrag von PureLust »

Hallo zusammen,

ich habe bislang mit Sound noch nicht viel gemacht und würde gerne eine Wellenform selber generiere und diese dann irgendwie abspielen.

Soweit ich die PB Sound-Befehle verstanden habe, geht sowas ja damit nicht, da man nur vorgefertigte Soundfiles catchen kann.

Hat evtl. schon mal jemand sowas gemacht oder hätte einen Tipp dazu, wie man selbst generierte Wellenformen abspielen könnte oder eben einen Ton durch Angabe von Frequenz und Länge ausgeben kann (ggfl. auch über API)?

Thx und Grüße,
PL.

PS: Mir würde im Grunde auch sowas reichen wie :
Spiele Frequenz X1 für Y1 Millisekunden, danach Frequenz X2 für Y2 Millisekunden, ...
Früher habe ich für sowas Beep_() benutzt, aber bei neueren Betriebssystemen liegt zwischen den Beeps ist immer eine Pause, so dass man keinen zusammenhängenden Sound mehr hin bekommt.

Code: Alles auswählen

For n = 900 To 700 Step -20 : Beep_(n,50) : Next
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Derren
Beiträge: 556
Registriert: 23.07.2011 02:08

Re: Selbst generierten Sound aus RAM abspielen?

Beitrag von Derren »

Signatur und so
Benutzeravatar
PureLust
Beiträge: 1144
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Selbst generierten Sound aus RAM abspielen?

Beitrag von PureLust »

Derren hat geschrieben:Vielleicht hilft dir das?
Wau .... das wäre es gewesen. :allright: ... naja ... fast !!! :cry:
Ich hab den alten Code mal auf 5.71 angepasst, aber irgendwie klappt das nicht die erzeugten Daten anschließend mit CatchSound() zu grabben.

Evtl. liegt's daran, dass im Wave-Header einige ASCII Strings drin sind und PB ja komplett auf Unicode umgestellt wurde?
Aber dazu hab' ich aber ja PokeS() angepasst ... sollte meiner Ansicht ja nun so klappen. /:->
Der Wave-Header benötigt doch vermutlich nach wie vor noch die Header-Texte im ASCII Format, oder nicht?

Evtl. 'ne Idee woran's scheitert?

Code: Alles auswählen

EnableExplicit

Structure WAVE
	wFormatTag.w
	nChannels.w
	nSamplesPerSec.l
	nAvgBytesPerSec.l
	nBlockAlign.w
	wBitsPerSample.w
	cbSize.w
EndStructure

Procedure MakeSound(nr,Frequency, Duration)
	Protected SoundValue.b, Result
	Protected w.f; // omega ( 2 * pi * frequency)
	#Mono			=	$0001;
	#SampleRate	=	11025; // 8000, 11025, 22050, or 44100
	#RiffId		=	"RIFF"	;
	#WaveId		=	"WAVE"	;
	#FmtId		=	"fmt "	;
	#DataId		=	"data"	;
	
	Protected WaveFormatEx.WAVE
	WaveFormatEx\wFormatTag			=	#WAVE_FORMAT_PCM;
	WaveFormatEx\nChannels			=	#Mono				 ;
	WaveFormatEx\nSamplesPerSec 	=	#SampleRate;
	WaveFormatEx\wBitsPerSample	=	$0008		  ;
	WaveFormatEx\nBlockAlign		=	(WaveFormatEx\nChannels * WaveFormatEx\wBitsPerSample) /8
	WaveFormatEx\nAvgBytesPerSec	=	WaveFormatEx\nSamplesPerSec * WaveFormatEx\nBlockAlign;
	WaveFormatEx\cbSize				=	0
	
	Protected DataCount = (Duration * #SampleRate)/1000; // sound data
	Protected RiffCount.l = 4+4 +4+ SizeOf(WAVE)+4 +4+ DataCount
	
	Protected *start=AllocateMemory(RiffCount+100)
	Protected MS.i=*start
	
	PokeS(MS,#RiffId,4,#PB_Ascii | #PB_String_NoZero)	:	MS+4  ; 'RIFF'
	PokeL(MS,RiffCount)											:	MS+4	; file Data size
	PokeS(MS,#WaveId,4,#PB_Ascii | #PB_String_NoZero)	:	MS+4	; 'WAVE'
	PokeS(MS,#FmtId ,4,#PB_Ascii | #PB_String_NoZero)	:	MS+4	; 'fmt '
	PokeL(MS,SizeOf(WAVE))										:	MS+4	; TWaveFormat data size
	
	PokeW(MS,WaveFormatEx\wFormatTag)						:	MS+2	; WaveFormatEx record
	PokeW(MS,WaveFormatEx\nChannels)							:	MS+2
	PokeL(MS,WaveFormatEx\nSamplesPerSec)					:	MS+4
	PokeL(MS,WaveFormatEx\nAvgBytesPerSec)					:	MS+4
	PokeW(MS,WaveFormatEx\nBlockAlign)						:	MS+2
	PokeW(MS,WaveFormatEx\wBitsPerSample)					:	MS+2
	PokeW(MS,WaveFormatEx\cbSize)								:	MS+2
	
	PokeS(MS,#DataId,4,#PB_Ascii | #PB_String_NoZero)	:	MS+4  ;'data'
	PokeL(MS,DataCount)											:	MS+4	;sound data size
	
	;{Calculate And write out the tone signal} // now the Data values
	
	Protected i
	w = 2 * #PI * Frequency										; omega
	For i = 0 To DataCount - 1
		;// wt = w *i /SampleRate
		;SoundValue := 127 + trunc(127 * Sin(i * w / SampleRate));
		SoundValue = 127 + 127 * Sin(i * w / #SampleRate);
		PokeB(MS,SoundValue):MS+1								 ;
	Next
	;// you could save the wave tone To file with :
	;// MS.Seek(0, soFromBeginning);
	;// MS.SaveToFile('C:\MyFile.wav');
	;// then reload And play them without having To
	;// construct them each time.
	;{now play the sound}
	;sndPlaySound(MS.Memory, SND_MEMORY Or SND_SYNC);
	;MS.Free;
	
	Result = CatchSound(nr,MS)
	FreeMemory(*start)
	ProcedureReturn Result
	
EndProcedure

Procedure QuitSound(nr)
	StopSound(nr)
	FreeSound(nr)
	;FreeMemory(nr)
EndProcedure

InitSound()
If MakeSound(0,1100,2000)
	PlaySound(0)
	Delay(2000)
	QuitSound(0)
Else
	Debug "ERROR !!! MakeSound() / CachSound() failed" + #CRLF$
EndIf
Debug "done"
PS: Hab im CodeArchiv auch noch einen ähnlichen Code von Froggerprogger gefunden (Create&PlayWAVESoundsInMemory.pb für PB4.0)
Musste natürlich auch angepasst werden ... läuft aber leider genauso wenig. :cry:
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
#NULL
Beiträge: 2216
Registriert: 20.04.2006 09:50

Re: Selbst generierten Sound aus RAM abspielen?

Beitrag von #NULL »

Vielleicht ist das hier auch hilfreich:
https://www.purebasic.fr/english/viewto ... 27&t=62941
my pb stuff..
Bild..jedenfalls war das mal so.
Benutzeravatar
PureLust
Beiträge: 1144
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Selbst generierten Sound aus RAM abspielen?

Beitrag von PureLust »

#NULL hat geschrieben:Vielleicht ist das hier auch hilfreich:
https://www.purebasic.fr/english/viewto ... 27&t=62941
Danke für den Link ... sieht schick aus. :mrgreen:

Hab mir aber gerade nochmal den Code von FroggerProgger (aus dem CodeArchiv) angeschaut und hab den Fehler gefunden.
Klappt also nun wie erhofft.

Vielen Dank nochmals für Eure Hilfe !!! :allright:

Aber noch 'ne Frage zu 'nem Trick den FroggerProgger da ursprünglich angewandt hatte:

Code: Alles auswählen

*mem\l = 'atad'       ; anstatt:  PokeS(*mem,"data", 4,#PB_Ascii | #PB_String_NoZero)
(Wusste garnicht, dass sowas geht. :D )

Dieser Code erzeugt seit der Umstellung auf Unicode ja nun eine 8 Byte Ergebnis (statt früher 4 Byte)
Kann man PB noch irgendwie dazu bringen sowas in ASCII aufzulösen?

Code: Alles auswählen

; English forum: http://www.purebasic.fr/english/viewtopic.php?t==14344&highlight=
; Author: Froggerprogger (updated for PB 4.00 by Andre)
; Date: 11. March 2005
; OS: Windows
; Demo: Yes


;- 11.03.05 by Froggerprogger 
;- For further information on the WAV-format look at: http://www.sonicspot.com/guide/wavefiles.html 

#samplerate = 44100                 ; samplerate 
#bitrate = 16                       ; Bits per sample, #bitrate Mod 8 must be 0 ! 
#channels = 2                       ; number of channels 
#totalsamples = 5*#samplerate       ; length in samples (here 5 seconds) 

#avBytesPerSec  = #channels*#bitrate/8*#samplerate  ; calculate the average bytes per second 
#datachunkBytes = #totalsamples * #channels * #bitrate/8 

Structure PBUnion 
  StructureUnion 
    b.b 
    w.w 
    l.l 
    f.f 
  EndStructureUnion 
EndStructure 

*sound = AllocateMemory(44 + #datachunkBytes) 

*mem.PBUnion = *sound 

;*mem\l = 'FFIR'          													: *mem+4      ; riff-chunk-ID "RIFF" 
PokeS(*mem,"RIFF", 4,#PB_Ascii | #PB_String_NoZero)		: *mem+4      ; riff-chunk-ID "RIFF" 
*mem\l = 36 + #datachunkBytes 					 				: *mem+4      ; normally filesize minus (these) 8 Bytes 
PokeS(*mem,"WAVE", 4,#PB_Ascii | #PB_String_NoZero)		: *mem+4      ; wave-chunk-ID "WAVE" 
PokeS(*mem,"fmt ", 4,#PB_Ascii | #PB_String_NoZero)		: *mem+4      ; format-chunk-ID "FMT " 
*mem\l = 16       													: *mem+4      ; chunk data size (+ Extra Format Bytes) 
*mem\w = 1             									         : *mem+2      ; compression code 
*mem\w = #channels													: *mem+2      ; number of channels 
*mem\l = #samplerate													: *mem+4      ; samplerate 
*mem\l = #avBytesPerSec												: *mem+4      ; average bytes per second, (channels)*(block align)*(samplerate) 
*mem\w = #bitrate/8*#channels										: *mem+2      ; Block Align ('bytes per sample') 
*mem\w = #bitrate														: *mem+2      ; Bits per sample 
;*mem\l = 'atad'														: *mem+4      ; data-chunk-ID "DATA" 
PokeS(*mem,"data", 4,#PB_Ascii | #PB_String_NoZero)		: *mem+4      ; data-chunk-ID "DATA" 
*mem\l = #datachunkBytes											: *mem+4      ; data chunk size in byes 

Debug *mem - *sound
;/ Now lets write #totalsamples of a 440Hz-sinus 
;/ work only for 16 Bit or more. 8-Bit has zero-line at value 128, so it is unsigned 

#fq = 440 
Global maxAmp.l : maxAmp = Pow(2, #bitrate-1)-1 

For acttime = 1 To #totalsamples 
  For actchannel = 1 To #channels 
    *mem\w = maxAmp * Sin(2 * #PI * #fq * acttime / #samplerate) 
    *mem+2 
  Next 
Next 


;/ catch and play the sound 
InitSound() 
CatchSound(0, *sound) 
PlaySound(0) 
Delay(5000) 
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Dadido3
Beiträge: 101
Registriert: 24.02.2007 22:15
Kontaktdaten:

Re: Selbst generierten Sound aus RAM abspielen?

Beitrag von Dadido3 »

Der vollständigkeit halber noch ne lib für Audio ein- und ausgabe: Damit ist es außerdem einfach möglich audiodaten "live" per callback auszugeben oder abzufragen. Grobes Beispiel für eine simple Ausgabe, wobei vollständige Beispiele auf Github vorliegen:

Code: Alles auswählen

*AudioOut = AudioOut::Initialize(#WAVE_MAPPER, 44100, 1, 8) ; Daten als 44100 Samples/s, 1 Kanal, 8 Bit

AudioOut::Write_Data(*AudioOut, ?Blub, ?Blub_End - ?Blub)
Delay(1000)

AudioOut::Deinitialize(*AudioOut)

DataSection
  Blub:
  Data.a $7D,$7D,$7E,$7D,$7D,$7C,$7E,$7E,$80,$82,$82,$83,$81,$82,$80,$80,$80,$82,$82,$83,$82,$84,$83,$81,$82,$81,$81,$80,$81,$81,$7E ; Weitere Wellenformdaten fehlen. Nur ein Beispiel
  Blub_End:
EndDataSection
Antworten