2014-07-07 07:13:55

Hello,
I would like to know how NVDA controls and creates its little beep sound for mouse movement and status reports?
I would like to put something similar in one of my games to indicate HP, but don't want to have 100 .ogg files unless I really have to.
I was looking at pygame's built-in midi support, but it looks as if midi is kind of complex to port to linux.
Does anyone have any ideas on what I could do?
So just in summery, I would like a tone to move up and down in pitch based on the percentage of the status bar I create. So if the bar is at 1% it will be really low pitched and if it is at 100% it will be really high pitched.

2014-07-07 11:02:36 (edited by SoundMUD 2014-07-07 11:04:16)

I don't know how NVDA do this (it's surely in the source), but you can try winsound:
https://docs.python.org/2/library/winsound.html

winsound.Beep(frequency, duration)

    Beep the PC’s speaker. The frequency parameter specifies frequency, in hertz, of the sound, and must be in the range 37 through 32,767. The duration parameter specifies the number of milliseconds the sound should last. If the system is not able to beep the speaker, RuntimeError is raised.

2014-07-07 14:53:04

Frastlin, SoundMUD is exactly right. Last time I looked at the NVDA source code it was using Winsound to make the status indicators and little beeps you hear now and then. Its not a cross-platform solution so if you are thinking of a game for Linux Winsound definitely won't work for this project.

Sincerely,
Thomas Ward
USA Games Interactive
http://www.usagamesinteractive.com

2014-07-07 16:35:27

I wonder if there is an algorithm that lowers the pitch of the playing sound... If not, I'll just need to make 100 files for each tone. Or perhaps I can make one file of the tone going from high to low, then have the file play and stop at different times along the file.

2014-07-08 02:04:44

Is there no way to synthesize tones? Something simple like this could be accomplished with a short triangle or square sample. The code to generate the data for those is trivial; the question is more if there's a way to then play it.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2014-07-08 05:18:28

Hello,
What I think I will do is create a file that descends like 2 octaves in audacity and then play something like 0.5 seconds for each percentage. Does anyone know how to see how long a file or track is in audacity?

2014-07-08 17:28:04

One file or 100 files probably amounts to the same. Maybe you can use a tool like sox to generate all the files with a loop from a script. A command is for example:
sox.exe -n output.wav synth .2 sine 300
http://sox.sourceforge.net/

In theory you can use pygame to synthesize the sounds but I couldn't make them sound right. The following example should be sine waves and it probably doesn't loop well.

import time

import numpy
import pygame


sample_rate = 44100

def sine(hz):
    length = sample_rate / float(hz)
    omega = numpy.pi * 2 / length
    a = numpy.sin(numpy.arange(int(length)) * omega)
    aa = numpy.column_stack((a, a))
    return pygame.sndarray.make_sound(aa)

def play_sine(hz, d):
    sound = sine(hz)
    sound.play(loops=-1)
    time.sleep(d)
    sound.stop()
    
def main():
    pygame.mixer.pre_init(sample_rate, -16, 2) # 44.1kHz, 16-bit signed, stereo
    pygame.init()
    sounds = (sine(i) for i in range(330,550))
    for sound in sounds:
        sound.play(loops=-1)
        time.sleep(.07)
        sound.stop()

##    for f in range(330, 550):
##        play_sine(f, .07)

if __name__ == '__main__': main()

2014-07-09 05:10:52

Sox looks really cool, but I can't get it to work. It may be that I have a 64 bit system, but it also may be that I don't understand how to play audio. (sox audio.mp3 play) or (sox play audio.mp3) don't work...


I thought pygame had a start function (so I could start audio 2.05 seconds into a sound object, but It seems to just be in music. That is strange, because shouldn't anything in music be accessible in the parent class?
I see the argument to play for 0.05 seconds (Which is really nice), but that is not really useful without the start marker in this circumstance...
do you know how to do this?
Otherwise it is creating 100 audio files that are 0.05 milliseconds long for each kind of bar I wish to have!!!

2014-07-09 13:44:35

The example with pygame.sndarray.make_sound() creates a sound for each frequency, so there is no need to start at a position. It does'nt work well though.

I didn't try sox to play audio. I just use it to generate sound.

2014-07-09 17:28:19

I totally am lost on the sndarray module! I don't understand it, but your code doesn't look right to me and doesn't look like the code that are in the examples. The description says: "in 22-kHz format, element number 5 of the array is the amplitude of the wave after 5/22000 seconds."
I don't know what you were doing in numpy, but what should happen is there should be an array that is 2200 items long of the same number.
This would give me a sound that lasts 0.05 seconds and is at 44000 HZ.
So, I think the code would look something like:
l = []
for s in range(2200):
    l.append(440)

Then I use the sndarray module that I'm still trying to puzzle out. It seems as if snd.array() will act as l, but I'm not sure. What ever the case, I need to use sndarray.make_sound(l)
Then on that object I call play.
On further reading, it seems as if numpy has its own array type and I need to tell pygame what to use. I don't think there is any interaction with numpy by me at all.

But if this does not work, do you know if there is a way to start a sound object something like 4 seconds in? There is in the music module, but I don't see it in the mixer module...

2014-07-10 07:54:37

OK,
this is a little over my head! But I did find a working example!!!
taken from:
http://www.mail-archive.com/pygame-user … 16140.html


I wonder what the code would be to change the shape of it? Also to make the sound come equally out of both ears?
I changed a lot of numbers, but the math functions are throwing me and so is the separate channels.
What can you make of it?
#code:
import pygame, numpy, math

duration = 1.0 #in seconds
sample_rate = 44100
bits = 16
frequency = 440

try:
    pygame.mixer.init(frequency = sample_rate, size = -bits, channels = 2)
    n_samples = int(round(duration*sample_rate))
    buf = numpy.zeros((n_samples, 2), dtype = numpy.int16)
    max_sample = 2**(bits - 1) - 1
    for s in range(n_samples):
        t = float(s)/sample_rate        # time in seconds
        buf[s][0] = int(round(max_sample*math.sin(2*math.pi*frequency*t)))
     # left
        buf[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*frequency*t)))    # right
    sound = pygame.sndarray.make_sound(buf)
    sound.play()
    pygame.time.wait(int(round(1000*duration)))

finally:
    pygame.mixer.quit()

2014-07-10 08:24:09

Here is another example, but it is kind of buggy.
#code:
import pygame
from pygame.locals import *

import math
import numpy

size = (1366, 720)

bits = 16
#the number of channels specified here is NOT
#the channels talked about here http://www.pygame.org/docs/ref/mixer.ht … m_channels

pygame.mixer.pre_init(44100, -bits, 2)
pygame.init()
_display_surf = pygame.display.set_mode(size, pygame.HWSURFACE | pygame.DOUBLEBUF)


duration = 1.0          # in seconds
#frequency for the left speaker
frequency_l = 440
#frequency for the right speaker
frequency_r = 550

#this sounds totally different coming out of a laptop versus coming out of headphones

sample_rate = 44100

n_samples = int(round(duration*sample_rate))

#setup our numpy array to handle 16 bit ints, which is what we set our mixer to expect with "bits" up above
buf = numpy.zeros((n_samples, 2), dtype = numpy.int16)
max_sample = 2**(bits - 1) - 1

for s in range(n_samples):
    t = float(s)/sample_rate    # time in seconds

    #grab the x-coordinate of the sine wave at a given time, while constraining the sample to what our mixer is set to with "bits"
    buf[s][0] = int(round(max_sample*math.sin(2*math.pi*frequency_l*t)))        # left
    buf[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*frequency_r*t)))    # right

sound = pygame.sndarray.make_sound(buf)
#play once, then loop forever
sound.play()

sound.play(loops = -1)


#This will keep the sound playing forever, the quit event handling allows the pygame window to close without crashing
_running = True
while _running:

    for event in pygame.event.get():
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            _running = False
            break

pygame.quit()

2014-07-10 08:32:36

And here is a little synthesizer that uses the keyboard as input and uses the sndarray module:
Keyboard synth

2014-07-12 16:10:39

Is explanation still wanted?  I don't want to type up a long explanation of how basic sound synthesis works unless someone actually wants to read it.

My Blog
Twitter: @ajhicks1992

2014-07-15 06:23:13

I understand sound from after the signal is created and coming through my ears, but I have never found any description on what the arrays in a sound file look like.
My math knowledge is limited to algebra and geometry, so some of those functions above I don't know what they are suposed to do.

2014-07-15 17:30:56 (edited by camlorn 2014-07-15 17:34:51)

All right, here goes.  I'm going to show how we get from the statement "I want to make a sine wave" to "I have a buffer that contains a sine wave", including all the reasoning.  Trig is not required, so long as you're willing to accept the things I say about the sine function--and then, the view of the sine function in audio is different from that in trig, anyway.  This is long.  I will entertain questions.  There are no complete programming examples because the programming is very unimportant.

A lie about your Speaker

This is a lie about your speaker.  It is true enough to be useful, while not actually really being true.  Pretend that you've got a spring and a plate on the end of  it.  The plate will naturally sit at some position, which we will call 0 units.  You can push this plate inwards, say to -5 units.  you can pull this plate outwards, say to 20 units.  In our hypothetical lie-brand speaker, this spring can be contracted and expanded by an electrical signal.  Say that the minimum contraction is at -5 volts and the maximum expansion is at 5 volts.  By rapidly varying the voltage applied to this speaker, we can vibrate the plate in a predictable pattern.
Different speakers have different ways of talking to them and different minimum and maximum voltages.  Your sound card sits between your program and the speaker and deals with this for us.  The minimum and maximum value depends on the format of the buffer--for a 16-bit int, it's something like -32767 to 32767 (I don't have the maximum values of different int sizes memorized).  most audio programmers prefer to use -1.0 to 1.0, and that's what I'm going to use here.  Getting from a buffer from -1.0 to 1.0 is simply a multiplication by the maximum value in the new format, and virtually everything these days will let you just not bother and set the audio format to float.  I'm going to come back to this buffer at the end, but it's enough to know for now that if our function ever goes above 1.0 or below -1.0, it's bad.  The minimum contraction corresponds to -1.0 and the maximum expansion to 1.0.

Continuous-time audio

Every sound in the real world is a continuous mathematical function that cannot go to infinity or -infinity.  Your footstep, your car, everything.  This is different from the computer's notion of audio, which is at the end of this post.
I'm not going to start with a sine wave, because it's complex.  I'm going to start with a sawtooth wave because this lets me demonstrate how this works before adding a complexity that the trigonometric functions bring in.  The % operator means remainder, i.e. 2%3 is 2, 4%3 is 1, 9%3 is 0, 12%3 is 0, and 13%3 is 1.  Furthermore, this is defined on floating point values: 2.5%2 is .5, 4.7%2 is .7, 5.3%2 is 1.3.  You can try the following mathematical function in Python, if you want to see what it looks like-but I'll tell you.  It goes up at about a 45-degree angle from 0 to 1, drops back down to 0 at 1, and then goes up again from 1 to 2, and so on.  For the purposes of this post, t represents time in seconds and must start at 0--time is never negative.
So, that said, let's derive a sawtooth wave.  The function representing a sawtooth wave is simply t%1.  Since this function repeats every 1 second, we say that it has a period of 1 second.
there's two problems.  I said that the minimum and maximum value need to be -1.0 and 1.0 respectively.  This function has a minimum value of 0 and a maximum value of 1.  Furthermore, the frequency of this function is too low--specifically, it's 1 HZ, well below the human hearing range.  So let's fix them.
The first problem is easy.  If I multiply the function by 2, it's minimum value stays 0 and its maximum value becomes 2.  The way I get from here to the range we want is to subtract 1.  This gives:
2*(t%1)-1
Which is a 1 HZ sawtooth wave at maximum volume--that is, it's minimum value is -1.0 and its maximum value is 1.0.
The next thing we want to do is to make its frequency change on demand.  The period of a function  a is related to its frequency by frequency=(1/period).  Say we want to make it play at 500 hz.  By basic algebraic manipulation, we can see that the period needs to be 1/500th of a second.  We basically want t to move faster--to go through 500 periods between t=0 and t=1.  We can get this effect by replacing t with 500*t.
2*((500*t)%1)-1
But something similar holds for all frequencies.  Let frequency in hertz be f.  How about this?
2*((f*t)%1)-1
Which is a sawtooth wave at any frequency.  It will repeat f times a second instead of just once per second.

The Sine Wave

So let's apply this process to the sine wave.  The minimum value of the sine function is already -1 and the maximum value of the sine function is 1, so we're all good there.   The period of the sine function is a bit tricky, however: it's 2*pi--if you just do sin(t), it's going to repeat every 2*pi seconds.
The first thing we have to do is get rid of the 2*pi period.  We want to use the above derivation, which works only on functions with a period of 1.  We can just do sin(2*pi*t), which makes the period go to 1, and that's it.  By what we have above, we bring in the f for frequency, and sin(2*pi*f*t) is the function representing a sine wave.  It looks like a slithering snake or a bunch of half circles in a line, where every other half circle has its flat side up instead of down (it's a bit hard to describe accurately. I'm trying).
Sine waves are interesting for a few reasons.  It happens that if you introduce a concept called phase that I'm not going to try to describe here because it's unnecessary, you can represent any sound and, by extension, any real mathematical function with certain properties as a sum of sine functions.  An interesting thing about audio in general is that, if you take two functions representing different sounds and add them, you get a new function that, if played, is the same as playing the sounds separately but simultaneously.

your computer and the Sampling Rate

So all of this is great, but I've not talked about the buffer yet.
your computer cannot work in continuous time.  It is impossible.  Almost nothing can work in continuous time, save analog circuitry--as soon as the word digital comes in, the word sampling rate isn't far behind.
In order to overcome its limitations, your computer takes "samples" of audio.  When you record, the microphone varies continuously, but the computer will only look at the value of the microphone so many times per second.  If you are recording at 44100 HZ, the computer is going to ask the microphone "what is your displacement?" 44100 times a second.  It then takes thee displacement values and puts them in a buffer.  It happens that, at least for humans, 44100 hz sampling rate might as well be a continuous function-when you play it back, you are literally unable to tell the difference between the original audio and the recorded audio.  there are higher sampling rates and some people swear by them, but it's hard to tell any difference beyond 44.1KHZ.
So if you have the above sine function and want to make a buffer, here's how it works.  Let's say that our sampling rate is 1000--it's an easier number than 44100 when you try to reason this out for the first time for the simple reason that 1/1000th of a second is 1 millisecond.
The first sample of the buffer is always at 0.  The next sample is at 1/sr, the 3rd at 2/sr, the 4th at 3/sr, the 5th at 4/sr, and so on.  These are in seconds.  Because sr=1000, the first sample of the buffer is at 0 ms, the second at 1 ms, the 3rd at 2ms, and so on.  What you want to do is plug these time values into the sine function, and put whatever it returns at the appropriate slot in the buffer.  The following python code is very, very slow but should return a list of numbers representing the buffer for a sine wave with duration 1 second at sample rate 1000:

buffer = []
f = 500 #frequency
sr = 1000
for i in xrange(sr):
 t = i/float(sr) #float(sr) because we need the float involved.
 buff.append(sin(2*pi*f*t))

You can fold the sampling rate into the sin function, so that you have an index i instead of a time t.  It would be as follows, if you did that:
sin(2*pi*f*(i/float(sr))
here sr is the sampling rate.  Float makes it work in python: without converting either i or sr to a float, it'll do integer division, which you don't want.
Plug in i=0 for the first sample (array index 0), i=1 for the second (array index 1), and so on.  You're getting the function at time values that are a multiple of 1/sr and recording them in a buffer.  A continuous time buffer would take infinite memory, if you will, and consequently can't ever work.

Some Practical notes

So, some quick things that you need to know to actually make use of this:
The minimum and maximum values of float and double format audio are always -1.0 to 1.0, but the integer buffer formats aren't.  To convert  a buffer of floats, you need to multiply every sample in the buffer by 2**(bits-1) and copy it over to a new buffer.  This is annoying, but true-it's easiest to request signed floating point when possible.
Volume is a multiplier.  To make a buffer quieter, multiply the entire buffer times a scalar less than 1.  Louder is a scalar greater than 1.  I find it easiest to make everything at max volume and then make it quieter--this gives a known range for volume without issues rather than having to guess if 2.0 is going to cause clipping.  It is worth noting that human volume perception is not linear: 0.5 will not sound "half as loud" as 1.  I can go into this if required, but all that's going to come out of me doing so is a magic formula.  I suggest Googling the decibel and coming back if you have questions, which I will try to answer.  Wikipedia will give the formulas and a pretty good description.
If you go above the frequency sr/2, you will not get what you expect.  For 44.1khz, this should never be an issue--sine waves above 10000 hz quickly become inaudible, and 44100/2 is just above the upper end of the human hearing range.  The specific reasoning for this is something I do not understand the proof of, but it's called the Nyquist frequency and you never want to go over it (except for some advanced ring modulation algorithms that I don't need or understand either).
And as for duration to bufffer size: you need floor(duration*sr) samples in the buffer for a sound duration seconds long.  For the above functions, it's best to stick to multiples of 1 second--it'll click if you don't because the ends won't line up when you loop it.
I think I've hit all the points, though digesting this might take a while.

My Blog
Twitter: @ajhicks1992

2014-07-15 19:54:46

I don't understand:
"The % operator means remainder, i.e. 2%3 is 2, 4%3 is 1, 9%3 is 0, 12%3 is 0, and 13%3 is 1."
What are we dividing? Or what is the formula in english? I thought that 2%3 would be x/y = 2%3, so if x =13 and y = 5 it is 2 with the remainder of 3.

2014-07-15 21:01:32

x%y = the remainder of x/y.
So 13%3 =1, because 13/3=4 remainder 1.
For example, an easy way to tell if an int is even or odd is to do x%2, since the only possible remainders for division by 2 are 0 and 1.

x%y = remainder of x/y. If x is a multiple of y, then x%y = 0.
So you wouldn't want to try x%0, because you'd get a division by 0 error (or infinity, or NaN... different languages handle this differently).

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2014-07-15 21:14:53 (edited by camlorn 2014-07-16 01:56:29)

Edit: I've left my original explanation below, but it came to my attention that I may have misunderstood a comment of yours to mean that you're expecting it to return two values.  If this is not the case, you can stop--it returns the remainder.  Nevertheless, the below provides a good deal of examples and such that might make it clearer, all be it the explanation may be too basic for some.  I do discuss how it can be defined on decimals, though, which is something most people don't know.  I also apparently posted at the same time as CAE.
% is technically modulus.  The English formula 2%3 is technically read 2 mod 3, and the definition is a bit more complicated (except in C/C++ where % really is remainder--the first thing I had to do was write my own using the bigger definition).  Since we're only talking about positive numbers, we don't need the complicated clock analogies and the following will do nicely:
2%3=2 because  3 goes into 2 0 times with 2 left over.
13%5 is 3because 5 goes into 13 twice with 3 left over.
x/y says "how many times does y go into x".  x%y says "if I put y into x however many times it goes in, what's left?"  You could write, though I'm not sure how much it helps in understanding:
x%y == x-int(x/y)*y
If we're talking about ints, then x/y throws out the remainder.  x%y throws out the x/y part, keeping only the remainder.  I'd suggest trying some examples in the Python repl to understand it.
As for the definition on floats, if we say 3.5%2, we're asking for the remainder of dividing 2 into 3.5.  Clearly, 2 goes into 3.5 once, so we say 3.5-1*2, which gives us 1.5.  Since it's defined on floats, we can do 0.75%1--1 goes into 0.75 0 times, with a remainder of 0.75, so the result is 0.75.
The following Python lines may prove illuminating:

[i%5 for i in xrange(15)]
[(float(i)/3)%1 for i in xrange(9)]

The last is the sawtooth wave taken every 1/3rd of a second at frequency 1 hz (we don't have to write *1).
And here's a more algorithmic but 20 times less efficient approach that might be clearer for those who don't get algebra:

def remainder(x, y):
 while(x > y):
  x-=y
 return x

Hopefully this clears it up.

My Blog
Twitter: @ajhicks1992

2014-07-16 19:21:45

frastlin wrote:

OK,
this is a little over my head! But I did find a working example!!!
taken from:
http://www.mail-archive.com/pygame-user … 16140.html


I wonder what the code would be to change the shape of it? Also to make the sound come equally out of both ears?

Sorry for not replying earlier. This example is definitely working. To make the sound come equally out of both ears, it's easy, remove "*0.5" from the second line:

buf[s][0] = int(round(max_sample*math.sin(2*math.pi*440*t)))
buf[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*440*t)))

To change the shape, the idea of the sawtooth is to go progressively from -1 to 1, then to go instantly back to -1, and so on. Another shape might be the square: return -1 for the first half of the signal, and +1 for the second half of the signal.

2014-07-16 22:19:31 (edited by frastlin 2014-07-16 23:18:11)

Wow, that is a great explination, I can totally see the sounds now! So, in the example, why is there a call to numpy and what is special about the arrays they are calling?
btw, here is the working sound file with comments. Import this module and use it like:
import beap_sound
sound = beap_sound.sound_creator(duration=1.0, frequency=440, left=0.7, right=0.3)
sound.play()
pygame.time.wait(1500)

#our imports, numpy is required for pygame.sndarray to run and math is used for the sin and pi functions
import pygame, numpy, math

def sound_creator(duration=1.0, frequency=440, left=0.5, right=0.5, sr=44100, bits=16):
    #initialize the pygame's mixer module with default values.
    pygame.mixer.init(frequency = sample_rate, size = -bits, channels = 2)

    #This gives a number of samples in our file. Don't try to print this number, it is really big! I'm not sure why the "round" function     #is there
    n_samples = int(round(duration*sample_rate))

    #This is creating our lovely array. I'm not sure what all of it means, but the n_samples is the amount of items in our list (That     #really big number that we got above!) and the 2 there means that we are wanting 2 channels. I don't know what the other     #number is.
    buf = numpy.zeros((n_samples, 2), dtype = numpy.int16)

    #This is making sure our intijure buffer formats are inbetween -1 and 1, it is making sure we don't have a clipping sound
    max_sample = 2**(bits - 1) - 1

    #Now we are appending samples to the array we made above. I'm not sure why we didn't just do this with "buffer = [[], []]"     #above, but what ever! 
    for i in xrange(n_samples):

        #This is where we create the type of wave it is.
        #t is the time we have in seconds
        t = i/float(sr)

#This is appending the wave type numbers to the first array which on 2 channels is the left
        buf[i][0] = int(round(max_sample*left*math.sin(2*math.pi*frequency*t)))
        #Now we are doing the same to the second array which is the right
        buf[i][1] = int(round(max_sample*right*math.sin(2*math.pi*frequency*t)))

        # Now we are creating the sound through pygame's sndarray module
    sound = pygame.sndarray.make_sound(buf)

    #Now we are returning a sound that is the same as a sound object in the mixer module
    return sound

#This will only run if you run this module, it is a nice example that will play quietly in the left speaker
if __name__ == ('__main__'):
    #Change these values to suit your needs
    duration = 1.0 #in seconds
    sample_rate = 44100
    bits = 16
    frequency = 440
    left = 0.1
    right = 0.03

    #Sound is a tipical sound file like "bird.ogg"
    sound = sound_creator(duration, frequency, left, right, sample_rate, bits)
    sound.play()

    #If you don't wait the program will exit. If you wait the duration of the sound you will get some popping when the sound is     #done. That is why I'm waiting 1.5 seconds, rather than 1.
    pygame.time.wait(1500)
    pygame.mixer.quit()

2014-07-16 23:10:04

frastlin wrote:

So, in the example, why is there a call to numpy and what is special about the arrays they are calling?

I'm not sure why pygame.sndarray requires numpy arrays. Maybe because these arrays are more efficient, smaller, faster, multidimensional (for stereo), and use a specific data type?

2014-07-16 23:22:19

Numpy is very fast, very compact, and very capable if you know a bit of math.  The main point of it with sound code, however, is memory consumption.  Especially for larger buffers, the fact that Python has to use what is called boxxed types hurts you: an integer is the integer itself, plus some data saying that it's an integer.  In addition, python lists are actually arrays of pointers to the objects in the list, rather than the objects themselves--so you've got some extra data for that, too (it's possible python optimizes this case, but I don't believe so).
Numpy does a few things, most majorly storing ints as an unboxxed type.  It's also got convenient syntaxes and functions for a bunch of math operations: everything from basic stuff like find the min or max in an array through convolution, the FFT, trigonometry, and a bunch of matrix operations.  The list is so extensive that I can't recall them all without looking at the docs, but anything mathematical in python typically brings Numpy in (I use it, for example, to make .hrtf files from the MIT kemar Hrtf dataset for Libaudioverse).  The problem in terms of this discussion is that we're discussing something primarily mathematical as an abstract and qualitative thing, but the examples of how to   do this assume that you're capable and willing to use things like Numpy (and tbh Numpy will let you do stuff like trivially apply and design filters, though I haven't done that there myself).  It is worth noting that Numpy docs tend to be accessible, at least if you know LaTeX a bit.

My Blog
Twitter: @ajhicks1992

2014-07-17 00:13:21

Here is a more pythonic and functional module for generating sounds in pygame using the sndarray module. Where can I find more equations for different waves? I googled equations for sound waves, but just found the basic idea of moving from -1 to 1. I know that that is really the only limit to a type of wave, but I also know there are several basic types.


#our imports, numpy is required for pygame.sndarray to run and math is used for the sin and pi functions
import pygame, numpy, math


def sine(frequency, t):
    """The equasion for a sine type wave"""
    return math.sin(2*math.pi*frequency*t)

def sawtooth(frequency, t):
    """The equasion for a sawtooth wave"""
    return 2*((frequency*t)%1)-1


#A dictionary with a string key of the wave types
wave_types = {
"sine": sine,
"sawtooth": sawtooth
}

def sound_creator(duration=1.0, frequency=440, left=0.5, right=0.5, wave_type="sine", sr=44100, bits=16):
    #initialize the pygame's mixer module with default values.
    pygame.mixer.init(frequency = sample_rate, size = -bits, channels = 2)

    #This gives a number of samples in our file. Don't try to print this number, it is really big! I'm not sure why the "round" function     #is there
    n_samples = int(round(duration*sample_rate))

    #This is creating our lovely array. I'm not sure what all of it means, but the n_samples is the amount of items in our list (That     #really big number that we got above!) and the 2 there means that we are wanting 2 channels. I don't know what the other     #number is.
    buf = numpy.zeros((n_samples, 2), dtype = numpy.int16)

    #This is making sure our intijure buffer formats are inbetween -1 and 1, it is making sure we don't have a clipping sound
    max_sample = 2**(bits - 1) - 1

    #Now we are appending samples to the array we made above.
    for i in xrange(n_samples):

        #This is where we append to our array the number for the type of wave it is.
        #t is the time we have in seconds
        t = i/float(sr)

        #This is appending the wave type numbers to the first array which on 2 channels is the left
        #max_sample is the clipping volume and the left and right are just the spacific volume for that side. The wave_types         #dictionary is called with the string of the kind of wave the caller wished ("sine", "sawtooth"...)
        buf[i][0] = int(round(max_sample*left*wave_types[wave_type](frequency, t)))

        #Now we are doing the same to the second array which is the right
        buf[i][1] = int(round(max_sample*right*wave_types[wave_type](frequency, t)))

    #this creats the sound through pygame's sndarray module
    sound = pygame.sndarray.make_sound(buf)

    #sound is now the same as any object that is created using the pygame.mixer.Sound class
    return sound

#This will only run if you run this module, it is a nice example that will play quietly in the left speaker
if __name__ == ('__main__'):
    #Change these values to suit your needs
    duration = 1.0 #in seconds
    sample_rate = 44100
    bits = 16
    frequency = 440
    left = 0.1
    right = 0.03
    type = "sine"

    #Sound is a tipical sound object that pygame uses
    sound = sound_creator(duration, frequency, left, right, type, sample_rate, bits)
    sound.play()

    #If you don't wait the program will exit. If you wait the duration of the sound you will get some popping when the sound is     #done. That is why I'm waiting 1.5 seconds, rather than 1.
    pygame.time.wait(1500)
    pygame.mixer.quit()

2014-07-17 00:58:43 (edited by CAE_Jones 2014-07-17 01:35:38)

The four basics are sine, sawtooth, square and triangular.
This page gives examples (it looks like one of them uses headings to separate them, so it should be easy to find):
http://stackoverflow.com/questions/1073 … angle-wave
Those aren't incredibly useful on their own--you still need to change a few values and such--but that covers the most common basic waves.
Also, it's for C, so there are some bits of notation in there you might or might not find confusing, depending on your experience. Specifically the liberal use of ++, and the ?: thing (Python has equivalents to these, but the latter at least looks pretty different).

I'll translate the square one into Python as best I can:

y = 3 if(x % 6) < 3 else 0

(Except you'd want -1 and 1 for the maxima instead of 3 and 0, and the 6 and 3 in there should be replaced with the period and half of said period respectively. So it looks more like this:

bytes[i]=-1.0 if((t%(1.0/f) < 0.5/f) else 1.0

... I think. I'm having a stupidly hard time remembering how to calculate the period all of a sudden.)

[edit] The last answer on that page might be more helpful, but warning: uses C.
http://stackoverflow.com/a/21197837
And ignore the plotRGB lines in there. Those appear to be for graphics.
[/edit]

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.