|
Post by Pjot on Sept 23, 2017 14:58:01 GMT 1
Hi vovchik, Your link points to this forum, I guess you mean this library? Looks very interesting indeed, and thanks for the nice small soundfonts - I am going to check this out right now! Best regards Peter
|
|
|
Post by vovchik on Sept 24, 2017 9:18:14 GMT 1
Dear Peter, Sorry about the bad link - your link is correct. I have already tested and am attaching two working BaCon examples. I like it in that it is self contained. With kind regards, vovchik UPDATED ARCHIVE: Added third demo, reading in soundfont as memvar and compiling into code - so that the resulting executable is totally self-contained. Attachments:tiny_midi.tar.gz (123.62 KB)
|
|
|
Post by Pjot on Sept 24, 2017 12:11:10 GMT 1
Thanks vovchik, I got it working with OpenAL, see the below. However, I am still struggling with the duration of the notes. They all seem to render for 1 second, not sure how to set the duration properly, looking into it... Best regards Peter INCLUDE openal.bac
PRAGMA INCLUDE TinySoundFont-master/tsf.h : ' Include the TinyFonts header file
PRAGMA OPTIONS -DTSF_IMPLEMENTATION
CONST TSF_Rate = 44100 CONST TSF_Chunk = 44100 : ' Same as sample rate
RECORD TSF LOCAL tinysf TYPE tsf* LOCAL buffer[1] TYPE int LOCAL source TYPE int END RECORD
TSF.tinysf = NULL
PROTO tsf_set_output, tsf_note_off, tsf_note_on, tsf_render_short, tsf_close
TSF_VOICE = 0 TSF_VOLUME = 1.0
SUB TSF_FONT(font$)
IF NOT(FILEEXISTS(font$)) THEN EPRINT "ERROR: cannot find file '", font$, "'! Exiting..." END 1 END IF
TSF.tinysf = tsf_load_filename(font$)
END SUB
SUB TSF_PLAY(tone)
LOCAL state, which, processed TYPE int LOCAL data[TSF_Chunk] TYPE short
IF TSF.tinysf = NULL THEN EPRINT "ERROR: No font loaded! Exiting..." END 1 END IF
tsf_set_output(TSF.tinysf, TSF_MONO, TSF_Chunk, 0) tsf_note_on(TSF.tinysf, TSF_VOICE, tone, TSF_VOLUME) tsf_render_short(TSF.tinysf, data, TSF_Rate, 1)
' Error cleanup alGetError()
alGenBuffers(1, TSF.buffer) alBufferData(TSF.buffer[0], AL_FORMAT_MONO16, data, TSF_Chunk, TSF_Rate)
alGenSources(1, &TSF.source) alSourceQueueBuffers(TSF.source, 1, TSF.buffer)
alSourcePlay(TSF.source)
REPEAT alGetSourcei(TSF.source, AL_SOURCE_STATE, &state) UNTIL state <> AL_PLAYING
tsf_note_off(TSF.tinysf, TSF_VOICE, tone)
alDeleteSources(1, &TSF.source) alDeleteBuffers(1, TSF.buffer)
END SUB
SUB TSF_CLOSE
tsf_close(TSF.tinysf)
END SUB
OPENAL_INIT OPENAL_INFO
' Font TSF_FONT("/path/to/font/gorts_midget.SF2")
' Volume TSF_VOLUME = 0.8
' Voice TSF_VOICE=3
' Simple scale of notes. FOR note$ IN "56 58 60 62 64 65 67 69 71 72" TSF_PLAY(VAL(note$)) NEXT
TSF_CLOSE
OPENAL_FREE
|
|
|
Post by vovchik on Sept 24, 2017 15:11:32 GMT 1
Dear Peter, The duration is controlled here: tsf_note_off(my_soundfont, preset, note) tsf_note_on(my_soundfont, preset, note, duration(e.g 0.5f) That works for me... Some duration modification and an effects soundfont are in the archive. And your new canvas plugin will be ready soon. Nice work. With kind regards, vovchik Attachments:tiny_midi_sfx.tar.gz (413.29 KB)
|
|
|
Post by Pjot on Sept 24, 2017 16:26:53 GMT 1
Thanks vovchik, But strange ...as I understand this TinySoundFont library, the last argument in the 'tsf_note_on' function determines the 'velocity' meaning volume? So if I use this argument then I hear a softer tone. In any case, I have solved it now by working with buffer offsets, similarly as in the previous MML player. The final result can be found here. BR Peter
|
|
|
Post by vovchik on Sept 24, 2017 17:31:57 GMT 1
Dear Peter, The plugin works nicely - and voices change. You are entirely right about that third argument of tsf_note_on - it is velocity and not duration. Me bad. I think control of duration can achieved by introducing some delay, e.g. SDL_DELAY(1000) or SLEEP, before the tfs_not_off instruction. I have to look at that carefully again.... With thanks and kind regards, vovchik
|
|
|
Post by Pjot on Sept 24, 2017 17:53:31 GMT 1
Hi vovchik, I have improved the TinySoundFont plugin further, it is a separate include file now, like the other OpenAL plugins. There is a demo program here. Regards Peter
|
|
|
Post by vovchik on Sept 25, 2017 11:25:07 GMT 1
Dear all, This is a pretty wild demo of the Silly ROM soundfont using TinySoundfont code. The reason the attachment is so large is that all the TSF stuff is in there, as well as a header that contains the Silly ROM soundfont as a memvar. It is compiled into a program which, on my machine, yields a 270k executable. That is not so bad, considering that there is a sound bank with quite a few wave samples in there as well as the sound rendering engine from TSF. The sounds are pretty amazing and can be used nicely in games. I will see whether I can reduce the ~200k Silly ROM soundfont to around 60k by eliminating some voices and, maybe, downsampling from 44k to 22k. When the program ends, it copies out the Silly ROM soundfont (silly_rom.sf2) to the current directory, so you will hve it in that form, too. With kind regards, vovchik Attachments:sillysf_memvar.tar.gz (414.85 KB)
|
|
|
Post by Pjot on Sept 25, 2017 17:56:34 GMT 1
Thanks vovchik, Very funny sf2 indeed, I have used it in my demo program to listen to the examples again. The SoundFont / midi technology still is very useful! With the proper sound font any program can improve its attraction and the TinySoundFont keeps everything small. Regards Peter
|
|
|
Post by vovchik on Sept 26, 2017 15:21:50 GMT 1
Dear Peter (and all), I couldn't resist doing this, all the more that the PC speaker does not really work in many modern *nixes. It is beep program embellished by a soundfont. And it can actually play music, after a fashion. Here is a copy of the first part of the help: sfbleep is a supercharged beep command that makes use of an embedded soundfont. You can control the voice, the pitch, the duration and the amplitude of the sound.
Usage: sfbleep a b c d
where a = voice [0 to 212], b = note [0 to 125], c = duration in milliseconds and d = volume [0-100].
Enter sfbleep -l to see all available voices. I have included a script demo that actually plays a melody. Have fun. With kind regards, vovchik Attachments:sfbleep-src.tar.gz (258.86 KB)
|
|
|
Post by bigbass on Sept 26, 2017 16:25:01 GMT 1
Hey Vovchik Wonderful! da da da daaaaaaa / da da da daaaaaaa /da da da daaaaaaa finally there's sound coming out of this laptop A tech note I needed this sudo apt-get install libasound2-devfor the alsa header to be included I had tried all your other demos but as I said before I was missing something and couldnt figure out what it was this is perfect A big thanks for your persistence and creativity Joe
|
|
|
Post by vovchik on Sept 26, 2017 16:59:44 GMT 1
Dear Joe, Great that you got sound working. I found an easy way for sfbleep to do counterpoint and harmony in bash, of all things: #!/bin/bash
# Demo of sfbleep playing melodies - vovchik, 2017 # Les Parapluies de Cherbourg - over and over again # and somewhat humanized (e.g. duration and amplitude), # and harmonized.
# variable x is used for looping through all the voices (213) # variable y is transposition factor # melody consists of 32 notes # variable z is harmony voice
declare -i y=12 declare -i z=211 echo "--------------------------------------" echo "Playing Les Parapluies de Cherbourg" echo "using sfbleep's 213 soundfont presets." # loop through all the voices for x in {0..212}; do echo "--------------------------------------" echo "Soundfont voice $x is now playing..." echo "--------------------------------------" # transpose by 12 chromatic steps using y echo "********* Phrase 1 *********" ./sfbleep $x $((y+48)) 300 40 ./sfbleep $x $((y+50)) 300 45 ./sfbleep $x $((y+51)) 350 50 ./sfbleep $z $((y+41)) 1400 40& ./sfbleep $z $((y+44)) 1300 25& ./sfbleep $z $((y+48)) 1300 35& ./sfbleep $z $((y+51)) 1400 30& ./sfbleep $x $((y+56)) 1200 60 echo "********* Phrase 2 *********" ./sfbleep $x $((y+46)) 300 40 ./sfbleep $x $((y+48)) 300 45 ./sfbleep $x $((y+50)) 250 50 ./sfbleep $z $((y+39)) 1400 40& ./sfbleep $z $((y+43)) 1300 40& ./sfbleep $z $((y+46)) 1400 40& ./sfbleep $z $((y+50)) 1300 40& ./sfbleep $x $((y+55)) 1320 60 echo "********* Phrase 3 *********" ./sfbleep $x $((y+44)) 300 30 ./sfbleep $x $((y+46)) 300 45 ./sfbleep $x $((y+48)) 350 50 ./sfbleep $z $((y+38)) 1300 40& ./sfbleep $z $((y+41)) 1400 40& ./sfbleep $z $((y+44)) 1300 40& ./sfbleep $z $((y+48)) 1400 40& ./sfbleep $x $((y+53)) 1290 60 echo "********* Phrase 4 *********" ./sfbleep $x $((y+43)) 300 25 ./sfbleep $x $((y+45)) 300 35 ./sfbleep $x $((y+47)) 250 40 ./sfbleep $z $((y+36)) 1400 40& ./sfbleep $z $((y+39)) 1300 25& ./sfbleep $z $((y+43)) 1300 30& ./sfbleep $z $((y+46)) 1400 30& ./sfbleep $x $((y+51)) 1500 50 echo "********* Phrase 5 *********" ./sfbleep $x $((y+48)) 300 40 ./sfbleep $x $((y+50)) 300 45 ./sfbleep $x $((y+51)) 350 50 ./sfbleep $z $((y+29)) 1400 40& ./sfbleep $z $((y+41)) 1400 40& ./sfbleep $z $((y+44)) 1300 25& ./sfbleep $z $((y+48)) 1300 35& ./sfbleep $z $((y+51)) 1400 30& ./sfbleep $x $((y+56)) 1200 60 echo "********* Phrase 6 *********" ./sfbleep $x $((y+46)) 300 40 ./sfbleep $x $((y+48)) 300 45 ./sfbleep $x $((y+50)) 250 50 ./sfbleep $z $((y+27)) 1400 40& ./sfbleep $z $((y+39)) 1400 40& ./sfbleep $z $((y+43)) 1300 40& ./sfbleep $z $((y+46)) 1400 40& ./sfbleep $z $((y+50)) 1300 40& ./sfbleep $x $((y+55)) 400 50 ./sfbleep $x $((y+55)) 1080 60 echo "********* Phrase 7 *********" ./sfbleep $x $((y+44)) 300 30 ./sfbleep $x $((y+46)) 300 45 ./sfbleep $x $((y+48)) 350 50 ./sfbleep $z $((y+26)) 1200 40& ./sfbleep $z $((y+38)) 1200 40& ./sfbleep $z $((y+41)) 1300 40& ./sfbleep $z $((y+44)) 1200 40& ./sfbleep $z $((y+48)) 1300 40& ./sfbleep $x $((y+53)) 1390 60 echo "********* Phrase 8 *********" ./sfbleep $x $((y+50)) 250 25 ./sfbleep $z $((y+19)) 500 50& ./sfbleep $z $((y+31)) 500 50& ./sfbleep $z $((y+43)) 500 50& ./sfbleep $z $((y+47)) 500 30& ./sfbleep $z $((y+50)) 500 30& ./sfbleep $z $((y+53)) 500 30& ./sfbleep $x $((y+53)) 300 35 ./sfbleep $x $((y+51)) 250 40 ./sfbleep $z $((y+24)) 1400 40& ./sfbleep $z $((y+36)) 1400 40& ./sfbleep $z $((y+39)) 1300 25& ./sfbleep $z $((y+43)) 1300 30& ./sfbleep $z $((y+46)) 1400 30& ./sfbleep $x $((y+48)) 1500 50 done echo "--------------------------------------" echo "This sfbleep demo thankfully ended." echo "--------------------------------------" This is fun! With kind regards, vovchik
|
|
|
Post by Pjot on Oct 15, 2018 20:19:06 GMT 1
The sound architecture for the plugins always relies on the OpenAL library. The decoders for MIDI, FLAC, MP3 etc use OpenAL to render the decoded data to the sound hardware. +-----------------------------+ | Music File | +-----------------------------+ | Decoder | +-----------------------------+ | Open Audio Library | +-----------------------------+ | Computer Hardware | +-----------------------------+
Obviously, the disadvantage is that we always need OpenAL installed for BaCon to play music files. However, the same developer for the FLAC decoder now also has created a multiplatform audio library to render sound. It currently supports WASAPI, DirectSound, WinMM, Core Audio (Apple), ALSA, PulseAudio, JACK, sndio (OpenBSD), audio(4) (NetBSD and OpenBSD), OSS (FreeBSD), OpenSL|ES (Android only), OpenAL and SDL. The page for this one-header library called "MINI_AL" can be found here and is licensed under Public Domain or MIT. Below simple port of the main demonstration program, playing FLAC files. The package for Mini_Al also contains decoders for MP3, WAV, Vorbis, MOD and XM. It is very complete and allows independent OS builds (even for Android!). Enjoy, Peter PRAGMA OPTIONS -DDR_FLAC_IMPLEMENTATION -DMINI_AL_IMPLEMENTATION
PRAGMA INCLUDE mini_al-master/extras/dr_flac.h
PRAGMA INCLUDE mini_al-master/mini_al.h
PRAGMA LDFLAGS dl pthread
OPTION PARSE FALSE
DECLARE decoder TYPE mal_decoder DECLARE result TYPE mal_result DECLARE config TYPE mal_device_config DECLARE device TYPE mal_device
'-------------------------------------------------------------------------------------------------------------------
' This is the function thats used for sending more data to the device for playback. FUNCTION on_send_frames_to_device(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) TYPE mal_uint32
LOCAL pDecoder TYPE mal_decoder*
pDecoder = (mal_decoder*)pDevice->pUserData
IF pDecoder = NULL THEN RETURN 0
RETURN (mal_uint32)mal_decoder_read(pDecoder, frameCount, pSamples)
ENDFUNCTION
'-------------------------------------------------------------------------------------------------------------------
IF AMOUNT(ARGUMENT$) <= 1 THEN PRINT "No input file." END -1 ENDIF
result = mal_decoder_init_file(TOKEN$(ARGUMENT$, 2), NULL, &decoder)
IF result != MAL_SUCCESS THEN PRINT "Could not init decoder." END -2 ENDIF
config = mal_device_config_init_playback(decoder.outputFormat, decoder.outputChannels, decoder.outputSampleRate, on_send_frames_to_device)
IF mal_device_init(NULL, mal_device_type_playback, NULL, &config, &decoder, &device) != MAL_SUCCESS THEN PRINT "Failed to open playback device." mal_decoder_uninit(&decoder) END -3 ENDIF
IF mal_device_start(&device) != MAL_SUCCESS THEN PRINT "Failed to start playback device." mal_device_uninit(&device) mal_decoder_uninit(&decoder) END -4 ENDIF
PRINT "Press <ESC> to quit..." REPEAT key = GETKEY UNTIL key = 27
mal_device_uninit(&device) mal_decoder_uninit(&decoder)
|
|
|
Post by Pjot on Oct 16, 2018 20:49:03 GMT 1
For Android, the above program can be compiled in Termux as follows: And the FLAC player actually works... Regards Peter
|
|
|
Post by vovchik on Oct 16, 2018 21:30:20 GMT 1
Dear Peter, Thanks. It works great and the sound is beautiful. here is the sample flac I listened to: flac musicIt sounds superb. With kind regards, vovchik
|
|