Page 1 of 1

What exactly does SetSoundFrequency() ???

Posted: Thu Dec 05, 2013 10:39 pm
by infratec
Hi,

want to write an emulator for an 'phasewheel' which delivers the rpm and the position of cylinders to the ECU.
The wheel has many teeth with a few missing to show a special position.

My idea was to create a sound with this as waveform. So far so good.
Now I want to setup different speeds.
I thought it is possible with SetSoundFrequency().
But I don't know what it does.
The second parameter is definately not the frequency.

An example:

Code: Select all

EnableExplicit

Structure RIFFStructure
  Riff.s{4}
  Length.l
  Wave.s{4}
EndStructure


Structure fmtStructure
  fmt.s{4}
  Length.l
  Format.u
  Channels.u
  SampleRate.l
  BytesPerSecond.l
  BlockAlign.u
  BitsPerSample.u
EndStructure


Structure dataStructure
  Signature.s{4}
  Length.l
EndStructure



Procedure.i CreateSineWAV(*WAVBuffer)
  
  Protected.i Result, dataOffset, Ptr, i
  Protected *RiffPtr.RIFFStructure, *fmtPtr.fmtStructure, *dataPtr.dataStructure
  
  If *WAVBuffer
    
    *RiffPtr = *WAVBuffer
    *RiffPtr\Riff = "RIFF"
    *RiffPtr\Wave = "WAVE"
    
    *fmtPtr = *WAVBuffer + SizeOf(RIFFStructure)
    *fmtPtr\fmt = "fmt "
    *fmtPtr\Length = SizeOf(fmtStructure) - 8
    *fmtPtr\Format = 1
    *fmtPtr\Channels = 1
    *fmtPtr\SampleRate = 44100
    *fmtPtr\BitsPerSample = 16
    *fmtPtr\BlockAlign = *fmtPtr\Channels * ((*fmtPtr\BitsPerSample + 7) / 8)
    *fmtPtr\BytesPerSecond = *fmtPtr\SampleRate * *fmtPtr\BlockAlign
    
    
    *dataPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure)
    *dataPtr\Signature = "data"
    
    dataOffset = SizeOf(RIFFStructure) + SizeOf(fmtStructure) + SizeOf(dataStructure)
    
    Ptr = 0
    For i = 0 To 359
      PokeW(*WAVBuffer + dataOffset + Ptr, Sin(Radian(i)) * 30000)
      Ptr + 2
    Next i
    
    *dataPtr\Length = Ptr
    *RiffPtr\Length = SizeOf(RIFFStructure) + SizeOf(fmtStructure) + SizeOf(dataStructure) + Ptr - 8
    
    ;ShowMemoryViewer(*WAVBuffer, *RiffPtr\Length + 8)
    
    Result = #True
    
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


InitSound()

Define *Buffer

*Buffer = AllocateMemory(1024)
If *Buffer
  
  If CreateSineWAV(*Buffer)
    Debug "Created"
    If CatchSound(0, *Buffer)
      
      Debug "Play"
      PlaySound(0, #PB_Sound_Loop)
      Delay(3000)
      
      Debug "Play 44100"
      SetSoundFrequency(0, 44100)
      Delay(3000)
      
    EndIf
  EndIf
  
  FreeMemory(*Buffer)
EndIf
If you check the created WAV with audacity for example, you see one sine wave with 125Hz.
That's also what you can hear during the first 3 seconds.

Than I tried to use SetSoundFrequency()...
Not really successfull.
If I use the samplerate as 'frequency', than I see and hear the same sound.

Can anyone explain what exactly SetSoundFrequency() does?

Or is it a bug?

Bernd

P.S.: disable 'create unicode executable' in compiler options!

Re: What exactly does SetSoundFrequency() ???

Posted: Thu Dec 05, 2013 11:50 pm
by Pot Noodle
Hi Infratec,

I used SetSoundFrequency() in my car game for the engine sound.
Increasing the frequency and then changing gear and so on.

Take a look at this it may just answer you question.

http://forum.purebasic.com/english/view ... 7ca9bc1877

Hope it helps. :wink:

Re: What exactly does SetSoundFrequency() ???

Posted: Fri Dec 06, 2013 5:16 am
by BasicallyPure
From my experience with SetSoundFrequency() I have come to this conclusion.
When you specify the frequency parameter you are setting the sample rate for the sound playback.
It is useful to know the sample rate of the original sound that you are playing.
For example assume the original sound was a 1000 Hz waveform created with a sample rate of 44100 samples per second.
If you use SetSoundFrequency(44100) before playback then the pitch of the sound will be the same as the original (1000 Hz).
If you were to use SetSoundFrequency(22050) then the pitch would be 1/2 of the original (500 Hz).

PlaybackFrequency = OriginalFrequency * SetFrequency / OriginalSampleRate
PlaybackFrequency = 1000 * 22050 / 44100 = 500

BP

Re: What exactly does SetSoundFrequency() ???

Posted: Fri Dec 06, 2013 10:29 am
by infratec
@BasicallyPure

That's also what I thought.

From Audacity samplerates reaches from 8000 to 384000Hz.
Now I have to check if each 'frequency' (new samplerate) between is possible.

Bernd

Re: What exactly does SetSoundFrequency() ???

Posted: Fri Dec 06, 2013 11:30 am
by infratec
Hi,

in my test I can set at maximum 200000 as 'frequency'

Code: Select all

Procedure NewSetSoundFrequency(Sound.i, OrgSamplerate.i, OrgFreq.i, NewFreq.i)
  
  SetSoundFrequency(Sound, NewFreq * OrgSamplerate / OrgFreq)
  
EndProcedure
And the OrgSamplerate and OrgFreq values are always the original values :!:

That means that PB (or windows) stores this values somewhere.

This works:

Code: Select all

PlaySound(0, #PB_Sound_Loop)
Delay(3000)

NewSetSoundFrequency(0, 44100, 125, 250)
Delay(3000)

NewSetSoundFrequency(0, 44100, 125, 125)
Delay(3000)
more or less exact:
234Hz instead of 250.

Bernd

Re: What exactly does SetSoundFrequency() ???

Posted: Fri Dec 06, 2013 11:31 am
by Pot Noodle
Thanks BasicallyPure

You explained it better than I could :wink:

Re: What exactly does SetSoundFrequency() ???

Posted: Fri Dec 06, 2013 4:47 pm
by BasicallyPure
@infratec

looking at the code from the first post it looks like the frequency produced is
44100 / 360 = 122.5 Hz.
If you change the value 125 to 122.5 your results may be more accurate.
Also, using floats for frequencies may work better.

Code: Select all

Procedure NewSetSoundFrequency(Sound.i, OrgSamplerate.i, OrgFreq.f, NewFreq.f)
  
  SetSoundFrequency(Sound, NewFreq * OrgSamplerate / OrgFreq)
  
EndProcedure

Code: Select all

PlaySound(0, #PB_Sound_Loop)
Delay(3000)

NewSetSoundFrequency(0, 44100, 122.5, 250) ; sample rate = 90000
Delay(3000)

NewSetSoundFrequency(0, 44100, 122.5, 125) ; sample rate = 45000
Delay(3000)

NewSetSoundFrequency(0, 44100, 122.5, 122.5) ; sample rate = 44100
Delay(3000)
BP