Audio library for FreeBasic - Features
Re: Audio library for FreeBasic - Features
I present 2 files, one entry using sfx, the other using dosmid player. You can listen and make sure that sfx plays something incomprehensible under DOS:
Here is the dosmid entry (correctly played): https://disk.yandex.ru/d/6odNNDDQJtsorQ
Here's a sfx recording (incomprehensible music): https://disk.yandex.ru/d/lGb3XJ6LiSV0gw
Here's the original file midi: https://disk.yandex.ru/d/P7X_8HiAel5y3w
P.S. Under Linux and Windows, this file plays correctly.
P.P.S I use SoundBlaster on virtual system (freedos). Similarly, it sounds bad on a real computer with adlib.
Here is the dosmid entry (correctly played): https://disk.yandex.ru/d/6odNNDDQJtsorQ
Here's a sfx recording (incomprehensible music): https://disk.yandex.ru/d/lGb3XJ6LiSV0gw
Here's the original file midi: https://disk.yandex.ru/d/P7X_8HiAel5y3w
P.S. Under Linux and Windows, this file plays correctly.
P.P.S I use SoundBlaster on virtual system (freedos). Similarly, it sounds bad on a real computer with adlib.
Re: Audio library for FreeBasic - Features
I think the issue is a bad support for drums under sfx.
About the file onestop.mid, it is possible that it is a type 2 midi file?
About the file onestop.mid, it is possible that it is a type 2 midi file?
Re: Audio library for FreeBasic - Features
And why then on windows and linux the sound is normal? And the second question is: Can this be improved?
I don't know. I only know that this is a file that lies in a standard folder: C:\Windows\Media
I don't think microsoft would put a non-standard or bad file in the windows.
Re: Audio library for FreeBasic - Features
Because if it's the case, the issue would be in the part of code used to translate the MIDI command into OPL commands. Under Windows or Linux the library doesn't use that part of the code, but it relies on the OS-specific implementation (or, in Linux, loads a small software synthesizer)
I think it can be improved, but I am not sure how complex is the task
Type 2 MIDI files are standard, they are just pretty uncommon. Type 2 is a specific format, not supported in my library, that allows to have several different songs inside a single MIDI file.
I don't know. I only know that this is a file that lies in a standard folder: C:\Windows\Media
I don't think microsoft would put a non-standard or bad file in the windows.
Re: Audio library for FreeBasic - Features
Then at least the library should have a check (if tracks > 16 then ....). Currently crash program if tracks > 16.
Re: Audio library for FreeBasic - Features
In LoadMidi there is the line:
that stops the load if the type is not 0 or 1. Is it executed or not? (if the load fails and you try to play the null audio, it would crash anyway)
Code: Select all
if b[1]>1 then delete Midi: close F:return 0 'Not a supported format
Re: Audio library for FreeBasic - Features
The error (segmentation fault) is here , if tracks = 17:
Code: Select all
Midi->Track(I)=left(input(TrackLength,F), TrackLength-4)
Re: Audio library for FreeBasic - Features
What happens if you change the value of the const?
Re: Audio library for FreeBasic - Features
So try it yourself.
And by the way, here is the player for DOS: https://bisqwit.iki.fi/jutut/kuvat/prog ... iplay.html
He can play any midi files. The only downside is that it loses at a faster rate (+20%). The source code is of course solid spaghetti, but maybe this will help you figure it out.
Re: Audio library for FreeBasic - Features
I cannot try because I don't have that midi file.
Re: Audio library for FreeBasic - Features
Here is the file: https://dropmefiles.com/ruS2I
Re: Audio library for FreeBasic - Features
Debian and Lubuntu have the same behaviour. The sound is audible but distorted.
With timidity -iA the sound gets good but stumbles a bit.
Lubuntu with Ubuntu Studio gives a good sound without disturbance. (And without timidity.)
I tried longint in sequencer.bi and sleep in playtomidi.bas and could not find a difference.
I am interested in the DSP feature of sfx. The following program crashes with SoundSet(44100,1,8).
It runs if screenres is commented out, or if the last allocated buffer (pWave(10)) is not used.
With timidity -iA the sound gets good but stumbles a bit.
Lubuntu with Ubuntu Studio gives a good sound without disturbance. (And without timidity.)
I tried longint in sequencer.bi and sleep in playtomidi.bas and could not find a difference.
I am interested in the DSP feature of sfx. The following program crashes with SoundSet(44100,1,8).
It runs if screenres is commented out, or if the last allocated buffer (pWave(10)) is not used.
Code: Select all
#cmdline "-mt -exx"
#include "sfx.bi"
#inclib "fbsfx"
dim as long buffersize,i
dim as single d=5
dim as integer samplerate,channels,bits
samplerate=44100
channels=1
bits=8
SoundSet(samplerate,channels,bits)
dim shared as WaveHeaderType ptr pWave(1 to 10)
buffersize=samplerate*d
for i=lbound(pWave) to ubound(pWave)
pWave(i)=CreateWave(buffersize,samplerate,channels,bits)
next i
print "AAA"
sleep 1000
Sound pWave(10),0,SineWave(440),d
'Sound pWave(10),0,DSPWave(pWave(5)),d
screenres (400,300)
print "End of program, any key to quit."
sleep
Re: Audio library for FreeBasic - Features
@angros47
found the reason for the crashes. Line 568 in SoundFunction.bas should be:
for i as integer=0 to samples - 1
As the seven corresponding lines above in the two sound subroutines.
found the reason for the crashes. Line 568 in SoundFunction.bas should be:
for i as integer=0 to samples - 1
As the seven corresponding lines above in the two sound subroutines.
Re: Audio library for FreeBasic - Features
Or in your program you can change the line:
to
Code: Select all
buffersize=samplerate*d
Code: Select all
buffersize=samplerate*d +1
Re: Audio library for FreeBasic - Features
I tried your proposal in my programs. It seems to work, thank you.
My functions work with gas32,gas64 and gcc64. They do not work with gcc32.
Therefore I replaced the sfx internal variable __Samplerate by the own variable samplerate:
My functions work with gas32,gas64 and gcc64. They do not work with gcc32.
Therefore I replaced the sfx internal variable __Samplerate by the own variable samplerate:
Code: Select all
'' https://www.freebasic.net/wiki/ExtLibsfx
'' https://en.wikipedia.org/wiki/Piano_key_frequencies
#cmdline "-mt -exx"
#include "sfx.bi"
#inclib "fbsfx"
dim shared as long samplerate,channels,bits
samplerate=44100
channels=1
bits=16
SoundSet(samplerate,channels,bits)
''===================================================
type ExpADEnvelopeFunction extends SoundFunction
Max as double
Pow as double
Amplitude as double
declare function GetNext() as single
end type
function ExpADEnvelopeFunction.GetNext() as single
dim as double arg,arg2,arg3
arg=t/(Max*samplerate)
arg2=(arg/Pow)^Pow ' (arg^Pow)/(Pow^Pow)
arg3=(arg2)*exp(Pow-arg)
if arg3 > 1 then arg3=1
if arg3 < 0 then arg3=0
t+=1
if child=0 then
return (2*arg3*Amplitude-1)
else
return arg3*Amplitude*(child->getnext)
end if
end function
function ExpADEnvelope overload(Pow as double, Max as double, Amplitude as double=1) as ExpADEnvelopeFunction ptr
dim w as ExpADEnvelopeFunction ptr=new ExpADEnvelopeFunction
w->Pow=Pow
w->Max=Max
w->Amplitude=Amplitude
return w
end function
function ExpADEnvelope overload(func as any ptr, Pow as double, Max as double, Amplitude as double=1) as ExpADEnvelopeFunction ptr
dim w as ExpADEnvelopeFunction ptr=new ExpADEnvelopeFunction
w->child=func
w->Pow=Pow
w->Max=Max
w->Amplitude=Amplitude
return w
end function
''===================================================
sub ShowWave(buffer as WaveHeaderType ptr)
open cons for output as #1
print #1, mkl(buffer->RiffID),"RIFF"
print #1, buffer->RiffLength,"Riff Length = File Length - 8"
print #1, mkl(buffer->WavID),"WAVE"
print #1, mkl(buffer->FmtID),"fmt "
print #1, buffer->FmtLength,"Fmt Length (16)"
print #1, buffer->wavformattag,"Format Tag (1: PCM)"
print #1, buffer->Channels,"Channels"
print #1, buffer->SamplesPerSec,"Sample Rate"
print #1, buffer->avgBytesPerSec,"Bytes/Second"
print #1, buffer->blockalign,"Block Align"
print #1, buffer->FmtSpecific,"Bits/Sample"
print #1, mkl(buffer->DataID),"data"
print #1, buffer->DataLength,"Data Length = File Length - 44"
print #1, string (44,"=")
close #1
'------------------------------------------------
dim as ulong i
dim as long x,y
x=400 : y=300
screenres (x,y)
cls
if (buffer->Channels) = 2 then line (0,y\2)-(x,y\2),10
if (buffer->Channels) = 1 then
if (buffer->FmtSpecific) = 16 then
'Print "1,16"
window (0,-32768)-((buffer->DataLength)\2,32767)
dim as short ptr SourcePtr=cast(short ptr,(cast(byte ptr,buffer)+44))
for i=1 to (buffer->DataLength)\2
pset (i-1,SourcePtr[i-1])
next i
else
'print "1,8"
window (0,0)-((buffer->DataLength),255)
dim as ubyte ptr SourcePtr=cast(ubyte ptr,(cast(byte ptr,buffer)+44))
for i=1 to (buffer->DataLength)
pset (i-1,SourcePtr[i-1])
next i
end if
else
if (buffer->FmtSpecific) = 16 then
'print "2,16"
window (0,-32768)-((buffer->DataLength)\2,32767)
dim as short ptr SourcePtr=cast(short ptr,(cast(byte ptr,buffer)+44))
for i=1 to (buffer->DataLength)\2 step 2
pset (i-1,SourcePtr[i-1]\2+16384)
pset (i-1,SourcePtr[i]\2-16384)
next i
else
'print "2,8"
window (0,0)-((buffer->DataLength),255)
dim as ubyte ptr SourcePtr=cast(ubyte ptr,(cast(byte ptr,buffer)+44))
for i=1 to (buffer->DataLength) step 2
pset (i-1,SourcePtr[i-1]\2+128)
pset (i-1,SourcePtr[i]\2)
next i
end if
end if
end sub
''===================================================
'sfx initialises with zeros (function CreateWave in wave.bas).
'In some cases (MixWaves) it is useful to initialise 8-bit files with 127 or 128.
'sfx uses 127.
sub Init8BitWave(buffer as WaveHeaderType ptr)
if (buffer->FmtSpecific) <> 8 then exit sub
dim as ulong i
dim as ubyte ptr bptr=cast(ubyte ptr,buffer)
for i=0 to (buffer->DataLength)-1
bptr[i+44]=127
next i
end sub
''===================================================
print "Please wait..." : locate 1
dim as long buffersize,i
dim as single start,duration
'' n: Midi note number, d: duration
dim as single n(1 to ...)={ 69, 69}
dim as single d(1 to ...)={1.8,9.5}
function MidiNoteToFrequency(n as single) as single
return (2^((n-69)/12))*435 ' 440
end function
'calculate duration
duration=0
for i=lbound(d) to ubound(d)
duration+=d(i)
next i
''------------------------------------------
dim shared as WaveHeaderType ptr pWave(1 to 16),mWave(1 to 14),sWave,eWave
buffersize=samplerate*duration + 3
for i=lbound(pWave) to ubound(pWave)
pWave(i)=CreateWave(buffersize,samplerate,channels,bits)
Init8BitWave(pWave(i))
next i
for i=lbound(mWave) to ubound(mWave)
mWave(i)=CreateWave(buffersize,samplerate,channels,bits)
Init8BitWave(mWave(i))
next i
dim as single ed=1
eWave=CreateWave(samplerate*ed+1,samplerate,channels,bits)
Sound eWave,0,ExpADEnvelope(1,0.1,0.8),ed
start=0.2
sWave=CreateWave(samplerate*(duration+start),samplerate,channels,bits)
Init8BitWave(sWave)
dim shared as single Pow=0.4,Max=0.4
sub tone(start as single,n as single,d as single)
Sound pWave(1),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n-12)),Pow,1,0.5),d
' Sound pWave(2),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n)),Pow,0.1,0.25),d
Sound pWave(3),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n)),Pow,Max,1),d
Sound pWave(4),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+3)),Pow,Max,0.73),d
Sound pWave(5),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+7)),Pow,Max,0.4),d
Sound pWave(6),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+12)),Pow,Max,0.95),d
Sound pWave(7),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+16)),Pow,Max,0.5),d ' (!)
Sound pWave(8),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+17)),Pow,Max,0.25),d
Sound pWave(9),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+17+0.01)),Pow,Max,0.25),d
Sound pWave(10),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+19)),Pow,Max,0.9),d
Sound pWave(11),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+21)),Pow,Max,0.75),d
Sound pWave(12),0,ExpADEnvelope(SineWave(MidiNoteToFrequency(n+24)),Pow,Max,1),d
' Sound pWave(13),0,...
' Sound pWave(14),0,...
' Sound pWave(15),0,...
' Sound pWave(16),0,...
'---
Sound mWave(1),0,MixWaves(DSPWave(pWave(1)),DSPWave(pWave(2))),d
Sound mWave(2),0,MixWaves(DSPWave(pWave(3)),DSPWave(pWave(4))),d
Sound mWave(3),0,MixWaves(DSPWave(pWave(5)),DSPWave(pWave(6))),d
Sound mWave(4),0,MixWaves(DSPWave(pWave(7)),DSPWave(pWave(8))),d
Sound mWave(5),0,MixWaves(DSPWave(pWave(9)),DSPWave(pWave(10))),d
Sound mWave(6),0,MixWaves(DSPWave(pWave(11)),DSPWave(pWave(12))),d
' Sound mWave(7),0,MixWaves(DSPWave(pWave(13)),DSPWave(pWave(14))),d
' Sound mWave(8),0,MixWaves(DSPWave(pWave(15)),DSPWave(pWave(16))),d
'---
Sound mWave(9),0,MixWaves(DSPWave(mWave(1)),DSPWave(mWave(2))),d
Sound mWave(10),0,MixWaves(DSPWave(mWave(3)),DSPWave(mWave(4))),d
Sound mWave(11),0,MixWaves(DSPWave(mWave(5)),DSPWave(mWave(6))),d
' Sound mWave(12),0,MixWaves(DSPWave(mWave(7)),DSPWave(mWave(8))),d
'---
Sound mWave(13),0,MixWaves(DSPWave(mWave(9)),DSPWave(mWave(10))),d
Sound mWave(14),0,MixWaves(DSPWave(mWave(11)),DSPWave(mWave(12))),d
'---
Sound sWave,start,Panning(MixWaves(DSPWave(mWave(13)),DSPWave(mWave(14))),,2.7),d ' Amplify with Panning
end sub
'fill buffers
for i=lbound(d) to ubound(d)
tone(start,n(i),d(i))
start+=d(i)
next i
''-------------------------------
ShowWave(eWave)
print "Any key to continue..."
sleep
ShowWave(sWave)
'SaveWave("envelope.wav",eWave)
'SaveWave("test.wav",sWave)
PlayWave(sWave)
sleep
Last edited by hhr on Nov 05, 2022 8:23, edited 2 times in total.