A small XM (FastTracker II Extended Module) player library.

Overview

libxm

A small XM (FastTracker II Extended Module) player library. Main features:

  • Small size in mind; many features can be disabled at compile-time, or are optimized out by the compiler if not used.

  • Timing functions for synchronising against specific instruments, samples or channels.

  • Samples can be loaded and altered at run-time, making it possible to use libxm with softsynths or other real-time signal processors.

Written in C11 and released under the WTFPL license, version 2.

Size

The playback routine (assuming the non-portable .libxm format is loaded, see libxmize below) fits in under 7KiB of compressed machine code.

xzcrush libxmtoau
for x in *.xm; do libxmize $x $x.libxm; done
rename .xm.libxm .libxm *.xm.libxm
ls *.{xm,libxm} | xargs -n 1 -P 16 xz -9ekf
wc -c *.*xm *.*xm.xz libxmtoau.crushed

 6810919 an-dream.libxm
 5585551 an-dream.xm
  109423 cerror-expatarimental.libxm
   49240 cerror-expatarimental.xm
  282590 drozerix_-_crush.libxm
  121346 drozerix_-_crush.xm
  581955 heritage.libxm
  438340 heritage.xm

 2855496 an-dream.libxm.xz
 2876184 an-dream.xm.xz
    4180 cerror-expatarimental.libxm.xz
    4820 cerror-expatarimental.xm.xz
   36060 drozerix_-_crush.libxm.xz
   37276 drozerix_-_crush.xm.xz
  201348 heritage.libxm.xz
  201200 heritage.xm.xz

    6833 libxmtoau.crushed

Binaries crushed with xzcrush.

libxmize and the non-portable format

The libxmize binary can convert a standard .xm file to a non-standard, non-portable representation of that module. The file generated by libxmize is usually a lot larger than the original module, but has better compressibility.

In addition, the non-portable format:

  • requires less code to load (xm_create_context_from_libxmize() instead of xm_create_context()) and thus can be used to produce smaller binaries. (See the size section above.)

  • requires significantly less memory to play back modules (only kilobytes thanks to mmap(), see libxmtoau for an example).

The data generated by libxmize will not be readable:

  • On a different CPU architecture
  • On a different libxm commit
  • On a libxm compiled with another compiler
  • On a libxm compiled with a different compiler version
  • On a libxm compiled with different options or CFLAGS

Examples

Some example programs are provided.

  • libxm.js is a very simple XM player/visualiser that runs in a browser (emscripten port).

  • xmgl is a simple music visualiser that uses OpenGL and JACK for very precise audio synchronisation. See a demo here: https://www.youtube.com/watch?v=SR-fSa7J698

  • xmprocdemo: see README

  • xmtoalsa is a simple player that uses the ALSA library. It produces xmp-like output while playing. Use xmtoalsa --help (or check the source) to see the full usage.

    ./xmtoalsa --random **/*.xm
    
  • xmtowav will play a module and output a .wav file.

    ./xmtowav my_module.xm my_module.wav
    
  • xmtoau will play a module and output a .au file to standard output.

    mpv <(./xmtoau my_module.xm)
    
  • libxmtoau is similar to xmtoau, except that it loads non-portable files generated by libxmize.

  • xmbench is a benchmark program.

Here are some interesting modules, most showcase unusual or advanced tracking techniques (and thus are a good indicator of a player's accuracy):

Status

Effects

 Status |##| Eff | Info | Description
--------+--+-----+------+------------------------------
DONE    |00|  0  |      | Arpeggio
DONE    |01|  1  |  (*) | Porta up
DONE    |02|  2  |  (*) | Porta down
DONE    |03|  3  |  (*) | Tone porta
DONE    |04|  4  |  (*) | Vibrato
DONE    |05|  5  |  (*) | Tone porta+Volume slide
DONE    |06|  6  |  (*) | Vibrato+Volume slide
DONE    |07|  7  |  (*) | Tremolo
DONE    |08|  8  |      | Set panning
DONE    |09|  9  |      | Sample offset
DONE    |10|  A  |  (*) | Volume slide
DONE    |11|  B  |      | Position jump
DONE    |12|  C  |      | Set volume
DONE    |13|  D  |      | Pattern break
DONE    |14|  E1 |  (*) | Fine porta up
DONE    |--|  E2 |  (*) | Fine porta down
        |--|  E3 |      | Set gliss control
DONE    |--|  E4 |      | Set vibrato control
DONE    |--|  E5 |      | Set finetune
DONE    |--|  E6 |      | Set loop begin/loop
UNTESTED|--|  E7 |      | Set tremolo control
DONE    |--|  E9 |      | Retrig note
DONE    |--|  EA |  (*) | Fine volume slide up
DONE    |--|  EB |  (*) | Fine volume slide down
DONE    |--|  EC |      | Note cut
DONE    |--|  ED |      | Note delay
DONE    |--|  EE |      | Pattern delay
DONE    |15|  F  |      | Set tempo/BPM
DONE    |16|  G  |      | Set global volume
DONE    |17|  H  |  (*) | Global volume slide
DONE    |20|  K  |      | Key off              (Also note number 97)
DONE    |21|  L  |      | Set envelope position
DONE    |25|  P  |  (*) | Panning slide
DONE    |27|  R  |  (*) | Multi retrig note
DONE    |29|  T  |  (*) | Tremor
DONE    |33|  X1 |  (*) | Extra fine porta up
DONE    |--|  X2 |  (*) | Extra fine porta down

Volume effects

 Status |  Value  | Meaning
--------+---------+-----------------------------
DONE    | $10-$50 | Set volume (Value-$10)
DONE    | $60-$6f | Volume slide down
DONE    | $70-$7f | Volume slide up
DONE    | $80-$8f | Fine volume slide down
DONE    | $90-$9f | Fine volume slide up
DONE    | $a0-$af | Set vibrato speed
DONE    | $b0-$bf | Vibrato
DONE    | $c0-$cf | Set panning
DONE    | $d0-$df | Panning slide left
DONE    | $e0-$ef | Panning slide right
DONE    | $f0-$ff | Tone porta

Known issues

  • Only loads FastTracker II-compatible XM files.

  • Loading a bogus file (that yet has a valid 60-byte header) will probably result in a segmentation fault.

  • Big endian architectures are not yet supported.

Tests

Some test XM files are in the tests directory. Their goal is to test a certain feature against regressions. A summary of tests (and what they are supposed to test) is in the table below.

     Test                      |     Status     |     Tested against     | Extras
-------------------------------+----------------+------------------------+------------------------------------------------
amiga.xm                       | FAIL           | MilkyTracker, xmp      | Should sound identical.
arp-slow.xm                    | FAIL           | MilkyTracker, OpenMPT  | Should sound identical.
autovibrato-turnoff.xm         | PASS           | MilkyTracker           | Same pitches should be heard twice in a row.
fadeout-speed.xm               | PASS           | MilkyTracker           | Should sound identical.
finetune.xm                    | PASS           | MilkyTracker           | Left and right channels should sound identical.
ghosts.xm                      | FAIL           | MilkyTracker           | Left and right channels should sound identical.
multiretrig-volume.xm          | PASS           | FT2, OpenMPT           | Should sound identical.
note-delay-ghost.xm            | PASS           | MilkyTracker, FT2      | Should sound identical.
note-delay-retrig.xm           | PASS           | MilkyTracker           | Should sound identical.
panning-law.xm                 | PASS           | MilkyTracker, FT2clone | Should sound identical.
pattern-loop-quirk.xm          | PASS           | MilkyTracker           | Should play the same notes at the same time.
pos_jump.xm                    | PASS           | Milkytracker, OpenMPT  | Only one beep should be heard.
ramping.xm                     | PASS           | MilkyTracker           | If XM_RAMPING is ON, no loud clicks should be heard.
ramping2.xm                    | PASS           | MilkyTracker           | If XM_RAMPING is ON, no loud clicks should be heard.
retrig-vol-fade.xm             | PASS           | MT, FT2clone, OpenMPT  | Should sound identical.
tone-portamento.xm             | PASS           | MilkyTracker           | Should sound identical.
tremolo.xm                     | PASS           | MilkyTracker           | Should sound identical.
tremor.xm                      | PASS           | MilkyTracker           | Should sound identical.
vibrato.xm                     | PASS           | MilkyTracker           | Should sound identical.
vibrato-slow.xm                | PASS           | OpenMPT                | Should sound identical.
vibrato-octave.xm              | PASS           | FT2clone, OpenMPT      | Should sound identical.

Thanks

Thanks to:

  • Thunder [email protected], for writing the modfil10.txt file;

  • Matti "ccr" Hamalainen [email protected], for writing the xm-form.txt file;

  • Mr.H of Triton and Guru and Alfred of Sahara Surfers, for writing the specification of XM 1.04 files;

  • All the MilkyTracker contributors, for the thorough documentation of effects;

  • All the people that helped on #milkytracker IRC;

  • All the libxm contributors.

Comments
  • Minor volume column porta fix

    Minor volume column porta fix

    So I'm looking into the porta issues in #1, specifically the file aurora_dawn.xm.

    I haven't yet cracked why it sounds so interesting (Milky sounds like it's not even applying porta to the note, I think it might be something to do with the tempo and ticks, seeing what I'm reading through a few docs. Maybe something with how we do SLIDE_TOWARDS or update_frequency), but I'm gonna try and keep plodding along with it and see what I find.

    But I did find this issue, which is why that big spike was happening. It was taking the effect number as well as the actual effect value (instead of 7 there, it was grabbing a much larger number because of the M).

    I haven't had a good look around at xm implementations, and I haven't done much audio work before, but I think porta's only meant to slide towards between the current and new note, right? I find it odd that even a larger than normal tone_portamento_param would make the note frequency spike – if anything, I'd expect it to just go between the two notes much faster than usual. But again, I'm not too familiar with XM, so I'll keep plodding along and see if I can work out the issue!

    edit: Having a play with MT, it looks like it is just doing the porta very fast, I suspect due to the tempo variable I saw some documentation about a bit earlier. I'll do some testing and see if I can get libxm sounding just like MT/etc sounds.

    opened by DanielOaks 8
  • Buffer overrun in xm_create_context

    Buffer overrun in xm_create_context

    I'm writing a Rust wrapper for libxm, and noticed that there's no bounds for moddata in xm_create_context(). This is obviously bad if moddata is corrupted or invalid.

    From what it appears, you seem to be aware of this issue already; it's listed in the README as:

    • Loading a bogus file (that yet has a valid 60-byte header) will probably result in a segmentation fault.

    Are there any plans to address this issue in the near future?

    bug enhancement 
    opened by nukep 7
  • Create floating_instrument to fix note delay effect

    Create floating_instrument to fix note delay effect

    This is an weird patch, but it fixes this test case (where the note delay effect ED6 fails because the instrument is wiped for each new row).

    Minimal test case: https://dl.dropboxusercontent.com/u/47853382/AT4RE%20-%20Lock%20Folder%20XP%203.6crk%20-%20test.xm

    Full song: https://dl.dropboxusercontent.com/u/47853382/AT4RE%20-%20Lock%20Folder%20XP%203.6crk.xm

    opened by DanielOaks 6
  • Add xm_create_context_safe(), avoid buffer overruns

    Add xm_create_context_safe(), avoid buffer overruns

    A safer xm_create_context_safe() function was added for creating the XM context; the now-deprecated xm_create_context() remains for backwards compatibility.

    I originally attempted to error-handle all invalid reads, but that turned out extraordinarily verbose and difficult. :) So I did what @Artefact2 suggested and padded out-of-bounds reads with 0.

    All of the READ_x macros will now return 0 if the provided offset exceeds the bounds of moddata. All occurrences of memcpy were also replaced with a new READ_MEMCPY macro that pads with zeros.

    Fixes #6

    opened by nukep 5
  • Fix playing of undefined patterns

    Fix playing of undefined patterns

    Some XM modules contain a pattern table that references an undefined pattern (whose index is higher than the number of patterns). Both ft2-clone and MilkyTracker agree that those are empty patterns of 64 rows and play them accordingly.

    This commit does the same in libxm, avoiding a segfault.

    opened by rasky 4
  • Fix a couple of bugs in effect Rxy (multiretrig)

    Fix a couple of bugs in effect Rxy (multiretrig)

    Rxy is possibly the most quirky command in the XM format, and it's hard to get right in all its dark corners. This gets libxm closer to FT2-Clone and XMPlay (even closer than MilkyTracker) but still not quite perfect.

    The main bug fixed here is that the volume change of a Rxy command only takes effect if the volume column is empty, and only if there is no volume envelope in the instrument (and in this case, the envelope is not even restarted, contrary to what E9x does).

    To fix this, I changed the code to first retrigger the note keeping the volume and the envelope like it is, and then updating it if needed.

    It's important to notice that, even the volume part of Rxy doesn't apply, the value is still remembered in case a subsequent R0y is issued; so the part handling Rxy in xm_handle_note_and_instrument isn't affected.

    Another bug (more obvious) is that the multi_retrig_add lookup tables is defined in 64th of a volume step, but the value was not scaled by 64, so the volume change was always saturating the volume.

    Co-developed with @bryc who also prepared the testcases.

    opened by rasky 4
  • Fix channel panning ramps.

    Fix channel panning ramps.

    It looks like in FT2, panning is made using an exponential scale, based on sqrt. This PR allows to match panning performed by MilkyTracker and OpenMPT.

    MilkyTracker: https://github.com/milkytracker/MilkyTracker/blob/be016986168a4d03b8d160303fa61296070a6e2c/src/milkyplay/ChannelMixer.cpp#L583

    FT2-clone: https://github.com/8bitbubsy/ft2-clone/blob/8af2e42736b61a36a0d54bede93a47a1bab35f5d/src/ft2_audio.c#L192

    The attached test makes it easy to reproduce the issue.

    Co-developed with @bryc who also prepared the test.

    opened by rasky 4
  • Fix: playing of instrument without note.

    Fix: playing of instrument without note.

    When an instrument is played without a note, the current playing sample should restart its envelope, keeping its position. So it's important not to change the current instrument.

    Also, the same behavior happens even if the instrument is invalid (and no note is specified); on the other hand, if the instrument is invalid and a note is specified, the current note is being cut.

    Co-developed with @bryc, who also prepared the tests

    opened by rasky 4
  • Fixes values spiking due to bad sample memory accesses

    Fixes values spiking due to bad sample memory accesses

    This fixes the clicks and staticy noises in the modules in #1. That is, the ones that make these messages:

    xm_sample(): final sample value is 136597905678638606450688.000000, this is a bug
    xm_sample(): final sample value is 296616456960244306673664.000000, this is a bug
    xm_sample(): final sample value is 144714319948683478564864.000000, this is a bug
    

    There are two things that cause this problem in the xm_next_of_sample(xm_channel_context_t* ch) function – either the sample length is 0, and when it grabs u = ch->sample->data[a]; it reads into memory that does not belong to it, so we have that if at the start to check the sample length is more than zero.

    What can also happen is that the 'loop end point' extends past the actual end of the sample. Just by one tick, so ch->sample_position was getting set to 132 at the end of a sample that was only 132 long, resulting in the same sort of read into memory that does not belong to it.

    Anyways, this fixes both of those issues and the clipping. I'm fairly sure Milkytracker handles this in the same way, clamping the loop end to the sample length.

    edit: I'm not sure whether this sort of fix should also be applied to the other loop types. I had to quickly type this up a few minutes before running to work, but otherwise I'll look into it when I get home.

    opened by DanielOaks 4
  • Infinite loop during playback

    Infinite loop during playback

    https://modarchive.org/module.php?33498

    Gets stuck in a loop using 100% of the CPU at the 1:18 mark.

    Spd[05/75] Pos[0C/29] Pat[06/32] Row[22/40] Loop[00/01] 00:01:18.88
    
    bug 
    opened by Artefact2 3
  • libxm: fix period calculation of high octaves in Amiga mode

    libxm: fix period calculation of high octaves in Amiga mode

    In octaves 6 and 7, there was not enough precision left to accurately compute the period, because too many bits were discarded during the scaling down.

    To fix this, scale the frequency table by 1024 after switching to uint32_t, and adjust calculations accordingly.

    Co-developed with @bryc.

    opened by rasky 2
  • Fix arpeggio + vibrato in linear frequencies

    Fix arpeggio + vibrato in linear frequencies

    In #27, we refactored xm_frequency to split arpeggio (note offset) from vibrato (period offset). Unfortunately, we did test it properly only for amiga frequencies.

    It turns out the linear frequency implementation is wrong. The note offset cannot be added to the period, but must be added to the note itself. In case of linear frequencies, that's trivial to do once we get the frequency, as we can simply scale it.

    This fixes binary_world.xm and so finally...

    Closes #1

    opened by rasky 3
  • Rxy + ghost note inaccuracies

    Rxy + ghost note inaccuracies

    Just to log it, there's another bug in Rxy which I'm not planning to fix for now. If a row contains no note but an instrument with the Rxy effect, what happens is that on tick 0, the ghost note of the previous instrument plays (as per standard behavior with rows that contain instruments without notes), but on the first retrigger the instrument is changed to the new one. So actually the instrument changes mid-row.

    This looks harder to implement because the logic to change instruments is not part of xm_trigger_note, but I haven't investigated into it. If you want, I can open an issue to log this.

    Originally posted by @rasky in https://github.com/Artefact2/libxm/issues/20#issuecomment-822318552

    bug 
    opened by Artefact2 4
  • Optional support for most effects, xmanalyze cflags

    Optional support for most effects, xmanalyze cflags

    Write a little helper program (xmanalyze?) that loads a module and sees which effects are used. The program spits out CFLAGS to build libxm with only these effects enabled. Maybe this saves a couple dozen bytes for demos and such.

    Things that could be somewhat easily #ifdef'd out:

    • Amiga frequencies
    • Linear frequencies
    • Waveform control stuff
    • etc.
    enhancement 
    opened by Artefact2 0
  • Playback inaccuracies

    Playback inaccuracies

    Gave it a spin with some tricky songs, and unfortunately I noticed some bugs that also appear in several other player libs. Note that it might be the songs that are at fault, with certain libs (xmplay/bassmod, openmpt/modplug, milkytracker/milkyplay) taking steps to cover it up. I don't know enough about the file format to judge. . binary_world.xm goes bad 39sec in, and OpenMPT has slight issues too http://modarchive.org/module.php?138953 http://clyp.it/hhp3pfex . ~~around 51sec, the lead echo in colond.xm is played at a slightly different pitch than the main lead, resulting in phasing~~ http://modarchive.org/module.php?174415 http://clyp.it/gfuaa1do . ~~as jt_strng.xm hits the higher notes at 35sec, they go off-pitch.~~ libxm gets a fair bit of static as well but I suppose that's intended http://modarchive.org/module.php?46508 http://clyp.it/nh15rq5h . ~~synthetic_attack.xm plays correctly but segfaults at the end:~~ (fixed in ac0bbdb, the module file is unsane. Opening then resaving the module in MilkyTracker fixes it.) http://modarchive.org/module.php?142503 #0 xm_row (ctx=0x7f8d92832010, output=, numsamples=128) at /libxm-master/src/play.c:847 #1 xm_tick (ctx=0x7f8d92832010, output=, numsamples=128) at /libxm-master/src/play.c:948 #2 xm_sample (ctx=0x7f8d92832010, output=, numsamples=128) at /libxm-master/src/play.c:1293 #3 xm_generate_samples (ctx=0x7f8d92832010, output=, numsamples=128) at /libxm-master/src/play.c:1340

    . ~~zalza-tequila_groove.xm throws assertion failures,~~ (fixed in f24bcab) and some static at the 49sec and 58sec marks: http://modarchive.org/module.php?66518 xm_sample(): final sample value is 136597905678638606450688.000000, this is a bug xm_sample(): final sample value is 296616456960244306673664.000000, this is a bug xm_sample(): final sample value is 144714319948683478564864.000000, this is a bug . All tests done with master as of writing. Also, what are those (*) in the effects table?

    bug 
    opened by 9001 4
Owner
Romain D.
OpenPGP B709 A6E4 82D8 CB26 D100 4B17 19A9 512F 7A21 425A See also my gitlab profile: https://gitlab.com/users/artefact2/projects
Romain D.
Invariant-ekf - C++ library to implement invariant extended Kalman filtering for aided inertial navigation.

inekf This repository contains a C++ library that implements an invariant extended Kalman filter (InEKF) for 3D aided inertial navigation. This filter

Ross Hartley 265 Nov 21, 2022
Extended kalman filter implementation.

EKF (Extended Kalman Filter) This project is a C++ implementation of EKF.For the related principles of EKF, please check this tutorial (TODO). Project

null 7 Oct 16, 2022
Obfuscator refactored and extended from OLLVM.

OLLVM++ Obfuscator refactored and extended from OLLVM. Environment Ubuntu 18.04.5 LTS LLVM 12.0.1 Clang 12.0.1 CMake 3.21.1 Usage Compile Obfuscation

34r7hm4n 500 Nov 24, 2022
The core engine forked from NVidia's Q2RTX. Heavily modified and extended to allow for a nicer experience all-round.

Polyhedron - A Q2RTX Fork A fork of the famous Q2RTX project by NVIDIA™ that strives to improve all of its other factors of what was once upon a time

Polyhedron Studio 19 Nov 22, 2022
Half-Life : Extended main branch for developing purposes

Half Life : Extended SDK Source Code of Half Life : Extended as a open source modbase for everyone publicly, make your own mod with alot of features e

Bacontsu 14 Nov 22, 2022
A CUDA-accelerated cloth simulation engine based on Extended Position Based Dynamics (XPBD).

Velvet Velvet is a CUDA-accelerated cloth simulation engine based on Extended Position Based Dynamics (XPBD). Why another cloth simulator? There are a

Vital Chen 37 Nov 21, 2022
C++11 header-only library that offers small vector, small flat map/set/multimap/multiset.

sfl library This is header-only C++11 library that offers several new containers: small_vector small_flat_set small_flat_map small_flat_multiset small

null 20 Nov 15, 2022
Simple Player-Glow & Driver Source Included

External-Apex-Cheat Install WDK Build in Release x64 Map driver using KDMapper Launch Game Run User-mode when in main menu Have Fun driver is indeed p

null 102 Nov 8, 2022
ESP32 drum computer / sample player / midi sequencer (Arduino audio project)

esp32_drum_computer ESP32 drum computer / sample player / midi sequencer (Arduino audio project) The project can be seen in my video https://youtu.be/

Marcel 41 Nov 14, 2022
Cross-platform tool to extract wavetables and draw envelopes from sample files, exporting the wavetable and generating the appropriate SFZ text to use in a suitable player.

wextract Cross-platform tool to extract wavetables and draw envelopes from sample files, exporting the wavetable and generating the appropriate SFZ te

Paul Ferrand 9 Jan 5, 2022
GTA Online survival missions in Single Player mode

SurvivalsModCPPVersion You liked the survival missions from GTA Online? Well, me too. This mod aims to recreate the same gamemode in Single Player mod

null 1 Nov 23, 2021
Immersive IMM Format and Player

Introduction Immersive media (IMM) is an API-neutral runtime immersive media delivery format. IMM provides an efficient, extensible, interoperable for

null 38 Oct 27, 2022
PUBG ESP Hack for Emulator using C++ code. Player Position, Bones, Loots, Weapons, Vehicles, Boxes ... etc.

PUBG 1.7 ESP Hack for Emulator (C++ Source Code) PUBG ESP Hack for Emulator using C++ code. Player Position, Bones, Loots, Weapons, Vehicles, Boxes ..

Zero One Billion 37 Nov 1, 2022
📽 A simple X11+SDL2 animated wallpaper setter and video player

anipaper ?? A simple X11+SDL2 animated wallpaper setter and video player Introduction Anipaper (ANImated Wallpaper) is a simple 'wallpaper setter' for

Davidson Francis 12 Nov 15, 2022
Quake Enhanced mod where one player (The Juggernaut) is very strong and all other players have to kill the Juggernaut

QE Juggernaut Quake Enhanced Juggernaut (A modification of the QEHunter mod by JPiolho.) This is a multiplayer mod where one player is the Juggernaut.

null 2 Jun 6, 2022
A plugin that can display player information overhead

A plugin that can display player information overhead Config File At plugins/HeadShow/config.json { "updateTick":60,

HuoHua 0 Jun 17, 2022
F Graphics Library (FGL) is a small graphics C++ portable library for LCD displays on embedded systems

F Graphics Library (FGL) Full documentation: fgl.docsforge.com (By Filipe Chagas) F Graphics Library is a C++ library that I created for use in embedd

Filipe Chagas 9 Oct 31, 2022
A test using a TTGO module (ESP32 + screen) which renders a 3d scene using pingo library

A simple 3D renderer tested and developed for the TTGO T-Display ESP32 board. The 3d renderer is: https://github.com/fededevi/pingo The 3D renderer is

fedevi 10 Nov 2, 2022
a small C library for x86 CPU detection and feature extraction

libcpuid libcpuid provides CPU identification for the x86 (and x86_64). For details about the programming API, you might want to take a look at the pr

Veselin Georgiev 353 Nov 14, 2022