schellingb / tinysoundfont Goto Github PK
View Code? Open in Web Editor NEWSoundFont2 synthesizer library in a single C/C++ file
License: MIT License
SoundFont2 synthesizer library in a single C/C++ file
License: MIT License
Hi again! Playing a single note (note_on, note_off) quickly results in sharp reverb cut off. I found a temporary hack which fixed this (maybe not ideal but works)
tsf.h commit 7f29067 line 1160 onwards:
for (v = f->voices, vEnd = v + f->voiceNum; v != vEnd; v++)
{
if (v->playingPreset != preset_index) continue;
#ifndef SET_LOSSLESS
if (v->playingKey == key) tsf_voice_endquick(v, f->outSampleRate);
if (v->region->group) haveGroupedNotesPlaying = TSF_TRUE;
#endif
}
You can hear the difference here: https://soundcloud.com/martin-minovski/tsf-test
Ignore the buffer underruns. If I pre-render the samples instead, it sounds perfect with the hack enabled.
Could be nice to have that as a setting variable which can change during runtime. 👍
Cheers
Martin
In the MIDI spec, a channel MIDI message (e.g. note on, note off, program changed, etc.) has a channel represented by 4 bits (i.e. 0-15). However, that's only a limitation of the MIDI messages. Since TSF uses functions as its interface, not MIDI messages, does it still have this restriction of only 16 channels? (Having searched the code for the number 16, I think the answer is "no", which is good, but it's safer to check with you!)
The reason I ask is because we're looking at trying to support >16 channels in our MIDI player. As far as I can tell, normally these are encoded by choosing which MIDI device to send the event to, with the assumption that each MIDI device handles just 16 channels. So channels 0-15 go to MIDI device 0, 16-31 go to MIDI device 1, 32-47 go to MIDI device 2, etc. You would configure this on your MIDI software. To record this concept in a Standard MIDI files, this is usually done by telling each track which MIDI device to use with a 0x21 (port name) or 0x9 (device name) meta-event.
Taken literally, this would mean spinning up multiple TSF instances, since TSF takes the role of an output MIDI device. However, if TSF can handle more than 16 channels, it would be far easier just to have a shim layer in front of TSF that simply receives a MIDI event for MIDI device D for channel C, and maps that to channel 16*D+C on TSF. This way we need just one instance of TSF, one audio stream connecting TSF to an audio device, etc.
Hi, Mr. Bernhard Schelling .
When I tried your TinySoundFont HTML5 MIDI Player at https://schellingb.github.io/TinySoundFont/CustomSoundFont.html using Microsoft Edge, I cannot hear any sound from my browser. But when using another browser, it works perfectly.
Are there any issue that can be fixed there? Because I want to ask somebody to make HTML5 game script that support MIDI and your library is the best for it and I want to use your HTML 5 MIDI Player as reference.
Thank you very much for your attention.
Would it be feasible to add pitch bend control for each note (defined by preset and pitch)?
Thanks
Martin
engine for palm mute check
use combination of resonator, bcf, and energy analysis to dial it in
maybe run faster than 1024 buffer
Hi,
I like this neat lib.
Is it possible to support playing music in QBASIC's sequence format or something like that? Which is very nice to have.
So I'm going to attack adding Pitch Modulation from the Mod Wheel (well, vibrato) to my Bela implementation and wondered if anyone had already had a crack at this.
I presume that I'll have to implement controller ID #1 in tsf_channel_midi_control and link it to mod or vibLfoToPitch. Anyway, I'll start digging.
joke if you rush people
If I call tsf_channel_note_on(soundFont, channel, key, 0);
internally the library call tsf_note_off(f, preset_index, key);
which causes the notes for the channel to go off, but applying sustain (some kind of fading out I think).
I'm using that first call as a way to mute the music of my game, is there any way the sustain and release doesn't get applied? Or should I approach the muting of the music in another way?
I also have this problem when I change the music, say Music 1 is playing and the I as a player change it to Music 2, you can hear the fading out of Music 1 while the Music 2 starts to play.
Am I doing something wrong, using the library wrong or something?
Here are the files we're having trouble with: tsfbug.zip
We were able to get that particular .sf2 working by clamping the sustain in tsf_region_envtosecs() and clamping region->attenuation where voice->noteGainDB is calculated in tsf_note_on(), but we were hoping to ditch the hacky workaround for a real fix since you were so responsive to the previous issue I reported.
Thanks in advance for taking a look at it and for a great single-file library.
Would it be possible to set a global panning value for the player?
Hi there.
tl;dr: Would you be fine for you, if I port your library to C# and merge it into my music notation library I am developing? I will try to retain the original copyright notice as good as possible but the borders between my library and yours will likely become quite fuzzy over time.
Long Version:
First of all thanks for this great library. Most of the synthesizer libraries out there are really heavyweight and consist of thousands of lines of code but your library is really slim and produces great results. The best and most complete ones out there, are still FluidSynth and Gervill (part of the JDK) but with simple soundfonts you can hardly here a difference (beside the missing effects #24 ). FluidSynth is quite heavyweight and hard to port to other languages due to its C-nature, huge codebase and tons of capabilities. Gervill with it's GPL license and Oracle in the back, I can already forget to use it outside of the Java world.
I am the author of alphaTab, a web (and .net) based music notation software with playback capabilities. I already have a soundfont based synthesis library where I generate raw audio samples based on a given midi input to play it via the audio interface available on the platform. TinySoundFont has a way smaller footprint and produces more accurate results than my current one and I'm considering to replace my synth library partly with yours.
In general the MIT license would not prevent me to port your library to another language, but I prefer to talk to the original authors of libraries before doing so to get official permission. Especially as it will not remain a simple 1:1 port of the original library.
My plan is to port the library to C# and then further cross compile it to JavaScript and Kotlin using a home-made compiler/transpiler. Actually I already finished the porting and it runs already on .net 😉. Unfortunately I will not be able to use the library as-it-is and I will need to make further extensions for my API and the need of SoundFont 3 (Ogg Vorbis) support. So I will need to rip apart the structure a bit and introduce new functionality here and there. Also my library currently is released under LGPL which would be then more restrictive.
Of course I will add to all synthesizer related classes your name, and refer to your project as well to maintain the original copyright notice but somehow TinySoundFont will likely be hidden within my library.
I'm also looking forward to implement certain missing parts of the synthesizer on top of my port. I compared several midi file/soundfont combinations between TinySoundFont and Gervill and often they sound quite different. I hope to eliminate those differences.
I'm looking forward to get your permission to adopt your library and integrate it with mine.
Kind Regards
Daniel
tml.h:91:24: warning: ISO C++ prohibits anonymous structs [-Wpedantic]
91 | struct { union { char key, control, program, channel_pressure; }; union { char velocity, key_pressure, control_value; }; };
| ^
Goddamn annoying that they haven't updated to C99 compatibility in even C++20, apparently.
Hi, Our team was trying to build a C++ project using tsf.h and GNU's g++ and kept getting linking errors that the functions in tsf.h were multiply defined. We traced the problem to line 59 of tsf.h:
#define TSFDEF extern
as the functions being flagged were all fully defined internally within tsf.h, not declared in tsf.h and then defined externally. We were able to fix the problem by revising line 59 as follows:
#define TSFDEF inline
Cheers,
-Joel.
Hello! Excellent library!
I've had no problems with it when calling from a static context that loads a file immediately, but I'm getting a lot of segfaults when I try to load a second file, or when I call tsf_set_output
a second time after loading another file. Is there something special that I need to do to prevent these crashes happening?
Hello,
I'm currently working on a project in which I use TinyMidiLoader
as a standalone lib (thanks!), and I'm encountering some problems with gcc complaining about tml_load_tsf_stream
, here's the related output:
In file included from rbncli.c:9:
tml.h:469:48: warning: ‘struct tsf_stream’ declared inside parameter list will not be visible outside of this definition or declaration
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream)
^~~~~~~~~~
tml.h:469:21: error: conflicting types for ‘tml_load_tsf_stream’
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream)
^~~~~~~~~~~~~~~~~~~
In file included from rbncli.h:7,
from rbncli.c:1:
tml.h:141:21: note: previous declaration of ‘tml_load_tsf_stream’ was here
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream);
^~~~~~~~~~~~~~~~~~~
struct tsf_stream
doesn't seem to be declared in TinyMidiLoader
and is assumed to have been declared earlier in tsf.h
.
I figure to fix this problem you could move it out of tml.h
(or remove it, considering it's only a simple cast) or you could compile it conditionally (from tsf.h
defines).
I could define a dummy struct tsf_stream
in my code to avoid the problem or remove the code from your lib, but it's client-side friction probably best avoided.
Do you have any other suggestion? Thanks again for your work!
How would one specify which bank should a preset be chosen from?
I think the constant 480000
in tml_load
, for the default tempo value is incorrect.
This is supposed to be defined as microseconds per tick, and the default BPM is supposed to be 120, which means a value of 500000
.
This is the line of code that I think needs to be changed:
double ticks2time = 480000 / (1000.0 * division); //milliseconds per tick
Repro steps:
tml_get_info(tiny_midi_loader, NULL, NULL, NULL, NULL, &time_length);
tml_load
):if (Msg->type == TML_SET_TEMPO)
{
//unsigned char* Tempo = ((struct tml_tempomsg*)Msg)->Tempo;
//ticks2time = ((Tempo[0]<<16)|(Tempo[1]<<8)|Tempo[2])/(1000.0 * division);
//tempo_msec = msec;
//tempo_ticks = ticks;
}
Expected:
The times in step 1 and step 3 should be equal
Actual:
The times are off by a factor of exactly 0.96
(480000 / 500000)
I tried both but in vain.
Error says:
example1.c: func main: undefined reference to SDL_Delay
minisdl_audio.c: func SDL_Audio_LockDevice_Default: undefined reference to SDL_ThreadID ……
makefile:
NDK_ROOT=F:/COD/NVPACK/android-ndk-r12b
sysroot=$(NDK_ROOT)/platforms/android-23/arch-arm
TOOLCHAINS_ROOT=$(NDK_ROOT)/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64
TOOLCHAINS_PREFIX=$(TOOLCHAINS_ROOT)/bin/arm-linux-androideabi
TOOLCHAINS_INCLUDE=$(TOOLCHAINS_ROOT)/lib/gcc/arm-linux-androideabi/4.9.x/include-fixed
PLATFROM_ROOT=$(NDK_ROOT)/platforms/android-23/arch-arm
PLATFROM_INCLUDE=$(PLATFROM_ROOT)/usr/include
PLATFROM_LIB=$(PLATFROM_ROOT)/usr/lib
FLAGSMY=-I$(TOOLCHAINS_INCLUDE)\
-I$(PLATFROM_INCLUDE)\
-L$(PLATFROM_LIB)\
-lgcc\
-Bdynamic\
-lc\
-fPIC
all:ha
.PHONY : all
ha:
$(TOOLCHAINS_PREFIX)-gcc $(FLAGSMY) -Wall example1.c minisdl_audio.c -lm -ldl -o libexample1.so --sysroot=$(sysroot)
clean:
$(RM) *.o
Hi Bernhard,
I'd like to make use of your tinysoundfont-library with ESP32 (128MBit) and Arduino IDE.
Can you give a small example of how this could work. I only want to play midi note-on and midi note-off with different instruments on different midi-channels.
Audio-out: I2S DAC
Possible with your library?
Any idea about latency?
I would like you to answer to: [email protected]
Thank you very much for a quick answer!
Michael
Hi.
First of all, really sorry to bother you with this poor question.
I just want to ask, are these libraries especially tml.h can be used to play Standard MIDI Files (.mid) replacing other libraries, such as Timidity++ or Fluidsynth?
If yes, how complete the support for MIDI specifications? Are there limitations?
Thank you so much for reading this.
This can be verified by changing the output frequency in any of the example programs. 44100Hz and 48000Hz seem to work fine, but 22050Hz, 11025Hz, etc are all broken. I've verified the breakage both with the example programs and with a separate integration of TinySoundFont into an existing project.
So, now I have a working TSF on my Bela. As the device has 'limited' performance .. I'd like to set a limit on the number of playable voices and see where that leads - this may give me some headroom to implement multiple outs and reverb / chorus. Is there a way currently to set a voice limit (I've had a look through the examples and couldn't see anything obvious, nor in SFZero or every the SF architecture - before I go digging where I don't belong :)
Kind regards
Adrian
It's really great, I use it for my sequencer. However I have an issue, for simultaneous processing.
Say I have two tracks that use the same channel and loaded SF file, then simultaneous processing cannot be with TSF.
Best regards,
Hi,
i try to write a wrapper/package for tcl/tk in c. I created a function
"play soundfont midifile"
(similar tu exemple3.c) but i dont know how to split the different functions in seperate c functions.
My Goal is to seperate These steps in tcl commands
The other think is how can i read the playing Information (whole length, actual Position etc.)?
thx a lot - kmatze
When playing onestop.mid from Windows XP a note gets stuck after the first "verse" of the song, and continues through the rest of the song.
I'm trying to figure out what's going on but it's a hard one to debug.
My project uses SDL_mixer and I saw your examples and it seems to use SDL audio directly.
The thing is that SDL_mixer can't be used at the same time so when I try it my app crashes.
Do you know if it's possible to use TinySoundFont with the SDL_mixer?
I tried to look for examples but I couldn't find it how.
Thank you!
(I think your library is amazing by the way, thanks for sharing this)
Not sure if this is an issue specific to the soundfonts I've tried, but I've found that TSF is playing samples at circa double the speed they should be played at. This can be quite noticeable for soundfonts where the sound changes dramatically over different octaves...
I haven't got stuck into the details, but my fix has been to scale pitchRatio by 0.5 on line #L978... Otherwise I always see pitchRatio values between ~1.5 and ~2.5, i.e. samples are being played at twice the speed they should be...
This might also apply to dynamic pitch ratio calculations - I haven't been able to check yet though...
Hope that makes sense and thanks for the great library!
Is the '-1' here a mistake?
To me, the pointer pphdr + hydra->phdrNum - 1 looks like to be in the valid range.
(Found this when trying to trans-code this wonderful project to Python. Not tested.)
When compiling TinySoundFont library as part of OpenGothic project (https://github.com/Try/OpenGothic), I get the following compilation errors on the MCST lcc compiler:
lcc: "/root/dev/r-a-sattarov/OpenGothic/lib/TinySoundFont/tsf.h", line 829: error #2463:
conversion may change the value [-Werror=conversion]
samplesLeft = *fontSampleCount = chunkSmpl->size / sizeof(short);
lcc: "/root/dev/r-a-sattarov/OpenGothic/lib/TinySoundFont/tsf.h", line 835: error #2463:
conversion may change the value [-Werror=conversion]
stream->read(stream->data, sampleBuffer, samplesToRead * sizeof(short));
lcc: "/root/dev/r-a-sattarov/OpenGothic/lib/TinySoundFont/tsf.h", line 1483: error #2463:
conversion may change the value [-Werror=conversion]
int channelSamples = (f->outputmode == TSF_MONO ? 1 : 2) * samples, floatBufferSize = channelSamples * sizeof(float);
log: TinySoundFont-OpenGothic_lcc_compile_err.log
original issue Try/OpenGothic#91
I've been looking into volume curves recently, because my implementation of a MIDI player using TSF didn't sound quite right. In the end I was using a linear curve to map MIDI velocity (0-127) to the velocity (0-1) in tsf_note_on
. It turns out that a quadratic curve is a better fit.
This led me to do some maths that a) I'd like to share in case anyone else is worrying about this, and b) I think it would be useful to use a quadratic curve in your examples (e.g. here), and also here.
A MIDI note has a velocity v
between 0 and 127 (int).
TSF asks for a velocity x
between 0 and 1 (float).
In the final output, we get a volume L
measured in decibels between -∞ and 0 (this is the difference in decibels from full volume, i.e. 0dB is full volume).
According to the GM recommendations (bottom of page 9) the recommendation is to map between v
and L
by L = 40 log (v/127)
.
From looking at TSF's code, it maps between x
and L
by L = 20 log (x)
(see tsf_gainToDecibels
).
It's the user of TSF's job to implement the map between v
and x
. If we want to conform to the GM recommendations, we need 40 log (v/127) = 20 log (x)
, i.e. x = (v/127)^2
.
Therefore, I recommend that people using TSF use the mapping x = (v/127)^2
when calling tsf_note_on
or similar functions. It makes sense to me to default to conforming to the GM recommendations.
I think it would be good to update the examples to use this map, rather than x = v/127
(which I see in example3.c). Also, I wonder if you should use a quadratic map rather than the cubic map x = (v/16383)^3
in TCMC_SET_VOLUME
(here v
is between 0 and 16383).
Hello!
Thanks for this interesting library. It's really compact and for sure can be used in many projects.
I had some strange problem when trying to run the examples on my old tv box, an allwinner a10 armhf system.
The example1 works fine there.
examples 2 and 3 do play the notes, but also some quite loud white noise plays in the background.
I have also tried to use the tinysoundfont implementation from esp8266audio and got a similar problem there. A background whooshing sound goes together with every note played.
On a regular x86_64 system it works perfectly.
Any hints to solve this? thanks again...
So when I turn off a note the sound stops completely, this is very abrupt and I will like it to stop it smoothly.
Is this possible?
I was thinking I could turn off the volume gradually until it reaches zero, is there something already built in for this on the library?
I tried to change the volume of a note by calling tsf_note_on with a lower velocity but it resets the note to the beginning.
Is it possible to have different notes with different volumes and fade them away after some time?
hi,
it works wonderfull in tcltk. Now, I Need a function to get the bank and preset number from presetindex of a sound. is it possible to make reversing function of tsf_get_presetindex?
// Returns the preset index from a bank and preset number, or -1 if it does not exist in the loaded SoundFont
TSFDEF int tsf_get_presetindex(const tsf* f, int bank, int preset_number);
thx and greetings - kmatze
It is possible for voice->playingPreset to be set to -1 during tsf_note_on before completion. This is caused by tsf_voice_kill altering the voice during render (assuming a multithreaded call) as soon as voice initialisation begins. This means that the voice pool grows over time. I've added an active flag (in my local code) around tsf_voice to protect it until it is fully set.
Hello again. So I want to apply e. g. a compressor to a single instrument (preset) in a sound font. I can't do it at the tsf_render_float level because that would have a mix of many instruments at that point.
It would be nice if tsf would have a callback that allows the source sound to be modified before mixing it to the float buffer.
Until then, which function can be hooked?
Best,
Any interest in seeing examples of use with other audio libraries/frameworks?
A few random suggestions:
I found several bigger/high level libraries as well. They would be pretty hard to set up a build for, compared to your stripped down SDL example. However for projects already using another audio lib that don't have good sound font synthesis/midi loading and playback this library might still be a useful option.
Two problems I've run into so far:
GeneralUser GS MuseScore v1.442.sf2
I can provide a sample midi file if that helps. I looked at the binary of the midi in a hex editor with midi template support, and ran the sample code through the debugger. There's no program specification on that channel at all, and no bank switching. It seems the midi file is relying on mapping to the GM standard.
I can just manually map to solve problem 1, but problem 2 I don't fully get how to work around. I tried playing just "note 49" by hard coding it in the sample program, and it still played the extra note.
How hard would it be to get reverb and chorus going? :)
These effects can be implemented in a tiny amount of code. I was poking around FluidSynth and they are using a 4 allpass + 8 comb filter network for reverb. I believe it is based on Freeverb.
My thoughts are that there's no reference implementation for these FX, so might as well make them sound as good as possible. There might be better options than Freeverb. Thoughts?
Hi,
This is actually a report against your fork of SFZero, but there's no issue tracker currently for that repo so I'm posting here.
SF2 works fine in your SFZero, however SFZ just produces silence (or at least some very low level noise).
I will look into this myself, but I'm asking here in case you're aware of anything obvious that may be causing the problem
The original stevefolta SFZ works fine, so this is definitely a regression.
Hello,
I am participating in this year's Google Summer of Code, for which i'll be integrating MIDI support in a game engine called Godot. So far TinySoundFont looks like the best option and i was wondering what are the conditions to using TSF in an already existing project?
I've studied the example files and if i understand correctly, I should be able to replace the SDL parts with another audio library and in theory it should work right?
Thanks
I'm sorry, this request is fairly vague :| It is sort of testing the limit of my sf/midi knowledge and debugging skills!
Playback is much better with most soundfonts w/ your previous 5 or 6 commits (🎈), but now I'm trying to find a small soundfont I can legally distribute w/ an open source game I'm porting.
I'm having a problem with this combo:
Other soundfonts are working fine w/ this track in the example3 player, and this sound font is working fine with this track in a different bassmidi-based player.
The problem is on track 12, when using Lead 6 Voice (85). The track has long held notes, modulation, and aftertouch. The result of playback in example3 is like someone trying to do rapid notes on an instrument with a very long attack, so it barely plays or doesn't sound at all.
I'd just use a different working soundfont, since other ones are working just fine with your lib, but they're either too big, or of dubious legality. I am working on a FOSS game port, so I'd rather not try anything on-the-sly!
Hi there! Would it be possible to assign panning factor for each individual note (voice)? I noticed you're setting some panning values for each voice in the note_on function, but I don't want to break anything there ;)
Great piece of lib, keep it up!
Cheers
Martin
Hiya, this might be a dumb question, but I want to include tsf.h in a header file, then include that header in main, and its giving me 40 duplicate symbols when I do (I see you said to include it in one file, I've tried pragma onceing it etc etc and its still showing duplicates, any ways around this?
I tried with different soundfont libraries, as well as on different platforms (BeagleBone+Bela, Windows 10 + standard soundcard [examples/example2.c]), but there is a persistent clicking noise - its frequency is correlated with the buffer length. Recorded the output, here's how it looks like:
https://pasteboard.co/GM3rN13.png
Looks almost as if there is one missing sample for each buffer window i.e. tsf_render_float and tsf_render_short producing less samples than defined in the the function argument? Any ideas whether it's something obvious?
Thanks!
i ran this script https://github.com/yishengjiang99/ssr-bach/blob/master/install.c 15 times (from note js) to compile 15 different instruments for keys 21-109 and it finished in 6.9 (first 2.0 were spent parsing some midi file)
`yishengs-macbook-pro:ssr-bach yisheng$ ts-node /Users/yisheng/Documents/GitHub/ssr-bach/src/install.ts
2.097498536
2.354698177
2.598045037
2.869136001
3.104193877
3.445881478
3.699593748
4.207481075
4.661177624
5.084969839
5.513516307
5.797124318
6.230779299
6.492082309
6.922956223``
I'm converting an old DirectMusic application to use TML. I need to seek/loop to a specific part of the song, but the application I am using has the time stamps encoded in MUSIC_TIME
(which is relative to tempo). In order to determine the actual milliseconds offset within the song, I need to seek from the beginning and see all tempo changes.
If the midi header has tempo data, it would also be useful to have that available, in case no change tempo messages are in the stream.
Hi there,
I'm trying to use TinySoundFont to render sound to Android using https://github.com/google/oboe/.
I'm having trouble marrying these two bits of documentation:
Any ideas of what I can do? For what it's worth, running without mutexes seems to work fine, and adding mutexes adds only very slight audio glitches here and there, so maybe I can just not include mutexes, but that feels dangerous.
This is regarding TML and not the TSF side of things.
I'm not sure if I'm doing things incorrectly, but tml_get_info
seems to return the begin timestamp of the last note in out_time_length
, and not include the lingering time. If I stop playback at exactly this time, then the final note gets cut off in the particular song I'm playing. I'm also not sure if it's cutting off on-tempo or not.
Is there some mechanism I've missed, or work-around that I can do? There are a couple I thought of ("just wait a bit longer" and "double-output so I can sample the volume"), but they don't seem ideal. I am planning on specifying a mid-song loop point, running to the end, and looping back to that point, so I think I need to get that last note to be the correct length for the tempo.
I might be able to get enough info if I had a way of determining "final" tempo, and got info from the midi header, but as far as I can tell, those are buried inside the implementation right now. Easy enough to hack around (esp if that's what you suggest), but I think it might also be nice to have functions to handle it for me :) Maybe return both a header struct as well as the message list from tml_load_filename
? If this sounds like a good direction, then I think I could make a PR for that.
Edit: Or maybe I'm thinking about this wrong... I am guessing most midi tracks are going to have their last message be a "note off". At least, the "track length" solution seems to assume something along those lines. So maybe looping isn't a problem? Properly sustaining the last note before unhooking the midi sample generator callback is all I'm looking for, then. Maybe this is best served with a hard-coded pause, or maybe getting the header info/tempo would still be useful. Would like some thoughts on that at least :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.