Sounds Good To Me
BlitzMax Forums/BlitzMax Beginners Area/Sounds Good To Me
| ||
Nope. No BlitzMAX example code, not a lick, this one has me completely stumped. Now back in time you could create speaker effects many different ways. One method I had that sounded like a sword clinging against a shield was: FOR I=1000 TO 1 STEP -1:SOUND 750+RND()*I,.1:NEXTBlitzMAX - at least to my knowledge has no way to create sound internally, not easily anyways. So has someone made a routine or code or what have you that will allow you to play a note of a particular pitch from too low to hear to too high to hear and at a duration that can be anywhere from 4 long seconds to as small as a thousandth of a second ? |
| ||
Have a look at this code archive entry by skidracer/nitro/simonarmstrong Original request of me was to provide streamed-ogg-support but his initial code was a dynamic created sound. It is not exactly what you want but maybe it is of help. bye Ron |
| ||
Dont know, whether it helps... but some time ago I build a software sythesizer for education purposes. Download: http://www.midimaster.de/download/hoerensehen_demo.exe Inside the code there is a part which show how to create samples and prepare it for the TSound format of BlitzMax. Also shown how to do it in real time: |
| ||
Hi Derron. I looked at that code - and listened. Sounded ok for the first part. Changed this line:osc1=Sin(t*(lfo+10))to listen to a higher pitch. Problem is there is a nasty warbling in the background, some type of feedback. Definitely not good. You mean no-one has written a clean sound generator ? Even the Atari 2600, primitive as it was, did a fine job for what the resources they had. I'd settle for that. SOUND LINK. MM, your program crashes on FLIP 0 no graphics are set up ? Failing this I know years ago I would play MIDI instruments on one of my adventure games (the upper 128) to create sound effects - so that is also a possibility if someone has written code to pluck MIDI instruments individually. This might actually be the route to take as your piano pitches are already set. |
| ||
The code is non-runable sample! This are only some lines from my 2000-lines-code, which show elementary technics of sound generating and converting. MIDI will not help you, because it plays only given 120 music instruments and 8 terrible sound effects. With my algorithm you will be able to create any waveform and process it to the audio device. Undesired sound effect result from 3 reasons: 1. Distortion, means no value should touch the 255 or be higher For Local k%=0 Until 44100 RohWert[k]=RohWert[k]/maxwert Next 2. Wrong zero point alignment, a volume-value of 0 should result in a 128 For Local k%=0 Until 44100 sample.samples[k]=(RohWert[k]*127.0+128) Mod 256 Next 3. The 100 Start- and 100 End- values of a sample need to form a locigal curve. ' altes Sample wegen Knacksern ausblenden For Local hh#=100 To 0 Step -3 SetChannelVolume Channel1,hh/100 Delay 1 Next ' Sound aus Sample erzeugen sound:TSound=LoadSound( sample,True ) StopChannel Channel1 channel1=CueSound(sound) SetChannelVolume Channel1,0 ResumeChannel Channel1 ' neues Sample wegen Knacksern einblenden For Local hh#=0 To 100 Step 3 SetChannelVolume Channel1,hh/100 Delay 1 Next EndIf |
| ||
The sound distortion might come from the "streaming code". If you preallocate the sample and fill it with the needed data, it should work. But if you pre-define everything, checkout CreateStaticAudioSample() CreateAudioSample() Or check out this Thread. bye Ron |
| ||
Hi Derron and company. Here is the best I have gotten so far in creating pitch playing. If I can do away with the opening and ending click or gurgle, I may be able to write a useful function to give users the ability to generate sound much like you could do with the PC speaker years ago. . . . To answer the above, FreeStream16 does not maintain a solid note, it wavers like getting a reception on a radio. |
| ||
UsingSetAudioDriver "OpenAL"Seems to remove most of the popping for me, but there is still one at the end with your sample. You will need to have OpenAL installed for this driver to work though. Loading one from a file has no clicking, so i suspect the waveform that you generate is not correct as Midimaster suggested. After some searching i found a way to generate a sine wave here. The result is below, with no popping. I have no idea what im doing here btw, i just fudged the numbers until a reasonable sound came out ;) SuperStrict SetAudioDriver "OpenAL" Local sample:TAudioSample=CreateAudioSample( 3000,11025,SF_MONO8 ) Local amplitude:Float = 255 Local samplerate:Float = 11025 Local frequency:Float = 11025 Local phase:Float Local delta:Float = 2.0 * Pi * frequency / samplerate For Local k:Int=0 Until 3000 sample.samples[k]=amplitude * Sin(phase) phase :+ delta Next Local sound:TSound=LoadSound(sample) PlaySound sound InputAlso searched the forum and found this: Realtime Synthesis with openAL Should give you something to chew on for a while ;) |
| ||
The ending pop happens becuase the value in the wave at the end is not 127 (middle for 8bit samples). For exmaple if you fill it with any constant value, you would get silence, but at the end it would trip down to zero, so if that trip is.. large enough, then we hear a pop. If I could lend that code above and show what I mean SuperStrict SetAudioDriver "OpenAL" Local sample:TAudioSample=CreateAudioSample( 3000,11025,SF_MONO8 ) Local amplitude:Float = 255 Local samplerate:Float = 11025 Local frequency:Float = 11025 Local phase:Float Local delta:Float = 2.0 * Pi * frequency / samplerate For Local k:Int=0 Until 3000 sample.samples[k]=amplitude * Sin(phase) phase :+ delta Next ' Overwrite the waveform and using this wave instead. For Local k:Int=0 Until 3000 sample.samples[k]= 127 ' Fill the waveform with all middle value for a 8bit wave, means no pop at the end (fill with for example 0 or 255 or any value large enough from the middle, that would give silence with an ending pop) Next Local sound:TSound=LoadSound(sample) PlaySound sound Input The original code fills the wave with alternating 0 and 255 which basically creates a square wave, so whichever it starts or ends on 0 or 255, will make a pop. As it's not middle (127). Abrupt changes always creates pops with sounds. I would look into volume control first. Vvolume ramping is the most practical way as you need to do it alot. If you're doing softsynths then you could do it on the actual wave data without wasting any power, as you're building the waves anyways yourself. |
| ||
For a bit. Here is what I tried to work with:Strict SetAudioDriver "OpenAL" Global sample:TAudioSample=CreateAudioSample(256,22050,SF_MONO8 ) Local sound:TSound=LoadSound(sample),i For i=255 To 0 Step -1 tone i Delay 1 Next Input Function tone(n) Local a#=255,s#=11025,f#=11025,p#,d#=n/256.0*Pi*f*s,i For i=0 Until 256 sample.samples[i]=a*Sin(p) p:+d Next PlaySound LoadSound(sample) EndFunction But it doesn't create a high to low sound, just a weird warble. |
| ||
So the problem with dw817s sample had more to do with the sample rate(Hz) then, as he also use 127 for the entire sample. Maybe modern audio hardware just dont like weird sample rates? |
| ||
No he does not use 127 for the entire sample he fills every other byte. Thats key here. If he filled every then it would make perfect silence with no pops at ens or start. But he fills every other byte, that would make it into 0 127 0 127 0 127 which is a square. |
| ||
Ah yes, i forgot about that.. And i didnt notice as i was testing it, that he also skipped the last byte, making it always 0 ;) |
| ||
The original code clicks at the start (but not end) if you fill it with all 127's I don´t know why that is. It should not click at the start either. The next examples works as they should if you fill with 127 only (no clicks at all). EDIT I tried some things with the original to find what made the click adding SetAudioDriver "OpenAL" at the original code muffles the click it does not dissapear all the way, it just muffles it. I thought maybe it's the length or the odd samplerate. It was not the samplerate but the length. Changing from 256 to 3000 made the start click dissapear aswell perfectly. No idea why. Something with buffersizes I guess. |
| ||
Nope I was wrong, it was not the buffersize. I´m not sure what's difference that creeped between those two. I don't see it. But this does work perfectly. SuperStrict SetAudioDriver "OpenAL" Local sample:TAudioSample=CreateAudioSample( 256,11025,SF_MONO8 ) For Local k:Int=0 Until 256 sample.samples[k]= 127 Next Local sound:TSound=LoadSound(sample) PlaySound sound Input |
| ||
I find it amazing that OpenAl comes standard with Bmax I think I will open the manual for this one. Great potential. It seems that setting the driver sets some default parameters (filters etc). Looking into this, in practice you could build your own soundfontplayer by hand using this (it would be fun). |
| ||
Hi Casaber. Actually I don't hear anything here w this code. Now, if you change the until 256 to until 256 step 2 you get a harsh sound but an equally harsh click. Unless there is improvement I was thinking of dissecting a .WAV file tomorrow and see if it's possible to build one in BlitzMAX that can be 1/100th of a second and at any pitch, then load it and play it. |
| ||
Haha it's my offical hello world with sound. Silence without clicks ;) I´m buzy trying to understand the byte format when jumping into 16bit, look here. Mind you that I changed from 8bit into 16bit Little Endian. 8 bits sounds very harsch I guess you want that sometimes, but you could do that in 16bit aswell by double everything (like zooming pixels and make them retro graphic pixels) I think I´m just tired now, but it seem like it uses bytes when you read it. Also as you can see I got the content wrong, the sinue is fucked up. This is what I call, the first step learning a tool aka the swearing period. SetAudioDriver "OpenAL" Graphics 800,600 Const SampleSize:Int = 100000 Global sample:TAudioSample = CreateAudioSample(SampleSize, 44100, SF_STEREO16LE) Global sampleData:Byte[SampleSize] Print sample.length ; Print getSampleLength(sample) SeedRnd MilliSecs() For Local m:Int = 0 Until SampleSize sample.samples[m] = Sin(m)*128 ' sample.samples[m] = 32767 ' 65535 ' uncomment for the byte test Next Local sound:TSound = LoadSound(sample) Local channel:TChannel = PlaySound(sound) Repeat Cls If channel.playing() Then drawWave(sample) If KeyDown(KEY_SPACE) And Not channel.playing() Then channel = PlaySound(sound) Flip Until KeyDown(KEY_ESCAPE) End Function getSampleLength:Float(sample:TAudioSample) Return Float( (sample.length / Float( (sample.hertz * 60) ) ) * 60) End Function Function drawWave(sample:TAudioSample) For x = 0 Until sample.length Step 1 y = sample.samples[x] if y = 32767 then end ' if found 32767 as setup above (but it's never found, its a wrapping byte) Plot x,y Next End Function |
| ||
oops Stereo I saw that now. That explains the sinus. Okay, but that's probably not everythng wrong with it. This is one of those things you need to sit down and take your time with. Is it okay if I skip this one? Lots of details to learn with Bmax. I can't even get my white noise random generator to work in Bmax which is frustrating (There's no long unsigned). btw this is it if your interested for later, it's perfect for explosions and shoots, it's short and sweet, it's a common "linear congrunetial" but its very cheap. I guess that maters only when you do realtime synthesis. But, it doubles as an allaround random number generator. ' White noise or pseudo random numbers. Seed with anything. Function RandomNumber:Long() Seed = (Seed * 196314165) + 907633515 Return Seed End Function |
| ||
some changes from me: more is not possible... I think the best would be to define a ring buffer and send samples continously direct to openal. I did something similar in my "recorder". http://www.blitzbasic.com/Community/posts.php?topic=90830 But there it was a ring buffer for fetching audio in. The same must be possible for audio out. found this: http://www.blitzbasic.com/Community/posts.php?topic=95529 |