The PLAY [string] command, and the latest beta

Started by rpnielsen, November 11, 2024, 02:09:50

Previous topic - Next topic

rpnielsen

Thank you, Chris, for looking into the issues with the PLAY [string] command..

I have installed the new beta update, and the DELAY command at least seem to work within an acceptable margin.

As for the PLAY command: Yes I believe I can hear that there is now at least some differentiation in the pauses between the notes. But I have to say it still don't sound right.. - I tested it using the example tune; Menuet by J.S.Bach, from the github reference..

Just before the new update I finished a program that use the SOUND command to play each note of the tune with the right timing as intended. And before the update it worked perfectly. After the new update though I have to change "T180" to "T120" or less, to slow down the tempo of the tune, before it will play right. - Using the PLAY command to play the same (thus slowed down) string, on the other hand, still suffers some long pauses in odd places.

---

Before the new update i tested the PLAY [string] command the same way as I had done with DELAY, and I found that each note plays longer than it should. That led me into a more thorough study of the notes durations at different specifications of tempo/length.

Conclusions summarized
(Note that these findings are from before the new update, so I'm not sure to what extend they still apply after the update, but as my trying it out with the Menuet string showed there clearly still remain some issues.)

As i mentioned, each note plays longer than it should, and the shorter the duration of the notes the longer the average deviation. (Not just by percentage, but in absolute terms by number of milliseconds).

Moreover, and especially with shorter note durations, the note sequence gets interrupted by random "hiccups" of short pauses of ca 100-200 ms in between notes. These 'hiccups' occur more frequently the shorter the notes are. Ie with notes shorter than 250 ms they occur so frequently that (in tests of whole sequences of many notes) the extra delay caused by this became practically indistinguishable from the general average background deviation, thus rendering it pointless to do further testing on note durations shorter than 250 ms.

Taking audio recordings of some of the test sequences into Audacity audio editor, revealed a couple of interesting things:

First: The sound itself (ie attack+sustain+release) are generally shorter than the supposed playtime (ie for a supposed 1000 ms note, the sound part is only abt 975 ms - while, for a supposed 250 ms note, the sound is abt 225 ms). The rest is pause before the next note.

Second: More than half the notes lacked the "release" part. In stead, for these notes, the sound wave is abruptly cutoff at the end of the "sustain", usually followed by afew ms of low-amplitude rubble.

Third: The earlier described "hiccups" are without exception those of the (supposed 250 ms) notes which DO have the "release" part. HOWEVER it is not the release itself that takes up the extra time, but the pause after the release are more than twice as long as compared to the pauses after the notes which do not have a release.

I hope these findings might be helpful to clue you in on what might be causing the troubles

---

Now back to the latest update and the PLAY command as it is now:

from my testing with the Menuet string, as I mentioned in the beginning, the "hiccups" clearly still occur. And they even seem to have gotten worse, in terms of how short notes can be before they become a problem.

Very clearly, just from the way the notes sound now, the wave form have changed. A quick look in Audacity reveals that the notes no longer have the sustain part, but now consist only of an attack followed by a release.

I have to say I liked the old sound better, especially the long attack bothers my ear. But personal preference aside I think there are points could be made for why having the note be just a long attack followed by a release, leaving out the sustain, is a less than good idea. Such as f.ex if you want to make like a piano key that plays until you let go of the key, then you need to have a very long note sustain a constant amplitude until you stop it with the nosound command.

Which by the way leads me to mentioning that the NOSOUND command also don't work. It has no effect at all.


But anyways, I hope all this can be helpful and that you can get the PLAY command to work right.

Kind regards.

chrisws

Thanks for your detailed report. I'll make another attempt at another update this weekend. 
If possible could you please provide a simple test program to help verify the changes. Perhaps with forground play with expected time duration.
Cheers,
Chris

rpnielsen

Quote from: chrisws on November 13, 2024, 21:33:52could you please provide a simple test program to help verify the changes. Perhaps with forground play with expected time duration.
Sure. Here is a test program that does 5 loops of timing the duration of playing 10 notes, and tells you the supposed duration vs the actual average duration, plus the average deviation in ms as well as by percentage.
To test different note duration times you can change the tempo and note length. (I set default tempo to 240 because that gives nicely 1 full note pr second). As far as I can see the particular tempo vs lenght parameters are not important, what matters is the duration of the note to play (ie whether tempo=240 and length=1, or tempo=120 and length=2 - either way the (supposed) duration is 1 second).

nrtests=5
tempo=240 '1/4 notes pr min
length=4  'play 1/x notes

expDur=(240000/tempo)/length

play "V10O3T"+tempo+"L"+length

? nrtests;" tests of 10 1/";length;" notes"
? "at tempo = ";tempo;" 1/4 notes pr minute"
? "Expected note duration = ";expDur;" ms."
? "--------------------------"
?

for a=1 to nrtests
  delay 50 'because otherwise nothing is printed to screen until after PLAY is done
  t=ticks
  play "CDEFGGFEDC"
  actDur=(ticks-t)/10
  dev=actDur-expDur
  ? "Test ";a
  ? "Average note duration = ";actDur;" ms."
  ? "Deviaton = ";dev;" ms = ";((actDur/expDur)-1)*100;" %"
  totalDur=totalDur+actDur
  totalDev=totalDev+dev
  ?
next a

? "Overall average:"
? "Duration  = ";totalDur/nrtests;" ms"
? "Deviation = ";totalDev/nrtests;" ms = ";(((totalDur/nrtests)/expDur)-1)*100;" %"

end

I hope you'll find it useful.

chrisws

I tried a few different audio player libraries and finally settled on something that seems to work reasonably well.

With your test program (which is awesome by the way) - I get an average duration ~254.5 ms.

Originally there was a "ramp" (attack-sustain-release) which I'd messed around with to compensate for audio-player issues. 

Currently this isn't implemented, it seems fine without it. 

I'll upload another test release in the next day or so, for you to try.

rpnielsen

Thanks for the fix. With the new update the timing works alright as it's supposed to, and there don't seem to be any of the 'hickups'. And the nosound command works too.

'Only little thing is that there are now audible clicks at the onset and end of each note.

As far as I can detect this is specifically the case where one note starts immediately as the previous note ends, or where a note is followed by a pause. And taking the audio recording into Audacity it looks to me like the reason is the audio wave is briefly deformed on the transition between notes as well as on the transition between a note and a pause - or, in the latter case, more specifically on the transition between the sustain and the release

I notice that with the new update only notes that are followed by a pause have a release - otherwise the sustained frequency is simply followed directly by the next sustained frequency. And I'd like to make the point that this (had it not been for the clicks) could actually be useful, f.eks to drag out a note indefinately by simply playing the same note repeatedly, or to create effects like fading in or out or changing frequency gradually.. Though, as I said, had it not been for the clicks.

But the clicking sound aside, on overall it's a very good fix and now everything works like it's supposed to.

chrisws

I made a couple of updates over the weekend. The final one is still "in review". This should hopefully remove most of the artefacts between notes. 
- If you call SOUND twice with the same frequency, the second instance should continue the phase of the waveform from the first one.
- When a sound has completed, it will continue with silence for a short period to avoid stopping and restarting the player in case you have a delay between notes.

rpnielsen

The clicks are still there. Except if I play the same note repeatedly, then yes it just continues as one continuous tone (which is great by the way) without the clicks. This goes for PLAY as well as for SOUND. But in any other scenareo the clicks are still there.

chrisws

I've just added another update which goes some way towards resolving the clicks issue. I've got some ideas for further improvements but that will have to wait for now.

rpnielsen

Yes. Thank you very much. It sounds good now, and using the SOUND command I can even make smooth fades of the volume, or gradual change of pitch.. As long as I use background. However, when I play in foreground (which I normally wouldn't though, so that's not much of a problem to me) I still get the clicking noises, especially for short-duration notes.

I'd like to mention also that even though when in context of simple test programs it all seems fine, but when I use that program I have mentioned earlier, that use the SOUND command to play the string (which plays in background by the way), for some reason I get lots of clicking.. For now I'll assume that's propably something to do with my program rather than with the SOUND command. - But as that program is rater complex I'll have to investigate further before I can say anything more specific.

But at least in any simpler testing context the latest beta seems to work fine and without clicking. - As long as I play the sound as background. 

Midimaster

#9
I follow your conversation and guess, what is the reason for the clicks you get.

Perhaps I can help, but I would need more information about, what you are doing with the sounds.
Normally such clicks appear when you  start or stop a SampleSound not at its ZERO-CROSSING.

I know this effects, when experimenting with cutting Samples and play the sections of it separately. The sudden start in the middle of a top phase of a wave make the speakers clicking.

You have to take care, that the very first sample value ( at the begin of the file) is 0 followed by a zone of 150 sample points with increasing volume from 0 to normal level. This prevents the speakers from crackling. This "fade-in" is not audible, because in an 48kHz Sample this lasts only 3msec. Do the same before the end of a sample. During the last 150 sample points fade the sample value down to 0.

Check your sample files with AUDACITY. Have a look at begin and end of the sound with an extrem ZOOM. Does it start at the Zero line?

The fade-in and fade-out can be done already in AUDACITY, then save the sound. Maybe this can be also processed in your BASIC in real-time, if your SmallBasic audio-port supports real-time-sample-manipulation for single sample values.

ClickSoundProblem.png

Here you see the problematic beginning and ending of an audio file. And in the second row you see the solution: fade-in and fade-out (here within 15msec = 750 sample points. Too wide! Only for making it visible)

This Audio-File makes the Screenshot audible. you will here 3 times the upper sample (with crackle), followed by three times the lower sample (with Fad-In and Fade-Out)
https://www.midimaster.de/fremde/SampleClick.mp3
...back from North Pole.

Baggey

I see the use of the Fade in and Fade out effect and hear it.

When you say the Zero Crossing. I under stand that to be sin(0) or Sin(360) or sin(2*PI).

Could you not just like find the equation of the line for f(x)? and just stop your sound at point X=0. Or would that still cause clicks.

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

perfect suggestion, Baggey.

Instead of preparing each Audio-File with adding a Fade-In and a Fade-Out, the player app can do that "on-the-fly".

But therefore the BASIC language needs a feature of manipulating single sample values in real-time.

Also BlitzMax was not able to do that, until the MiniAudio-Module came. The RingBuffer I wrote for you some years ago was a first try to manipulate the PlaySound() command with a real-time feature. But it was not perfect

Now we have the MiniAudio-Module for BlitzMax NG and now those things are super-easy: Realtime-Systhesis, Realtime-Filters, Equalizer, Latency-free-recording and Playback, etc...

I do not know whether SmallBasic has such features. Let us looking forward to the answers we will receive here...
...back from North Pole.

rpnielsen

Quote from: Midimaster on December 03, 2024, 00:30:26You have to take care, that the very first sample value ( at the begin of the file) is 0 followed by a zone of 150 sample points with increasing volume from 0 to normal level. This prevents the speakers from crackling. This "fade-in" is not audible, because in an 48kHz Sample this lasts only 3msec. Do the same before the end of a sample. During the last 150 sample points fade the sample value down to 0.
I have tested what you suggest in audacity, by generating 250 ms sine wave pieces, faded in and -out over 150 sample points, and stringing the pieces together.. I have to say the transition between notes is not completely inaudible, at least not when you continue with the same frequency. The short fadeout and fadein can be heard as a faint 'flop'.. But as an alternative to the clicking sound I agree it's a much better option..

But just to put it out there (mby a dumb question - I'm not an expert of audio generation - but..) Would it not be possible to simply make sure that each note start and end on the zero-line? (beginning towards a wave top and ending after a wave valley, or vice versa) - If that is possible that would make sure each next note can follow seamlessly upon the previous one.

chrisws

Desktop SmallBASIC uses mini-audio. For the android version that we're discussing here, I'm now using google's oboe library: https://github.com/google/oboe

Seeing that audacity screenshot made me think there must be someway to get the audio out of the android virtual-device. It turns out to be very simple, just hit record in Audacity and pulse-audio does the magic.

The first thing I noticed is when there's a pause (segment of silence) the adjoining non-silent wave-forms are out of phase.

Btw - fun project, use the light sensor in a loop as input to SOUND :)


Midimaster


 
Quote from: rpnielsen on December 03, 2024, 19:15:19...I have to say the transition between notes is not completely inaudible ...

Then reduce the zone size from 150 sample points to 50  or 15 and listen to the quality now. 150 is more to see as a maximum. It works also with much smaller zones. I told you 150 only for a good (already audible) demonstration of the effect.



Quote from: rpnielsen on December 03, 2024, 19:15:19Would it not be possible to simply make sure that each note start and end on the zero-line? (beginning towards a wave top and ending after a wave valley, or vice versa)
Yes this is 100% possible. There are two strategies:

1.
You wait until the wave reaches the zero-point. Then start the new frequency with 0.


...or...

2.
You can start a new frequency whenever you like as long as you do not start it at 0, but at the arc, that was given by the prior wave.

Read my oscillator tutorial here in syntaxbomb. 

tutorials/synthesizer-in-blitzmax-for-beginners/


A Sinus-Oscillator produces SINUS waves by adding the variable ArcAdd:Double to its variable Arc:Double. The Arc runs MOD 360.  Each step the oscillator calculates SIN(Arc) and return the result as audiosample-value.

Higher Frequencies have only bigger ArcAdd. This makes the Oscillator running faster.

But for a certain Arc the result of SIN(Arc) is always the same value, no matter which frequency it produced. e.g. the SINUS(33°) is always 0.5446390350.

So if you code your frequency change only with a change of ArcAdd and use the same oscillator, the wave will seamless continue, where the prior wave was.

But as I do not know, what is the target of your project is, I have no chance to give better advises,


The crackling problem


SINUS-Oscillators do not produces crackling because the sample-values are smoothly changing.

SQUARE-Oscillators should in theory change between -1 and +1. This per-se produces crackling. This is why all producer of digital SQUARE wave or PULSE-wave use the moment of change from -1 to +1 to insert a 0 into the stream instead of the correct result +1. The same with the moment of change from +1 back to -1:They insert again 0 into the stream instead of the correct result -1. This prevents the crackling and reduces the problem of too many unliked overtones or sub-notes.


MiniAudio

MiniAudio is the best thing that can happen to you, when your target is good audio quality (music producer, etc..). The quality and possibilities are incredible good. Do you have in SmallBasic direct access to it's CallBack-Function?





...back from North Pole.