Package: sf2-loader
sf2_loaderThis is an easy-to-use soundfonts loader, player and audio renderer in python.This is probably the most handy soundfont loader, player and renderer via pure programming at the time I am writing now (2021/8/29). This is a python package for handling SoundFont files, it has the following functionality:Load any soundfont files, including sf2 and sf3Listen to every preset in every bank in the soundfont files that are loaded using very simple syntaxPlay or export audio files for each note in a pitch range for any instruments in the soundfont filesPlay or export the whole piece of music as audio files with custom audio effectsLoading as much soundfont files as you canFor more functionalities that this soundfont loader provides, please continue reading.ContentsIntroductionInstallationWindowsLinuxmacOSUsageInitialize a soundfont loaderLoad sondfont filesThe representation of the soundfont loaderChange current channel, soundfont id, bank number and preset numberAbout channel initializationGet the instrument namesPlay notes, chords, pieces and MIDI filesExport notes, chords, pieces and MIDI filesExport instrumentsAudio effectsPause, unpause and stop current playing soundsIntroductionThis sf2 loader is heavily combined withmusicpy, which is one of my most popular project, focusing on music programming and music analysis and composition. If you have already learned how to use musicpy to build notes, chords and pieces, you can straightly pass them to the sf2 loader and let it play what you write. Besides of playing music with the loaded soundfonts files, I also write an audio renderer in the sf2 loader, which could render the audio from the loaded soundfont files with the input musicpy data structures and output as audio files, you can choose the output format, such as wav, mp3, ogg, and output file names, sample width, frame rate, channels and so on. In fact, this project borns with my attempt at making muscipy's daw module being able to load soundfont files to play and export audio files.If you are not familiar with musicpy data structures and is not willing to learn it in recent times, you can also straightly using MIDI files as input to the sf2 loader, and export the rendered audio files using the loaded soundfont files. However, I still recommend you to learn about musicpy, even not to consider music programming and analysis, it could also be very useful for MIDI files editing and reconstructing.This sf2 loader is compatible with both 32-bit and 64-bit python versions, for python >= 3.6, so be sure your installed python version match the requirements for this package to use.This package is currently being tested on Windows, Linux and macOS. For Windows version, this package is tested on Windows 10.Update: (2021/12/3) After many updates, currently the latest version is all compatible with Windows, Linux and macOS, so no compatible version is needed anymore, on Linux and macOS you just need to pip install sf2 loader the same as in Windows, and then you need to install fluidsynth and ffmpeg separately on Linux and macOS, the installation instruction is updated.Update: (2021/9/5) The macOS compatible version is ready, the installation and configuration of Linux compatible version is at the installation section of this readme. This macOS compatible version of sf2_loader is tested on Catalina 10.15.5.Update: (2021/9/5) The Linux compatible version is ready, the installation and configuration of Linux compatible version is at the installation section of this readme. This Linux compatible version of sf2_loader is tested on Ubuntu 18.04.5.Important note 1: the required python package musicpy is updated very frequently, so please regularly update musicpy by runningpipinstall--upgrademusicpyin cmd/terminal.Important note 2: If you cannot hear any sound when running the play functions, this is because some IDE won't wait till the pygame's playback ends, they will stops the whole process after all of the code are executed without waiting for the playback. You can setwait=Truein the parameter of the play functions, which will block the function till the playback ends, so you can hear the sounds.InstallationWindowsYou can use pip to install this sf2 loader.Run this line in cmd/terminal to install.pipinstallsf2_loaderNote: This package uses pydub as a required python package, which requires ffmpeg or libav installed to have abilities to deal with non-wav files (like mp3, ogg files), so I strongly recommend to install ffmpeg/libav and configure it correctly to make pydub working perfectly. You can refer to thislinkwhich is pydub's github main page readme to see how to do it, or you can follow the steps I provide here, which is easier and faster.Firstly, download the ffmpeg zip file from thislink, this is from the release page of musicpy which requires ffmpeg for the musicpy's daw module.Then, unzip the folderffmpegfrom the zip file, put the folder inC:\Then, add the pathC:\\ffmpeg\\binto the system environment variable PATH.Finally, restart the computer.Now you are all done with the set up of ffmpeg for pydub. If there are no warnings about ffmpeg from pydub pop up after you import this package, then you are good to go.LinuxYou can use pip to install this sf2 loader, which is the same as in Windows.Then, there are some important and necessary steps to configure this package in order to use it on Linux:Firstly, you need to install fluidsynth on Linux, you can refer to thislinkto see how to install fluidsynth on different Linux systems. Here I will put the install command for Ubuntu and Debian:sudo apt-get install fluidsynthRun this command in terminal on Ubuntu or Debian, and waiting for fluidsynth to finish installing.Secondly, you need to install ffmpeg on Linux (the same reason as in Windows), you can just run this command in terminal to install ffmpeg on Linux:sudo apt-get install ffmpeg libavcodec-extramacOSYou can use pip to install this sf2 loader, which is the same as in Windows.Then, there are some important and necessary steps to configure this package in order to use it on macOS:Firstly, you need to install fluidsynth on macOS, the easiest way to install ffmpeg in macOS is using homebrew. You need to make sure you have installed homebrew in macOS first, and then runbrew install fluidsynthin terminal, and waiting for fluidsynth to be installed.If you haven't installed homebrew before and cannot find a good way to install homebrew, here I will provide a very easy way to install homebrew on macOS, thanks from Ferenc Yim's answer from thisStack Overflow question:open thislinkin your browser, right-click and save it to your computer, and then open a terminal and run it with:/bin/bash path-to/install.sh, and waiting for homebrew to be installed.Secondly, you need to install ffmpeg on macOS (the same reason as in Windows), you can just run this command in terminal to install ffmpeg on macOS using homebrew:brew install ffmpegUsageHere are the syntax for the most important functionalities of this sf2 loader.Firstly, you can import this sf2 loader using this line:importsf2_loaderassfor you can using this line, which is without namespace, but this is not recommended in big projects because of potential naming conflicts with other python packages you import.fromsf2_loaderimport*Here we will use the first way of import as the standard.When you install sf2_loader, the musicpy package will be installed at the same time. The musicpy package is imported in sf2_loader asmp, so you can use musicpy package straightly by callingsf.mp.Initialize a soundfont loaderTo initialize a soundfont loader, you can pass a soundfont file path to the classsf2_loader, or leave it as empty, and useloadfunction ofsf2_loaderto load soundfont files later.loader=sf.sf2_loader(soundfont_file_path)# orloader=sf.sf2_loader()# examplesloader=sf.sf2_loader(r'C:\Users\Administrator\Desktop\celeste.sf2')# orloader=sf.sf2_loader('C:/Users/Administrator/Desktop/celeste.sf2')Load sondfont filesYou can load a soundfont file when you initialize asf2_loaderby passing a soundfont file path to the initialize function, or useloadfunction of the sf2 loader to load new soundfont files into the sf2 loader.Each time you load a soundfont file, the sf2 loader will save the soundfont file name and the soundfont id, you can get and use them by calling the attributesfileandsfid_listof the sf2 loader.You can unload a loaded soundfont file by index (1-based) usingunloadfunction of the sf2 loader.loader=sf.sf2_loader(soundfont_file_path)loader.load(soundfont_file_path2)# examplesloader=sf.sf2_loader(r'C:\Users\Administrator\Desktop\celeste.sf2')loader.load(r'C:\Users\Administrator\Desktop\celeste2.sf2')>>>loader.file['C:\\Users\\Administrator\\Desktop\\celeste.sf2','C:\\Users\\Administrator\\Desktop\\celeste2.sf2']# if the soundfont file does not exist in the given file path, the soundfont id will be -1>>>loader.sfid_list[1,2]loader.unload(2)# unload the second loaded soundfont files of the sf2 loader>>>loader.file['C:\\Users\\Administrator\\Desktop\\celeste.sf2']The representation of the soundfont loaderYou can print the sf2 loader and get the information that the sf2 loader currently has.The channel number, bank number and preset number are 0-based, the soundfont id is 1-based.>>>loader[soundfontloader]loadedsoundfonts:['C:\\Users\\Administrator\\Desktop\\celeste.sf2','C:\\Users\\Administrator\\Desktop\\celeste2.sf2']soundfontsid:[1,2]currentchannel:0currentsoundfontid:1currentsoundfontname:celeste.sf2currentbanknumber:0currentpresetnumber:0currentpresetname:StereoGrandChange current channel, soundfont id, bank number and preset numberEach channel of the sf2 loader has 3 attributes, which are SoundFont id, bank number and preset number. The sf2 loader has a attributecurrent_channelwhich is used when displaying current information of current channel.You can use thechangefunction of the sf2 loader to change either one or some or all of the current channel, soundfont id, bank number and preset number of the sf2 loader. You can use either preset number or preset name to change current preset of a channel.There are also some syntactic sugar I added for this sf2 loader, which is very convenient in many cases.For example, you can useloader < presetto change the current preset number of the sf2 loader to change the instrument of the soundfont files that the sf2 loader will use to play and export, while current channel, soundfont id and bank number remain unchanged. This syntactic sugar also accept second parameter as the bank number, which is used asloader < (preset, bank).You can also useloader % channelto change current channel.There are also a change function for each attribute of current channel, soundfont id, bank number and preset number, namelychange_channel,change_sfid,change_bank,change_preset.Each change function exceptchange_channelhas an optional argumentchannelto specify change which channel's attribute, if not specified, then change current channel's attribute by default.loader.change(channel=None,sfid=None,bank=None,preset=None,correct=True,hide_warnings=True,mode=0)# If you only need to change one or some of the attributes,# you can just specify the parameters you want to change,# the unspecified parameters will remain unchanged.# correct: if you set it to True,# when the given parameters cannot find any valid instruments,# the sf2 loader will go back to the program before the change,# if you set it to False, the program will be forced to change to the# given parameters regardless of whether the sf2 loader can find any valid# instruments or not# hide_warnings: prevent warning messages from external C/C++ libraries printed to the terminal or not# mode: if set to 0, then when channel is specified, the current channel of the sf2 loader will be changed# to that channel, and then change other specified attributes, otherwise,# change other attributes within the specified channel,# but current channel of the sf2 loader remain unchanged# examplesloader.change(preset=2)# change current preset number to 2loader.change(preset='Strings')# change current preset to Stringsloader.change(bank=9,preset=3)# change current bank number to 9 and current preset number to 3loader.change_preset(2)# change current preset number to 2loader.change_preset('Strings')# change current preset to Stringsloader.change_bank(9)# change current bank number to 9loader.change_bank(9,channel=1)# change current bank number of channel 1 to 9loader.change_channel(2)# change current channel to 2loader.change_sfid(2)# change current soundfont id to 2loader.change_soundfont('celeste2.sf2')# change current soundfont file to celeste2.sf2, the parameter could be full path or# just the file name of the soundfont file, but it must be loaded in# the sf2 loader alreadyloader<2# change current preset number to 2loader<'Strings'# change current preset to Stringsloader<(3,9)# change current bank number to 9, current preset number to 3loader<('Strings',9)# change current bank number to 9, current preset to Stringsloader%1# change current channel to 1About channel initializationNote that when a sf2 loader is initialized, the channel 0 will be automatically initialized, but other channels are not initialized. If you use a channel that is not initialized to play a sound or render audio, you will get no sound, which is the same for a channel that is initialized but with an invalid preset. But there are automatic initialization of channels built in this sf2 loader to make things easier.When you change to a channel that is not initialized, the program will automatically initialize that channel by select the first loaded SoundFont id to that channel and select the first valid instrument in bank 0 (or bank 128 for channel 9). If no valid instrument is found in bank 0 (or bank 128 for channel 9), then that channel will be initialized with no valid current preset, you will need to select a valid preset for that channel by looking at the result of the functionall_instrumentswhich returns all of the available banks and presets in current SoundFont file, I will talk about this function later.The automatic initialization of channels that are not initialized will also take place when you trying to play or export a piece instance of musicpy or MIDI files using channels that are not initialized (not for playing or exporting note and chord). However, there is at least one situation that you will still get no sound with uninitialized channels, that is when the automatic initialization of a channel cannot find a valid preset of the initial bank number, then it will remain initialized but with no valid current preset. In this case, you will need to select a valid preset for that channel yourself in order to get sound when playing or exporting using that channel.If you want to manually initialize a channel, you can useinit_channelfunction of sf2 loader, which takes a paremeterchannel.The initial bank number is 0 for each channel except channel 9, which is 128, since channel 9 is for percussion as default. The initial preset number for each channel is 0, but this might not be the first valid preset number for current SoundFont id and current bank number. The initial SoundFont id for a channel that is not initialized is 0, if a channel is initialized, then it will have a SoundFont id that is >= 1. You can use this information to check if a channel is already initialized or not. To get current SoundFont id of a channel, useget_sfidfunction of sf2 loader, which I will talk about later, or you can usevalid_channelfunction of sf2 loader to check if a channel is already initialized or not.You can initialize channels as much as you can in this sf2 loader, which could be more than 16 channels (the restriction of MIDI 1.0). But since most MIDI files out there are at most 16 channels, so this advantage does not actually works well if you directly use MIDI files for this sf2 loader. If you useexport_piecefunction to export a piece instance of musicpy to audio files, the number of channels and tracks of a piece instance could be more than 16, and they will be successfully rendered to audio. If you are interested in this, you can check out the piece data structure in the wiki of musicpy.To reset the current configuration of all channels, you can usereset_all_channelsfunction of sf2 loader, which will reset all channels to uninitialized state.Get the instrument namesIf you want to get the instrument names of the soundfont files you load in the sf2 loader, you can useget_all_instrument_namesfunction of the sf2 loader, which will give you a list of instrument names that current soundfont file's current bank number has (or you can specify them), with given maximum number of preset number to try, start from 0. By default, the maximum number of the preset number to try is 128, which is from 0 to 127. If you want to get the exact preset numbers for all of the instrument names in current bank number, you can set the parameterget_indtoTrue.loader.get_all_instrument_names(sfid=None,bank=None,max_num=128,get_ind=False,mode=0,return_mode=0,hide_warnings=True)# mode: when get_ind is True, if mode is 1, the current preset number will be set to the first available# instrument in the current bank number# return_mode: if it is 0, then when get_ind is set to True, this function# will return a dictionary which key is the preset number, value is the# corresponding instrument name; if it is 1, then when get_ind is set to True,# this function will return a tuple of 2 elements, which first element is# a list of instrument names and second element is a list of the# corresponding preset numbersIf you want to get all of the instrument names of all of the available banks of the soundfont files you load in the sf2 loader, you can useall_instrumentsfunction of the sf2 loader, which will give you a dictionary which key is the available bank number, value is a dictionary of the presets of this bank, which key is the preset number and value is the instrument name. You can specify the maximum of bank number and preset number to try, the default value of maximum bank number to try is 129, which is from 0 to 128, the default value of maximum preset number for each bank to try is 128, which is from 0 to 127. You can also specify the soundfont id to get all of the instrument names of a specific soundfont file you loaded, in case you have loaded multiple soundfont files in the sf2 loader.loader.all_instruments(max_bank=129,max_preset=128,sfid=None,hide_warnings=True)# max_bank: the maximum bank number to try,# the default value is 129, which is from 0 to 128# max_preset: the maximum preset number to try,# the default value is 128, which is from 0 to 127# sfid: you can specify the soundfont id to get the instrument names# of the soundfont file with the soundfont idTo get the instrument name of  a given soundfont id, bank number and preset number, you can useget_instrument_namefunction.loader.get_instrument_name(sfid=None,bank=None,preset=None,hide_warnings=True)To get current instrument name, you can useget_current_instrumentfunction.loader.get_current_instrument()To get current soundfont id, bank number and preset number of a given channel, you can usechannel_infofunction, which returns a tuple(sfid, bank, preset).To get one of current SoundFont id, current bank number, current preset number and current preset name of a channel, you can use functionsget_sfid,get_bank,get_preset,get_preset_name, which all takes a parameterchannel, which has a default valueNone, if the channel parameter is None, then use current channel. For the functionget_preset_name, if the channel has not yet initialized, it will return None.loader.channel_info(channel=None)# channel: if channel is None, then returns the channel info of current channelloader.get_sfid()# get current channel's SoundFont idloader.get_bank(1)# get current bank number of channel 1loader.get_preset(1)# get current preset number of channel 1loader.get_preset_name(1)# get current preset name of channel 1Here is an example of getting all of the instrument names in current bank number.>>>loader.get_all_instrument_names()['Stereo Grand','Bright Yamaha Grand','Electric Piano','Honky-tonk EMU2','Electric Piano 1','Legend EP 2','St.Harpsichd_Lite','Clavinet','Celesta','Glockenspiel','Music Box','VivesPS06','prc:Marimba','Xylophone','Tubular Bells','Dulcimer','DrawbarOrgan','PercOrganSinkla','Rock Organ','Church Organ','Reed Organ','Accordian','Harmonica','Bandoneon','TyrosNylonLight','Steel Guitar','Jazz Gt','Dry Clean Guitar','Palm Muted Guitar','Garcia _0_29','Les Sus_0_30','Guitar Harmonic','Acoustic Bass','MM JZ.F_0_33','BassPick&Mutes','Fretless Bass','Slap Bass 1','Slap Bass 2','Synth Bass 1','Synth Bass 2','Violin','Viola','Cello','Contrabass','Tremolo','Pizzicato Section','ClavinovaHarp','Timpani','Strings Orchest','Slow Strings','Synth Strings 1','Synth Strings 2','Ahh Choir','Ohh Voices','SynVoxUT','Orchestra Hit','Romantic Tp','Solo Bo_0_57','Tuba','Sweet Muted','FH LONG_0_60','BRASS','AccesVirusBrass','Synth B_0_63','Soprano Sax','Altsoft vib','Blow Tenor','Bari Sax','Oboe','English Horn','Bassoon','Clarinet','Piccolo','Flute','Recorder','ClavinovaPanFlu','Bottle Blow','Shakuhachi','Whistle','Ocarina','Square Wave','Saw Wave','Calliope Lead','Chiffer Lead','Charang','Solo Vox','Fifth Sawtooth Wave','Bass & Lead','Fantasia','Warm Pad','Polysynth','Space Voice','Bowed Glass','Metal Pad','Halo Pad','Sweep Pad','Ice Rain','Soundtrack','Crystal','Atmosphere','Brightness','Goblin','Echo Drops','Star Theme','Sitar','Banjo','Shamisen','Koto','Kalimba','BagPipe','Fiddle','Shenai','Tinker Bell','Agogo','Steel Drums','Woodblock','Taiko Drum','Melodic Tom','Synth Drum','Reverse Cymbal','Fret Noise','Breath Noise','Sea Shore','Bird Tweet','Telephone','Helicopter','Applause','Gun Shot']Here is an example of getting all of the instrument names of all of the available banks.>>>loader.all_instruments(){0:{0:'Grand Piano',1:'Bright Piano',2:'Rock Piano',3:'Honky-Tonk Piano',4:'Electric Piano',5:'Crystal Piano',6:'Harpsichord',7:'Clavinet',8:'Celesta',9:'Glockenspiel',10:'Music Box',11:'Vibraphone',12:'Marimba',13:'Xylophone',14:'Tubular Bells',15:'Dulcimer (Santur)',16:'DrawBar Organ',17:'Percussive Organ',18:'Rock Organ',19:'Church Organ',20:'Reed Organ',21:'Accordion',22:'Harmonica',23:'Bandoneon',24:'Nylon Guitar',25:'Steel String Guitar',26:'Jazz Guitar',27:'Clean Guitar',28:'Muted Guitar',29:'Overdrive Guitar',30:'Distortion Guitar',31:'Guitar Harmonics',32:'Acoustic Bass',33:'Fingered Bass',34:'Picked Bass',35:'Fretless Bass',36:'Slap Bass 1',37:'Slap Bass 2',38:'Synth Bass 1',39:'Synth Bass 2',40:'Violin',41:'Viola',42:'Cello',43:'ContraBass',44:'Tremolo Strings',45:'Pizzicato Strings',46:'Orchestral Harp',47:'Timpani',48:'Strings Ensemble 1',49:'Strings Ensemble 2',50:'Synth Strings 1',51:'Synth Strings 2',52:'Choir Aahs',53:'Voice Oohs',54:'Synth Voice',55:'Orchestra Hit',56:'Trumpet',57:'Trombone',58:'Tuba',59:'Muted Trumpet',60:'French Horns',61:'Brass Section',62:'Synth Brass 1',63:'Synth Brass 2',64:'Soprano Sax',65:'Alto Sax',66:'Tenor Sax',67:'Baritone Sax',68:'Oboe',69:'English Horns',70:'Bassoon',71:'Clarinet',72:'Piccolo',73:'Flute',74:'Recorder',75:'Pan Flute',76:'Blown Bottle',77:'Shakuhachi',78:'Whistle',79:'Ocarina',80:'Square Wave',81:'Saw Wave',82:'Synth Calliope',83:'Chiffer Lead',84:'Charang',85:'Solo Voice',86:'5th Saw Wave',87:'Bass & Lead',88:'Fantasia (New Age)',89:'Warm Pad',90:'Poly Synth',91:'Space Voice',92:'Bowed Glass',93:'Metal Pad',94:'Halo Pad',95:'Sweep Pad',96:'Ice Rain',97:'Sound Track',98:'Crystal',99:'Atmosphere',100:'Brightness',101:'Goblin',102:'Echo Drops',103:'Star Theme',104:'Sitar',105:'Banjo',106:'Shamisen',107:'Koto',108:'Kalimba',109:'Bag Pipe',110:'Fiddle',111:'Shannai',112:'Tinkle Bell',113:'Agogo',114:'Steel Drums',115:'Wood Block',116:'Taiko Drum',117:'Melodic Tom',118:'Synth Drum',119:'Reverse Cymbal',120:'Guitar Fret Noise',121:'Breath Noise',122:'Sea Shore',123:'Bird Tweets',124:'Telephone',125:'Helicopter',126:'Applause',127:'Gun Shot'},128:{0:'Standard Drum Kit',8:'Room Drum Kit',16:'Power Drum Kit',24:'Electronic Drum Kit',25:'TR-808/909 Drum Kit',32:'Jazz Drum Kit',40:'Brush Drum Kit',48:'Orchestral Drum Kit',49:'Fix Room Drum Kit',127:'MT-32 Drum Kit'}}Play notes, chords, pieces and MIDI filesYou can useplay_notefunction of the sf2 loader to play a note with specified pitch using current channel, soundfont id, bank number and preset number. The note could be a string representing a pitch (for example,C5) or a musicpy note instance. If you want to play the note by another instrument, you need to change current preset (and other program parameters if needed) before you useplay_notefunction, the same goes for other play functions.loader.play_note(note_name,duration=2,decay=1,volume=100,channel=0,start_time=0,sample_width=2,channels=2,frame_rate=44100,name=None,format='wav',effects=None,bpm=80,export_args={},wait=False)# note_name: the name of the note, i.e. C5, D5, C (if the octave number# is not specified, then the default octave number is 4), or musicpy note instance# duration: the duration of the note in seconds# decay: the decay time of the note in seconds# volume: the volume of the note in MIDI velocity from 0 - 127# channel: the channel to play the note# start_time: the start time of the note in seconds# sample_width: the sample width of the rendered audio# channels: the number of channels of the rendered audio# frame_rate: the frame rate of the rendered audio# name: the file name of the exported audio file, this is only used in export_note function# format: the audio file format of the exported audio file, this is only used in export_note function# effects: audio effects you want to add to the rendered audio# bpm: the BPM of the note# export_args: a keyword dictionary, the other keyword arguments for exporting,# you can refer to the keyword parameters of pydub's AudioSegment's export function,# a useful situation is to specify the bitrate of the exported mp3 file# to be exported (when you set the format parameter to 'mp3'), for example,# we want to specify the bitrate to be 320Kbps,# then this parameter could be {'bitrate': '320k# wait: if set to True, wait till the playback ends# examplesloader.play_note('C5')# play a note C5 using current instrument# you will hear a note C5 playing using current instrumentloader<25# change to another instrument at preset number 25loader.play_note('C5')# play a note C5 using the instrument we have changed to# you will hear a note C5 playing using a new instrumentloader.play_note('D')# play a note without octave number specified, will play the note D4loader.play_note(sf.mp.N('C5'))# play a note using musicpy note structureloader.play_note('C5',duration=3)# play a note C5 for 3 secondsYou can useplay_chordfunction of the sf2 loader to play a chord using current channel, soundfont id, bank number and preset number. The chord must be a musicpy chord instance.loader.play_chord(current_chord,decay=0.5,channel=0,start_time=0,piece_start_time=0,sample_width=2,channels=2,frame_rate=44100,name=None,format='wav',bpm=80,fixed_decay=True,effects=None,pan=None,volume=None,length=None,extra_length=None,export_args={},wait=False)# current_chord: musicpy chord instance# decay: the decay time unit in seconds, each note's decay time will be calculated# with decay * duration of the note, or if fixed_decay is True, this decay time# will be applied to every note, this decay time could also be a list of each note's# decay time# channel - bpm: same as play_note# piece_start_time: this is used when dealing with a musicpy piece instance, you won't need to set this generally# fixed_decay: if this is set to True, the decay time will be applied to every note# effects: same as play_note# pan: the pan effects you want to add to the rendered audio# volume: the volume effects you want to add to the rendered audio# the pan and volume effects are corresponding to the MIDI CC messages# length: you can specify the whole length of the rendered audio in seconds (used in case of audio effects)# extra_length: you can specify the extra length of the rendered audio in seconds (used in case of audio effects)# export_args: same as play_note# wait: same as play_note# examplesloader.play_chord(sf.mp.C('C'))# play a C major chord starts at C4 (default when# no octave number is specified)loader.play_chord(sf.mp.C('Cmaj7',5))# play a Cmaj7 chord starts at C5You can useplay_piecefunction of the sf2 loader to play a piece using current channel and soundfont id. The piece must be a musicpy piece instance. Here piece means a piece of music with multiple individual tracks with different instruments on each of them (it is also ok if you want some or all of the tracks has the same instruments). You can custom which instrument you want the soundfont to play for each track by setting theinstrumentsattribute of the piece instance, instrument of a track of the piece instance could be preset or [preset, bank, (sfid)].You can learn more about piece data structurehereat musicpy wiki.loader.play_piece(current_chord,decay=0.5,sample_width=2,channels=2,frame_rate=44100,name=None,format='wav',fixed_decay=True,effects=None,clear_program_change=False,length=None,extra_length=None,track_lengths=None,track_extra_lengths=None,export_args={},show_msg=False,wait=False)# current_chord: musicpy piece instance# decay: the decay time for the tracks of the piece instance (which is musicpy chord# instance), note that if this decay time is a list,# then it will be treated as the decay time for each track separately,# otherwise it will be applied to each track. If you want to pass the same list# to each track, you need to pass a list of lists which elements are identical.# sample_width - effects: same as play_chord# clear_program_change: when there are program change messages in the piece instance,# the instruments are forced to change during rendering, so you cannot use the# instrument you want to play, if you clear these messages, then you can specify# which instruments you want to play# length: you can specify the whole length of the rendered audio in seconds (used in case of audio effects)# extra_length: you can specify the extra length of the rendered audio in seconds (used in case of audio effects)# track_lengths: the length settings list of each track# track_extra_lengths: the extra length settings list of each track# export_args: same as play_note# show_msg: if it is set to True, then when the sf2 loader is rendering a piece instance to audio, it will print some messages showing current process, such as `rendering track 1/16 ...` (rendering the first track of the total 16 tracks), the default value is False# wait: same as play_note# examples# construct a musicpy piece instance and play it using the sf2 loader,# here we have a chord progression from Cmaj7 to Fmaj7, with different instruments of each chordcurrent_piece=sf.mp.P(tracks=[# C function is to translate human-readable chord name to chordsf.mp.C('Cmaj7')%(1,1/8)*4,sf.mp.C('Fmaj7')%(1,1/8)*4,# The code below does exactly the same job# sf.mp.chord('C, E, G, B') % (1, 1 / 8) * 4,# sf.mp.chord('F, A, C, E') % (1, 1 / 8) * 4],instruments=[1,47],start_times=[0,2],bpm=150)loader.play_piece(current_piece)# read a MIDI file to a musicpy piece instance and play it using the sf2 loadercurrent_midi_file=sf.mp.read(midi_file_path)loader.play_piece(current_midi_file)You can useplay_midi_filefunction of the sf2 loader to play a MIDI file using current channel and soundfont id. You can set the first parameter to the MIDI file path, and then the sf2 loader will read the MIDI file and analyze it into a musicpy piece instance, and then render it to audio data.loader.play_midi_file(current_chord,decay=0.5,sample_width=2,channels=2,frame_rate=44100,name=None,format='wav',fixed_decay=True,effects=None,clear_program_change=False,instruments=None,length=None,extra_length=None,track_lengths=None,track_extra_lengths=None,export_args={},show_msg=False,wait=False,**read_args)# current_chord: the MIDI file path# decay - clear_program_change: same as play_piece# instruments: the list of the instruments you want to play, the sf2 loader# will use this instrument list instead of the instrument settings in the MIDI file,# note that this instruments list must be the same length as the number of tracks# of the MIDI file# length - show_msg: same as play_piece# wait: same as play_note# **read_args: this is the keyword arguments for the musicpy read function# examples# play a MIDI file given a file path using current soundfont fileloader.play_midi_file(r'C:\Users\Administrator\Desktop\test.mid')loader.change_soundfont('celeste2.sf2')# change to another loaded soundfont file# play a MIDI file given a file path using another soundfont fileloader.play_midi_file(r'C:\Users\Administrator\Desktop\test.mid')# you can also specify which channel use which soundfont files in the instruments# parameter by specifying the soundfont idYou can specify which bank and preset (including channel and sfid) that each track of the MIDI file uses by setting theinstrumentsparameter of theplay_midi_filefunction.Export notes, chords, pieces and MIDI filesYou can export notes, chords, pieces and MIDI files using loaded soundfont files in the sf2 loader usingexport_note,export_chord,export_piece,export_midi_filefunction of the sf2 loader.All of the parameters of these export functions can refer to their corresponding play functions, except a parameterget_audio, if this parameter is set to True, then the export functions will return an AudioSegment instance (this is an audio instance in pydub) which contains raw audio data for further audio process. If this parameter is set to False (which is default), then the export functions will export the rendered audio data to an audio file with the file name and the audio file format you specify.# examples# render a MIDI file with current soundfont files and export as a mp3 file 'test.mp3'loader.export_midi_file(r'C:\Users\Administrator\Desktop\test.mid',name='test.mp3',format='mp3')# if you want to specify the bitrate of the exported mp3 file to be 320Kbpsloader.export_midi_file(r'C:\Users\Administrator\Desktop\test.mid',name='test.mp3',format='mp3',export_args={'bitrate':'320k'})Export instrumentsYou can export instruments of a specified instrument of the loaded soundfont files usingexport_instrumentsfunction of the sf2 loader.You can specify the pitch range of the notes, the default is from A0 to C8, which is the most common 88 keys on the piano.The duration of the notes is 6 seconds by default, you can set the duration of the notes in the function.The format of the export audio files is wav by default, you can set the export audio file format in the function.The exported audio file name of each note will be in the formatpitch.formatby default, where pitch is the note name such asC5, format is the audio file format you specify such aswav, so for example, the exported audio file names of notes will be likeC5.wav,C#5.wav,D5.wav. You can custom the name format of each note with the parameternamein the function, it could either be a list of each note's name (without file extension) or a function to format each note's name (without file extension).loader.export_instruments(channel=None,sfid=None,bank=None,preset=None,start='A0',stop='C8',duration=6,decay=1,volume=127,sample_width=2,channels=2,frame_rate=44100,format='wav',folder_name='Untitled',effects=None,bpm=80,name=None,show_full_path=False,export_args={})# channel, sfid, bank, preset: use which instrument to play, you can refer to# change function# start, stop: the pitch range, note that these must be strings representing pitches# duration - format: refer to play_note function# folder_name: the folder name of the exported instruments# effects: refer to play_note function, will be applied to each note# bpm: refer to play_note function# name: if not None, then set each note's file name with this parameter,# this could be a list of each note's name (without file extension) or a function# to format each note's name (without file extension),# for example, ['C5', 'C#5' 'D5'], lambda s: f'piano{s}'# show_full_path: when this function is running, it will print the export messages# for each note, showing which soundfont file and which bank and preset# you use to export which note, if this is set to True,# then the file path of the soundfont file will be full path,# otherwise the file path will be only the file name# export_args: same as play_note# examples# export notes from A0 to C8 of current instrumentloader.export_instruments()# export notes from C5 to C6 of current instrumentloader.export_instruments(start='C5',stop='C6')# export notes from A0 to C8 of current instrument of# the loaded soundfont file with id 2# (or you can change current soundfont file in advance)loader.export_instruments(sfid=2)Audio effectsThere is aeffectsparameter in the play and export functions, but how to use it?This python package provides a classeffect, which could store a type of audio effect, such as reverse, offset, fade in, fade out, ADSR envelope, and you can customize your own audio effect functions. You can useeffectclass to package an audio effect function and put it as an element in a list, the list could be used as the value ofeffectsin the play and export functions. There are already some predefined effect instances such asreverse,fade,adsr.For more details and usages ofeffectclass, and the parameters of predefined audio effects, please refer to the daw module of musicpy, here is thelinkfor the documentation of the audio effects.effect(func,name=None,*args,unknown_args=None,**kwargs)# func: the function to process the audio effect, the first parameter must be a pydub AudioSegment instance, the other parameters could be customized as you like, the return value must be a pydub AudioSegment instance# name: the name of the audio effect# *args, **kwargs: the positional arguments and keyword arguments that the function to process the audio effect could receive# unknow_args: the keyword arguments that the function to process the audio effect could receive, but cannot be known when packaged (for example, the bpm in real time)# examples# play a note C5 using current instrument with a reverse audio effectloader.play_note('C5',effects=[reverse])# play a note C5 using current instrument with a fade in audio effect of 2sloader.play_note('C5',effects=[fade_in(duration=2000)])# export a note C5 using current instrument with a reverse audio effectloader.export_note('C5',effects=[reverse])Pause, unpause and stop current playing soundsWhen you start playing sounds, you can usepausefunction of sf2 loader to pause current playing,unpausefunction to unpause,stopfunction to stop.DonationThis project is developed by Rainbow Dreamer on his spare time. If you feel this project is useful to you and want to support it and it's future development, please consider buy me a coffee, I appreciate any amount.