MusicBee ~ Extensible Audio Player


Enjoy a great music experience with MusicBee, the ultimate music manager and player. Play your music the way you want. Turn your computer into a music jukebox.

MusicBee makes it easy to manage, find, and play music files on your computer. Use auto-tagging to clean up your messy music library. MusicBee also supports podcasts, web radio stations and SoundCloud integration.

Supports AcoustID, Discogs, Last.FM, Milkdrop, ReplayGain and UPnP / DLNA

musicbee

getmusicbee.com
getmusicbee.com/downloads
getmusicbee.com/addons
Wiki
en.wikipedia.org/wiki/MusicBee

Resources:

sourceforge.net/projects/additional-tagging-tools/

Foobar2000 ~ Album Based Beats Per Minute


Beats Per Minute is great for playlist of songs sorted from slow songs to fast songs but it would be useful to sort albums by BPM as well. To do this the following script calculates an average of BPM information from each song of the album and writes that value to ALBUM_AVG_BPM. Then just create a playlist sorted by artist and then album_avg_bpm.

SMP Album Average BPM Calculator Script

In the DUI, toggle layout and create a new panel or tab, then right click the new area and add a New UI Element, scroll down to the Utility section and select Spider Monkey Panel and click OK. Now right click the new Spider Monkey Panel and select Edit Panel Script. Select the entire contents on the new ‘Temporary File’ window and replace them with the following script and click apply.

album_average_bpm.js
JavaScript
'use strict';
/*
====================================================
Album Average BPM Panel for foobar2000
Author: tom2tec
Created for www.audio-File.org
License: MIT
Repository: https://github.com/tom2tec/foobar2000-smp-album-average-bpm
Version: 1.0.0
====================================================
Description:
Spider Monkey Panel (SMP) JavaScript for foobar2000 that calculates and tags songs with
album-level BPM data
- Scan Library: Report number of files and albums missing album_avg_bpm values
- Generate / Update Album Avg BPM: Calculate and 12:01 PM 2026-02-12write album averages
- Force Recalculation: Recalculate all Album Average BPM values even if already calculated
- Select Median: Calculate and store median BPM instead of mean BPM values
Notes:
- Scanning alone does NOT calculate averages
- Requires track-level BPM data for calculation
- Missing BPMs are treated as 0 unless median is selected
- Designed specifically for SMP scripting environment
- Use at your own risk, backup your files before use.
Changelog:
v1.0.0 - Initial release
====================================================
*/
function RGB(r,g,b){ return (0xff000000 | (r<<16) | (g<<8) | b); }
////////////////////////////////////////////////////
// TitleFormats
////////////////////////////////////////////////////
const tf_album = fb.TitleFormat("%album%");
const tf_albumArtist = fb.TitleFormat("%album artist%");
const tf_artist = fb.TitleFormat("%artist%");
const tf_bpm = fb.TitleFormat("%bpm%");
const tf_existing = fb.TitleFormat("%album_avg_bpm%");
////////////////////////////////////////////////////
// UI Colours + Font
////////////////////////////////////////////////////
function getUIColours(){
try{
return { bg: window.GetColourDUI(1), text: window.GetColourDUI(0), accent: window.GetColourDUI(2) };
}catch(e){
return { bg: RGB(30,30,30), text: RGB(255,255,255), accent: RGB(0,200,0) };
}
}
function getUIFont(){ try{ return window.GetFontDUI(0); } catch(e){ return gdi.Font("Segoe UI",13,0); } }
////////////////////////////////////////////////////
// Library cache
////////////////////////////////////////////////////
let libHandles = null;
function loadLibraryOnce(){ if(!libHandles) libHandles = fb.GetLibraryItems(); }
////////////////////////////////////////////////////
// State
////////////////////////////////////////////////////
let runningUpdate=false;
let reporting=false;
let updateIndex=0, updateTimer=0;
let reportIndex=0, reportTimer=0;
let currentAlbum="Idle", currentFile="";
let updates=0;
let totalFiles=0, totalAlbums={};
let missingBPM=0, zeroBPM=0, missingAlbumAvg=0;
let minBPM=999999, maxBPM=0;
let albumConsistency={}, inconsistentAlbums=0;
let skippedFiles=[];
let forceRecalc=false, useMedian=false;
////////////////////////////////////////////////////
// Layout
////////////////////////////////////////////////////
const LEFT_WIDTH = 280;
const buttonScan={x:20,y:50,w:220,h:50};
const buttonUpdate={x:20,y:110,w:220,h:50};
const buttonCopy={x:20,y:170,w:220,h:50};
const checkboxForce={x:20,y:240,size:20};
const checkboxMedian={x:20,y:270,size:20};
////////////////////////////////////////////////////
// Album BPM Update Logic
////////////////////////////////////////////////////
let albumsMap=[];
function buildAlbums(){
loadLibraryOnce();
albumsMap = [];
let map={};
for(let i=0;i<libHandles.Count;i++){
let h=libHandles[i];
let album=tf_album.EvalWithMetadb(h) || "(No Album)";
let albumArtist=tf_albumArtist.EvalWithMetadb(h);
let artist=tf_artist.EvalWithMetadb(h) || "(No Artist)";
let bpm=parseFloat(tf_bpm.EvalWithMetadb(h));
if(isNaN(bpm)) bpm=0;
if(bpm>400) continue; // Filter extreme BPMs
let groupingArtist = albumArtist ? albumArtist : artist;
let key = groupingArtist+"|||"+album;
if(!map[key]){
map[key]={ handles:new FbMetadbHandleList(), sum:0, count:0, hasExisting:true, existingValues:{} };
}
map[key].handles.Add(h);
map[key].sum += bpm;
map[key].count++;
let albumAvg = tf_existing.EvalWithMetadb(h);
if(albumAvg) map[key].existingValues[albumAvg]=true;
if(!albumAvg) map[key].hasExisting=false;
}
albumsMap = Object.values(map);
}
function stopUpdateTimer(){ if(updateTimer){ window.ClearInterval(updateTimer); updateTimer=0; } }
function processUpdateNext(){
if(!runningUpdate) return;
if(updateIndex>=albumsMap.length){
runningUpdate=false;
stopUpdateTimer();
currentAlbum="Finished";
fb.ShowPopupMessage("Album BPM Update Finished. Updated Albums: "+updates);
window.Repaint();
return;
}
let data = albumsMap[updateIndex++];
currentAlbum = tf_album.EvalWithMetadb(data.handles[0]);
// Determine if update needed
let inconsistent = Object.keys(data.existingValues).length > 1;
if(!forceRecalc && !inconsistent) return;
let avg=0;
if(useMedian){
let arr=[];
for(let i=0;i<data.handles.Count;i++){
let val=parseFloat(tf_bpm.EvalWithMetadb(data.handles[i]));
if(!isNaN(val) && val<=400) arr.push(val);
}
arr.sort((a,b)=>a-b);
let mid=Math.floor(arr.length/2);
avg = arr.length%2===0 ? (arr[mid-1]+arr[mid])/2 : arr[mid];
}else{
avg = data.sum / data.count;
}
avg = avg.toFixed(2);
let json=[];
for(let i=0;i<data.handles.Count;i++){
try{
json.push({"ALBUM_AVG_BPM":avg});
}catch(e){
skippedFiles.push(data.handles[i].Path);
}
}
try{
data.handles.UpdateFileInfoFromJSON(JSON.stringify(json));
updates++;
}catch(e){
for(let i=0;i<data.handles.Count;i++) skippedFiles.push(data.handles[i].Path);
}
window.Repaint();
}
function startUpdate(){
if(runningUpdate) return;
loadLibraryOnce();
buildAlbums();
updates=0;
updateIndex=0;
runningUpdate=true;
// show first album immediately
if(albumsMap.length>0){
currentAlbum = tf_album.EvalWithMetadb(albumsMap[0].handles[0]);
}
window.Repaint();
updateTimer = window.SetInterval(processUpdateNext,100);
}
////////////////////////////////////////////////////
// Report Logic
////////////////////////////////////////////////////
let reportText="Press Scan Library.";
function stopReportTimer(){ if(reportTimer){ window.ClearInterval(reportTimer); reportTimer=0; } }
function processReportNext(){
if(!reporting) return;
let batch=500;
for(let c=0;c<batch && reportIndex<libHandles.Count;c++){
let h = libHandles[reportIndex++];
let album = tf_album.EvalWithMetadb(h) || "(No Album)";
let albumArtist = tf_albumArtist.EvalWithMetadb(h);
let artist = tf_artist.EvalWithMetadb(h) || "(No Artist)";
let bpmStr = tf_bpm.EvalWithMetadb(h);
let albumAvg = tf_existing.EvalWithMetadb(h);
let groupingArtist = albumArtist||artist;
let key=groupingArtist+"|||"+album;
totalFiles++;
totalAlbums[key]=true;
if(!bpmStr) missingBPM++;
let bpm=parseFloat(bpmStr);
if(!isNaN(bpm)){
if(bpm===0) zeroBPM++;
if(bpm>0){
if(bpm<minBPM) minBPM=bpm;
if(bpm>maxBPM) maxBPM=bpm;
}
}
if(!albumAvg) missingAlbumAvg++;
if(!albumConsistency[key]) albumConsistency[key]={};
if(albumAvg) albumConsistency[key][albumAvg]=true;
currentFile = groupingArtist+" - "+album;
}
if(reportIndex>=libHandles.Count){
reporting=false;
stopReportTimer();
inconsistentAlbums=0;
let inconsistentList=[];
for(let k in albumConsistency){
let vals=Object.keys(albumConsistency[k]);
if(vals.length>1){
inconsistentAlbums++;
if(inconsistentList.length<10) inconsistentList.push(k);
}
}
// Compose report
reportText =
`=== Library Diagnostic Report ===
Files:
- Total files scanned: ${totalFiles}
(All audio files counted)
- Total albums scanned: ${Object.keys(totalAlbums).length}
(Unique album/artist combinations)
BPM Status:
- Files missing BPM tag: ${missingBPM}
(Tracks without BPM information)
- Files with BPM = 0: ${zeroBPM}
(Tracks explicitly tagged with 0 BPM)
Album Avg Status:
- Files missing album_avg_bpm: ${missingAlbumAvg}
(Tracks without average album BPM set)
- Albums with inconsistent album_avg_bpm: ${inconsistentAlbums}
(Albums where tracks have different album_avg_bpm values)
Top Inconsistent Albums (up to 10):
${inconsistentList.length>0?inconsistentList.join("\n"):"None"}
Skipped / Inaccessible Files:
${skippedFiles.length>0?skippedFiles.join("\n"):"None"}
Current Status: Idle
BPM Range:
- Lowest BPM found: ${minBPM===999999?"N/A":minBPM}
- Highest BPM found: ${maxBPM}`;
}
window.Repaint();
}
function startReport(){
if(reporting) return;
loadLibraryOnce();
reportIndex=0;
totalFiles=0; totalAlbums={};
missingBPM=0; zeroBPM=0; missingAlbumAvg=0;
minBPM=999999; maxBPM=0; albumConsistency={};
skippedFiles=[];
reporting=true;
reportText="Scanning library...";
// show first file immediately
if(libHandles.Count>0){
currentFile = tf_album.EvalWithMetadb(libHandles[0]) || "(No Album)";
}
window.Repaint();
reportTimer = window.SetInterval(processReportNext,10);
}
////////////////////////////////////////////////////
// Drawing
////////////////////////////////////////////////////
function drawButton(gr,b,label,ui,font){
gr.FillSolidRect(b.x,b.y,b.w,b.h,ui.accent);
gr.DrawString(label,gdi.Font(font.Name,14,1),ui.text,b.x,b.y,b.w,b.h,0x11000000);
}
function drawCheckbox(gr,c,label,state,ui,font){
gr.DrawRect(c.x,c.y,c.size,c.size,1,ui.text);
if(state) gr.FillSolidRect(c.x+4,c.y+4,c.size-8,c.size-8,ui.accent);
gr.DrawString(label,font,ui.text,c.x+28,c.y-2,300,24,0);
}
function on_paint(gr){
let ui=getUIColours();
let font=getUIFont();
let titleFont=gdi.Font(font.Name,16,1);
gr.FillSolidRect(0,0,window.Width,window.Height,ui.bg);
// LEFT PANEL
gr.DrawString("Album Avg BPM Tools",titleFont,ui.text,20,10,LEFT_WIDTH,30,0);
drawButton(gr,buttonScan,"Scan Library",ui,font);
drawButton(gr,buttonUpdate,"Run Album BPM Update",ui,font);
drawButton(gr,buttonCopy,"Copy Report",ui,font);
drawCheckbox(gr,checkboxForce,"Force Recalculate",forceRecalc,ui,font);
drawCheckbox(gr,checkboxMedian,"Use Median Averaging",useMedian,ui,font);
gr.DrawLine(LEFT_WIDTH,0,LEFT_WIDTH,window.Height,1,ui.text);
// RIGHT PANEL - report text
let statusText = reporting ? "Scanning: "+currentFile : runningUpdate ? "Updating Album BPM: "+currentAlbum : "Idle";
let reportWithStatus = reportText.replace("Current Status: Idle","Current Status: "+statusText);
gr.GdiDrawText(reportWithStatus,font,ui.text,
LEFT_WIDTH+20,20,
window.Width-(LEFT_WIDTH+40),
window.Height-160,0); // leave 160px for progress bars
// Progress bars
const barHeight = 18;
const margin = 8;
const barYUpdate = window.Height - 2*barHeight - 2*margin;
const barYScan = window.Height - barHeight - margin;
if(runningUpdate){
let prog=Math.floor((updateIndex/albumsMap.length)*(window.Width-LEFT_WIDTH-40));
gr.FillSolidRect(LEFT_WIDTH+20,barYUpdate,prog,barHeight,ui.accent);
gr.DrawRect(LEFT_WIDTH+20,barYUpdate,window.Width-LEFT_WIDTH-40,barHeight,1,ui.text);
gr.DrawString("Updating Album BPM: "+currentAlbum,font,ui.text,LEFT_WIDTH+20,barYUpdate-25,window.Width-LEFT_WIDTH-40,20,0);
}
if(reporting){
let prog=Math.floor((reportIndex/libHandles.Count)*(window.Width-LEFT_WIDTH-40));
gr.FillSolidRect(LEFT_WIDTH+20,barYScan,prog,barHeight,ui.accent);
gr.DrawRect(LEFT_WIDTH+20,barYScan,window.Width-LEFT_WIDTH-40,barHeight,1,ui.text);
gr.DrawString("Scanning: "+currentFile,font,ui.text,LEFT_WIDTH+20,barYScan-25,window.Width-LEFT_WIDTH-40,20,0);
}
}
////////////////////////////////////////////////////
// Mouse
////////////////////////////////////////////////////
function on_mouse_lbtn_up(x,y){
if(hit(buttonScan,x,y)) {
startReport();
reportText = "Scanning library...";
currentFile = libHandles.Count>0 ? tf_album.EvalWithMetadb(libHandles[0]) || "(No Album)" : "Idle";
window.Repaint();
}
if(hit(buttonUpdate,x,y)) {
startUpdate();
currentAlbum = albumsMap.length>0 ? tf_album.EvalWithMetadb(albumsMap[0].handles[0]) : "Preparing update...";
window.Repaint();
}
if(hit(buttonCopy,x,y) && reportText){
utils.SetClipboardText(reportText);
fb.ShowPopupMessage("Report copied to clipboard.");
}
if(hitSquare(checkboxForce,x,y)){ forceRecalc=!forceRecalc; window.Repaint(); }
if(hitSquare(checkboxMedian,x,y)){ useMedian=!useMedian; window.Repaint(); }
}
function hit(b,x,y){ return x>=b.x && x<=b.x+b.w && y>=b.y && y<=b.y+b.h; }
function hitSquare(c,x,y){ return x>=c.x && x<=c.x+c.size && y>=c.y && y<=c.y+c.size; }

Album Avg BPM Tools Script

Dancing QT ~  Player For Dancing Schools


Dancing QT is a combined music database and player application specially designed for dancing schools and equivalent applications. Key features are an easy-to-use interface, fast search capabilities, playlist management, exact pitching and crossfading.

Looking around the open source landscape for a while, I tried to find a music database and player that is suitable for use in a dancing school environment – without success. Most mixing applications tend to be too confusing for the intended audience, most players lack database searching capabilites and most song databases don’t know how to pitch 😦

Because of this, I decided to setup a new application – Dancing QT. It uses alsaplayer because of its excellent interface and pitching capabilities, it uses an embedded SQLite DBMS to maintain a song database, and it uses taglib to populate the database. The interface is written in C++ using Qt. Because of the alsaplayer dependency, the target platforms will be limited to environments providing alsaplayer.

Dancing QT Interface

dqt.sourceforge.net
sourceforge.net/projects/dqt

Cynthia ~ Multitrack MIDI Player


Reliably play midi music files from a folder or “.m3u” playlist. Adjust playback speed, volume and output device on the fly during playback. A large playback progress bar makes jumping forward and backward in time a breeze with just a single click or tap. Supports “.mid”, “.midi” and “.rmi” files in format 0 (single track) and format 1 (multi-track). Comes complete with 24 sample midis ready to play.

Features:

  • Dual play systems – Play Folder and Play List
  • Comes with 24 built-in sample midis on a virtual disk
  • Elapsed, Remaining and Total time readouts
  • Native “.m3u” playlist support (copy, paste, open, save, build)
  • Drag and drop midi files to play / add to playlist
  • Play Modes: Once, Repeat One, Repeat All, All Once, Random
  • Play Speed: 10% to 1,000% (1/10th to 10x)
  • Intro Mode: Play first 2s, 5s, 10s or 30s of midi
  • Rewind / Fast Forward by: 1s, 2s, 5s, 10s or 30s
  • Play on Start option – playback commences on app start
  • Always on Midi option – maintain connection to midi device for instant playback
  • Auto Fade In – eliminate loud or abrupt notes during rewind, fast forward or reposition operations
  • Playback Progress bar – click to reposition/jump backward or forward in time
  • Volume control with volume boost (up to 200%)
  • Play “.mid”, “.midi” and “.rmi” midi files in 0 and 1 formats
  • Custom built midi playback subsystem for high playback stability
  • Scrolling lyrics viewer
  • Detailed midi information panel
  • Tracks Panel: Realtime track data indicators with mute all, unmute all, and mute individual track options
  • Channels Panel: Realtime channel output volume indicators with peak level hold and variable hold time, unmute all, mute all, and mute individual channel options
  • Notes Panel: 128 realtime note usage indicators with variable hold time, 8-12 notes per line display, labels as letters or numbers, unmute all, mute all, and mute individual note options
  • Piano Panel: View realtime piano keystrokes on a 128, 88, 76, 61, 54, 49 or 37 key keyboard with animated and lit keystrokes
  • Piano: Mark middle C key, C + F keys, or all white keys
  • Transpose option: Shift all notes up or down music scale
  • Use an Xbox Controller to control Cynthia’s main functions – playback speed and volume, song position, display panels, song file navigation, jump to start of song, toggle fullscreen mode, etc
  • Large list capacity for handling thousands of midi files
  • Switch between up to 10 midi playback devices
  • Simple and easy to use
  • Options Window – Easily change app color, font and settings
  • Portable

sourceforge.net/projects/cynthia1
www.blaizenterprises.com/cynthia

BlackDiamond ~ Fruityloops Studio Clone


Fruityloops clone with sound samples using Fmodex lib

BlackDiamond (formerly Crazy Machine) is a project I neglected for years until I got back into making music. The package comes with free VST plugins and samples, and soon to be introduced at some point in time, perfect sequencer sample mixer playback thingamagiggy we are now back in full armor trying to create the wildest dreams of software working on BlackDiamond.

Features:

  • Six built in effects for each 16 channels Flange, Chorus, Compression, Echo, Distortion, Reverb
  • fruity loops style pattern manipulation
  • Written in FreeBasic, the most best freeware IDE compiler for basic language
  • Recent May 2019 re-programming to V3
  • VST and Dialog window support, switch plugins with a click
  • calculations are now down to the clock cycle to milliseconds
  • Load VST plugins, samples during playback.
  • View VST plugin dialog, which works when using SET MS method
  • SET MS (Alter VST plugin data) now very easily tuneable
  • Supports ASIO Interface and Microsoft Windows wave file writing

sourceforge.net/projects/jesuschristsuns

lipupini ~ Media File Organization System


Lipupini is a public domain platform for organizing computer files like images, videos, sounds and writings that you might want to display under your domain on the Internet. Lipupini aims to support RSS and Fediverse protocols.

github.com/lipupini/lipupini
lipupini-demo.dup.bz/@example

AirWindows ~ Meter Plugin


This is a first JUCE plugin, meant to offer some useful metering.

github.com/airwindows/Meter/releases

QPxTool ~ Check The Quality


QPxTool is the Linux way to get full control over your CD/DVD drives. It is the Open Source Solution which intends to give you access to all available Quality Checks (Q-Checks) on written and blank media, that are available for your drive. This will help you to find the right media and the optimized writing speed for your hardware, which will increase the chance for a long data lifetime. See supported devices to get a list of the currently supported hardware.

QPxTool
QPxTool

Supported tests:

  • FE/TE Scan on written media
  • PIE / PIF / POF Scan
  • TA Scan
  • Jitter / Beta Scan
  • Transfer Rate Scan
  • C1, C2 and CU Scan
  • Extended CD Scan
  • Blank Media Quality Check
  • FE/TE Scan on blank media

qpxtool.sourceforge.io/qpxtool
github.com/dhucul/qpxtool

AudioPlayer ~ CD Image Player


This is an audio player for Windows, Linux and MacOS.

It is designed to play audio CDs dumped to raw bin/cue files.

The bin/cue files can be loaded from a folder on disk, or from a zip archive.

This player provides a convenient way of listening to dumps in that format without any additional step(s):

  • No need to mount the cue file as a virtual drive.
  • No need to extract the cue/bin files from zip files.
  • No need to convert the data to wav/flac/ogg/mp3.

This is currently NOT supported:

  • Playing from archives in 7z and rar formats.
  • Playing music from other formats such as wav, mp3, flac, ogg, etc. Just use a regular music player for that.

Album and track metadata is loaded from the CDTEXT information when present in cue file.

Additional metadata is optionally retrieved from CueToolsDB, including album art.

Lyrics are optionally retrieved from LRCLIB. Using a local LRCLIB sqlite3 database is also supported.

AudioPlayer Interface

github.com/huguesv/AudioPlayer

Amp Rack ~ Android Audio Effects Processor


Amp Rack is a Guitar / Voice Audio Effects Processor for Android. Amp Rack is an Open Source LADSPA Plugins Host for Android. More than 150 high quality audio plugins are available which can be added in any order to the audio effect chain to create distinct high quality tones for your guitar!

github.com/djshaji/amp-rack
play.google.com/store/apps/dev?id=8472172756594763620

Cue ~ WordPress Audio Playlists


Delightful and reliable audio playlists.

Cue makes it easy to create and manage beautiful, fully responsive audio playlists. Primarily built with music in mind, Cue can also be used for podcasts, sermons or to showcase voice over samples.

There’s no need to fiddle with XML, JSON, or FTP. Just upload audio files with the familiar WordPress Media Manager, then insert them into a playlist with the click of a button. Cue fetches metadata from uploaded files to automatically complete the title, artist, and length for each track.

It works on desktop, tablets, and other mobile devices.

Features:

  • Create unlimited playlists.
  • Embed a player in any post, page, or sidebar using a shortcode or widget.
  • Reorder tracks with a simple drag and drop interface.
  • Seamlessly integrates with WordPress media manager to select audio and images.
  • Automatically fetches title, artist, and length from the metadata if it’s available.
  • Completely responsive to work on any device that supports your audio format.
  • Link to external sources like Amazon S3 or other CDNs.
  • Customize the player background image.
  • Use custom artwork for each track.

github.com/audiotheme/cue

Java SID Player ~ Commodore 64 Emulator


Java SID Player Music Library V2

This is a Commodore 64 emulator specialized for sound reproduction. It is also a SID player for music collections like HVSC and CGSC. It is a full C64 emulator and can play games of the GameBase64 project as well.

Features:

  • Cycle-Exact C64 Emulator

sourceforge.net/projects/jsidplay2
openhub.net/p/jsidplay2

Online:

haendel.ddns.net:8443/static/c64jukebox.vue

PKHarmonic VST Plugin ~ Audiophile Harmonics Generator


distortaudio.org/pkharmonic