Entwicklung basierd auf:
Beschreibung:http://www.purebasic.fr/english/viewtopic.php?t=7431 von Froggerprogger und blbltheworm
Der Code hier kann anhand einer Liste mit Tonhöhe (Frequenz) und Tondauer einen Sound im WAV-Format im Speicher zusammenbauen.
1. Besonderheit: Entgegen einem einfachen Beep_() können mehrere Töne simultan erzeugt werden.
2. Besonderheit: Abgesehen davon dass man damit Musik machen kann, kann man auch ein (M)FSK-Signal erzeugen. Das Signal muss nur noch auf die entsprechende Hochfrequenz moduliert werden und kann dann abgestrahlt werden.
3. Besonderheit: Das erzeugte Signal kann über Catchsound() direkt geladen werden oder durch wegspeichern als .wav auch exportiert werden. Macht die Sache handlicher. Bin mir aber nicht sicher ob es durchoptimiert ist.
Viel Spaaaß,
Code: Alles auswählen
InitSound()
Structure WAVEHeader
MagicBytes.l
Filesize.l
Text.q
ChuckSize.l
Compression.w
Channels.w
samplerate.l
avBytesPerSecons.l
BlockAlign.w
bitPerSample.w
dataText.l
avBytesTotal.l
EndStructure
Structure Note
StartMs.i
DurationMs.i
Frequency.i
EndStructure
Procedure CreateMusic(List Note.Note(),channels=1,bitrate=16,samplerate=44100)
;{ #Pb_Any Catching
If channels = #PB_Any : channels = 1: EndIf
If bitrate = #PB_Any : bitrate = 16: EndIf
;}
;{ Missing input Catching
If ListSize(Note()) <= 0 : MessageRequester("Error","no notes given") : EndIf
;}
;{ Calculate Duration
TotalDuration = 0
ForEach Note()
current = Note()\StartMs + Note()\DurationMs
If TotalDuration < current
TotalDuration = current
EndIf
Next
SecUpRounded = Round(TotalDuration/1000,#PB_Round_Up)
;}
;{ Create a WAVE Header
avBytesPerSec.l = channels * bitrate / 8 * samplerate ; calculate the average bytes per second
Waveheader.Waveheader
Waveheader\MagicBytes = $46464952 ;Backwards, LittleEndian
Waveheader\Filesize = 36 + avBytesPerSec * SecUpRounded
Waveheader\Text = $20746d6645564157
Waveheader\ChuckSize = 16
Waveheader\Compression = 1
Waveheader\Channels = channels
Waveheader\samplerate = samplerate
Waveheader\avBytesPerSecons = avBytesPerSec
Waveheader\BlockAlign = bitrate / 8 * channels
Waveheader\bitPerSample = bitrate
Waveheader\dataText = $61746164 ;Backwards, LittleEndian
Waveheader\avBytesTotal = avBytesPerSec*SecUpRounded
WaveHeaderSize = SizeOf(Waveheader)
;}
;{ Allocate Memory for the whole song
Memory = AllocateMemory(WaveHeaderSize + SecUpRounded * samplerate * (bitrate / 8))
; Copy the Wave-Header to the first 44 Bytes
CopyMemory(Waveheader,Memory,WaveHeaderSize)
;}
;{ Start calculating the samples
Protected sample.w ;(signed RAW data)
For acttime = 1 To samplerate * SecUpRounded
ProgressMs.f = acttime / samplerate * 1000
For actchannel = 1 To channels
Sum = 0 : TempSample.f = 0
ForEach Note()
If ProgressMs >= Note()\StartMs And ProgressMs <= Note()\StartMs + Note()\DurationMs
Sum +1 ; Sum of Tones for later division (normalisation)
TempSample + Sin(2 * #PI * Note()\Frequency * acttime / samplerate)
EndIf
Next
If Not sum
Continue
EndIf
Sample = 32767 * (TempSample / Sum)
PokeW(Memory + WaveHeaderSize + acttime*2 ,sample)
Next
Next
;}
ProcedureReturn Memory
EndProcedure
CompilerIf Not #PB_Compiler_IsIncludeFile
Macro AddTone(Time,Dur,Frq)
AddElement(Notes()) : Notes()\StartMs = Time : Notes()\Frequency = Frq : Notes()\DurationMs = Dur
EndMacro
NewList Notes.Note()
AddTone(0,500,240)
AddTone(500,500,440)
AddTone(500,1000,240)
AddTone(0,50,240)
AddTone(1500,1500,440)
Mem = CreateMusic(Notes())
Sound = CatchSound(#PB_Any,Mem)
PlaySound(sound)
Delay(3000)
f = CreateFile(#PB_Any,"test.wav")
If f
WriteData(f,Mem,MemorySize(Mem))
CloseFile(f)
RunProgram("test.wav")
EndIf
FreeMemory(mem)
CompilerEndIf