arrow-left
Only this pageAll pages
gitbookPowered by GitBook
1 of 5

Developer Guide

Loading...

Loading...

Loading...

Loading...

Loading...

Music generation

Creating your own music generation engine

hashtag
Overview

JJazzLab framework → RhythmProvider → Rhythm → MusicGenerator → phrases → post-process

circle-check

The engine doesn’t have to care about real-time deadlines: JJazzLab handles scheduling and synchronization.

hashtag
RhythmProvider

Your engine must implement the interface with the @ServiceProvider annotation, so that the implementation can automatically find it upon startup. The used Netbeans mechanism is described (lookup).

Example: See for a simple RhythmProvider implementation example.

hashtag
Rhythm, RhythmVoices and RhythmParameters

The engine provides instances to the framework.

The Rhythm interface notably defines :

  • name, time signature, preferred tempo, feel, etc.

  • : the supported tracks (Drums, Bass, Piano, etc.). Each RhythmVoice defines the recommended Midi instrument and settings for the track.

  • : the "control knobs" given to the user to modulate music generation. Common rhythm parameters are Variation

circle-info

Rhythm instances are actually provided via RhythmInfo instances, which are used by the for its cache file. They represent what the user sees in the rhythm selection dialog.

hashtag
MusicGenerator

A Rhythm instance should implement the interface.

Actual music generation is performed by the provided instance. It receives a song context (chord leadsheet, song structure, tempo, etc.) and returns musical phrases (one per instrument) that form the backing track.

Example: See for a simple Rhythm implementation example.

Example: See for a simple MusicGenerator implementation example.

hashtag
Post-processing

After generation, the framework applies engine-independent post-processing to the returned phrases :

  • muting instruments in a song part

  • per-channel velocity shift

  • volume fade-out

  • tempo factor changes

The details of post-processing tasks performed by the framework are provided in the MusicGenerator interface comments.

,
Intensity
,
Mute
, etc. You see them in the Song Structure Editor, their value can be set for each Song Part. The framework provides default UI widget for each rhythm parameter type, but you can define your own UI widget if required.
  • etc.

  • RhythmProviderarrow-up-right
    RhythmDatabasearrow-up-right
    herearrow-up-right
    RhythmStubProviderImpl.javaarrow-up-right
    Rhythmarrow-up-right
    RhythmVoicesarrow-up-right
    RhythmParametersarrow-up-right
    RhythmDatabasearrow-up-right
    MusicGeneratorProviderarrow-up-right
    MusicGeneratorarrow-up-right
    RhythmStub.javaarrow-up-right
    DummyGenerator.javaarrow-up-right

    Architecture

    hashtag
    Overview

    hashtag
    Main NetBeans modules

    hashtag
    Core modules

    Model classes for the chord leadsheet

    Classes such as , , , , , , etc.

    Various utility classes, including classes to manage drum maps

    Model classes for the MidiMix (saved as .mix file). Controls the configuration of the output synth (bank select/program change, volume, panoramic, etc.) for a given song

    Classes to control music playback (start, pause, etc.)

    Model classes for a rhythm (style).

    Manage the available rhythm instances on the system

    Utility classes for music generation

    Model classes for a song (saved as .sng file). A song mainly contains a ChordLeadSheet, a SongStructure and optional user phrases.

    Model classes for a SongStructure

    hashtag
    App modules

    Manages the active song (JJazzLab can open several songs in parallel, but only the active one is allowed to send Midi data).

    The graphical editor for a object.

    The graphical editor for a object.

    The central place where all song editors are managed

    The graphical editor for a .

    The graphical editor for a object.

    hashtag
    Plugins modules

    Manages the internal FluidSynth-based synth.

    A rhythm music generation engine for practicing jazz standards with a natural feel

    A rhythm music generation engine with 2 Yamaha style-based rhythm providers

    ChordLeadSheetarrow-up-right
    Harmonyarrow-up-right
    Notearrow-up-right
    Degreearrow-up-right
    TimeSignaturearrow-up-right
    ChordSymbolarrow-up-right
    ChordTypearrow-up-right
    Scalearrow-up-right
    Midiarrow-up-right
    MidiMixarrow-up-right
    MusicControlarrow-up-right
    Rhythmarrow-up-right
    RhythmDatabasearrow-up-right
    RhythmMusicGenerationarrow-up-right
    Songarrow-up-right
    SongStructurearrow-up-right
    ActiveSongarrow-up-right
    CL_Editorarrow-up-right
    ChordLeadSheetarrow-up-right
    MixConsolearrow-up-right
    MidiMixarrow-up-right
    SongEditorManagerarrow-up-right
    SptEditorarrow-up-right
    SongPartarrow-up-right
    SS_Editorarrow-up-right
    SongStructurearrow-up-right
    FluidSynthEmbeddedSynth arrow-up-right
    JJSwing arrow-up-right
    YamJJazz arrow-up-right

    Developping with JJazzLab

    An open application for developers

    circle-info

    JJazzLab is written in Java. Why ?

    This choice reflects the project’s origins (started over 10 years ago, when Java was a common option for cross-platform desktop apps) and the nature of the problem: unlike a low-latency audio DAW, JJazzLab does not require hard real-time deadline management in the music generation engine. As a side note, modern Java is quite different from early versions and can deliver excellent performance.

    hashtag
    Updating the application

    hashtag
    Apache NetBeans Platform

    JJazzLab is based on the which provides a reliable and extensible architecture for cross-platform desktop applications.

    The NetBeans Platform manages the application lifecycle, window system, extension points, options, actions, and more.

    It uses NetBeans modules (different from java 9 JPMS modules) which group related Java classes into pluggable components, while managing visibility and dependencies between them.

    hashtag
    Adding new features

    Suppose you have a reharmonization algorithm that proposes alternate chord progressions (e.g., replacing | A7 | Dmaj7 | with | Em7 A7 | Dmaj7 |).

    You can easily implement an action that, when user selects chords, suggests these alternatives in the existing chord popup menu.

    Then your code can be bundled in a module which is deployed like a plugin.

    hashtag
    Develop your own rhythm generation engine without hassle

    Out of the box, JJazzLab provides the infrastructure (“plumbing”) that developers would otherwise need to build themselves: data management, user interface, MIDI management, playback control, music-generation control, etc.

    In JJazzLab, the rhythm generation engine just receives a context (chords, song structure, tempo, etc.) and returns musical phrases (one per instrument) that form the backing track, ready for playback.

    The engine doesn’t have to manage real-time deadline: JJazzLab handles scheduling and synchronization.

    hashtag
    JJazzLab Toolkit

    The is a standalone jar file which contains the JJazzLab core features, the JJazzLab plugins and the required dependencies.

    Use the toolkit to use JJazzLab features independently of the JJazzLab application.

    Build JJazzLab 5 from source code

    Requirements:

    • jdk-23 or higher

    • maven 3 or higher

    Tutorial (needs to be updated for 5.1)

    Creating your first JJazzLab Module! Some familiarity with Java and Maven is expected.

    JJazzLab is based on the . It provides a reliable and extensible architecture for desktop application which manages the application life cycle, the window system, extension points, options, actions, etc.

    Each distinct feature in a Netbeans Platform application can be provided by a distinct Netbeans module, which is comparable to a plugin. A Netbeans module is a group of Java classes that provides an application with a specific feature.

    Unless you want to fix the JJazzLab code itself, you will probably start by creating your own Netbeans module.

    hashtag

    git
    if you want to clone the repository (it can be downloaded as a ZIP file from github too).

    hashtag
    Preparation

    These steps are required for building JJazzlab, both from the command line or from Netbeans:

    • Clone the repository from https://github.com/jjazzboss/JJazzLabarrow-up-right (or download and extract the source files)

    • There is a file too big for git, you have to download it from https://archive.org/download/jjazz-lab-sound-font/JJazzLab-SoundFont.sf2arrow-up-right and move it to plugins/FluidSynthEmbeddedSynth/src/main/soundfont

    hashtag
    In Linux & MacOS, install fluidsynth package

    On both Linux and MacOS, you also need the native fluidsynth package. Check if it is installed with fluidsynth --version . If it's not yet there, install it with:

    • sudo apt-get install fluidsynth on Debian based distributions,

    • brew install fluidsynth for Homebrew users on MacOS,

    • for other Linux distributions and other MacOS installation options see https://github.com/FluidSynth/fluidsynth/wiki/Downloadarrow-up-right

    hashtag
    Build from the command line

    With the preparation done, you only need to execute the build and run the application:

    • In the project root, run mvn clean install

    • Go to app/application and run mvn nbm:cluster-app nbm:run-platform

    The application should open up, the output of the application will be visible in the terminal that launched the app.

    hashtag
    Build from Netbeas IDE

    Because JJazzlab uses Apache Netbeans Platform, Netbeans IDE is preferred for development. Follow these steps to build and run the application:

    • Go to File menu, Open project and point to the folder with JJazzlab source code

    • You will see a project named JJazzLab parent [master] , right click it and select build

    • Expand JJazzLab parent / modules using the > symbol on the left, and locate the module called JJazzLab App

    • Open that module by either double clicking on it or using right click and Open Project

    • Scroll up on the projects panel and locate JJazzLab App [master]

    • Right click the project name and use Run

    The application should open up, the output of the application will be visible in the output panel in the IDE.

    hashtag
    Troubleshooting

    If the instructions don't work as expected, consider creating an issue in github JJazzLab repositoryarrow-up-right or asking in jjazzlab forumsarrow-up-right.

    Apache Netbeans Platformarrow-up-right
    JJazzLab Toolkitarrow-up-right
    Create a Netbeans module
    circle-info

    In this example we want to add a new feature which proposes re-harmonized chord progressions. The reharmonization action will operate on the chord symbols selected by the user, and should be accessible via the chord symbol popup menu.

    Let's first create a new module to hold our code. In the Netbeans IDE, follow these steps:

    1. Open JJazzLab Parent and expand its contents

    2. Right click JJazzLab Parent / Modules and use Create New Module...

    3. Select Java with Maven as category and Netbeans Module as project

    4. Enter a name for the module, this guide uses "Reharmonize"

    5. Click next and finish in the next step

    You new module will appear in the JJazzLab modules list, but Netbeans will also open the module. If you expand all the module's contents you should have something like this:

    circle-info

    If the module did not open when created, go to JJazzLab Parent / Modules and locate the new module (it should be last) and either double click it, or right click and select Open Project .

    hashtag
    Create an action

    We want to create a "Reharmonize" action which should be callable from the chord symbol popup menu, and should operate on the chord symbols currently selected.

    The best way to start is to look for a similar action and copy the code. Actions classes are mainly found in the following modules:

    • CL_Editorarrow-up-right module : Chord Leadsheet editor actions such as insert bar, transpose chord symbols, etc

    • SS_Editor arrow-up-rightmodule : Song Structure editor actions such as delete song part, change rhythm, etc

    • MixConsole arrow-up-rightmodule : save default rhythm mix, mute all, etc

    • module: play, stop, etc

    • module: new song, open song, duplicate song, etc

    The chord leadsheet editor action TransposeDownarrow-up-right is enabled when user has selected one or more chord symbols, which makes it perfect to base our code on. Let's reuse it in our module:

    1. Open the CL_EditorImpl module, navigate to Source Packages > org.jjazz.cl_editorimpl.actions and copy TransposeDown.java (copy the file in the projects panel, not its contents!)

    2. Open the Reharmonize module, select the org.myself.reharmonize package, and choose Paste > Refactor Copy... (Ctrl+V triggers Refactor Copy in Netbeans)

    3. A dialog appears, set the new name to Reharmonize and press Refactor

    The new Reharmonize class will be created in the module, but it will show many errors due to missing dependencies.

    There are several ways of fixing the dependencies, for brevity let's just copy the ones from CL_EditorImpl:

    1. Go to Reharmonize > Project Files, open the pom.xml file and delete the whole <dependencies> element

    2. Go to CL_EditorImpl > Project Files, open the pom.xml file and copy the entire <dependencies> element

    3. Switch back to the pom.xml from the Reharmonize module, paste the <dependencies> element after the <build> element and save the file

    Open the Reharmonize class again or switch back to that tab in the editor. The errors in the import statements should be gone now! Not all problems are solved yet though...

    hashtag
    Action annotations

    Now you should have only one error in the file:

    Netbeans uses annotations to facilitate action declaration. There are separate annotations to regulate different aspects of how the action will integrate with the application:

    • @ActionIDarrow-up-right is used to identify the action, its required properties category & id are used to locate this action from other modules (e.g. see Actions#forIDarrow-up-right)

    • @ActionRegistrationarrow-up-right registers the action, making it available to other modules. The displayName property determines the text this action will show in the UI. If that name starts with a # symbolit means the actual text will be obtained from a Bundle.properties localization file instead

    • puts a reference to this action in the Netbeans virtual file system (created at runtime), in the Actions/ChordSymbol directory. When user right clicks a chord symbol, JJazzLab uses all action references in that directory to create the related menu entries, using the position value to order them

    circle-info

    Check the Netbeans Platform online documentationarrow-up-right for more information

    You only need a few changes to correctly show the action, most of them in the Java code. A few changes are also required in other files.

    The necessary changes for Reharmonize.java are:

    1. In the @ActionID declaration, replace the id by org.myself.reharmonize (or a string of your choice)

    2. In the @ActionRegistration, change the displayName to #CTL_TransposeDown

    3. There should be a use of the String literal "CTL_TransposeDown", as a parameter to ResUtil#getStringarrow-up-right. Change it to "CTL_TransposeDown" (notice there's no # at the start for this use)

    4. In @ActionReference, change the value of position from 410 to 415, this way the new action will appear in the popup menu after the TransposeDown action.

    A couple of changes are needed in other files:

    1. Edit Reharmonize > Other Sources > src/main/resources > org.jjazzlab.reharmonize > Bundle.properties by adding a line with CTL_Reharmonize=Reharmonize chord progression

    2. Open JJazzLab App > Project Files > pom.xml and add a dependency on the new module. Go to the end of the <dependencies> and add:

    You should be able to build the new module. Right click the Reharmonize module then Build from the popup menu. Run JJazzLab by right clicking JJazzLab App and selecting Run from the menu.

    JJazzLab will open, running with the new module. In any song (open one or create a new one), select a chord symbol and show the popup menu: our action should be there, as shown below. If you select it it will transpose down the chords symbols, as we have not yet changed the action code itself.

    hashtag
    Action code

    The two important methods for this guide are:

    • selectionChange() which is called each time selection has changed (e.g. user has selected or unselected bars/chord symbols/sections) with a selection context parameter. This is used to enable or disable the action depending on the selection

    • actionPerformed(), which performs the action. This can be triggered in several ways

    The automatic selection change mechanism in the active Chord leadsheet editor is provided by the CL_ContextActionSupport helper class. This mechanism is based on the powerful Netbeans global Lookup mechanism, which is a out of scope of this tutorial.

    circle-info

    For more information on the Lookup Mechanism, see this DZone article arrow-up-rightrecommended in the Netbeans Platform documentation

    Below is a sketch of a possible Reharmonize action implementation. If you are a music enthusiast, you probably know reharmonization is a complex topic, the strategy used in this code is a risky one: replace the selected chords by randomly generated chords!

    Although there is a non-zero chance of this code offering a good reharmonization, the strategy is not recommended at all! A proper implementation is outside the scope of this tutorial.

    circle-check

    As previously, you can right click > Build the new module, then right click > Run on JJazzLab App. Select multiple chords, use Reharmonize chord progression and see what you get!

    Now you know:

    • How to create a new module and add it to JJazzLab

    • How to add new actions (and where to look for examples of existing actions)

    circle-info

    For more information on other internals of JJazzLab development, see the API documentation

    Apache Netbeans Platformarrow-up-right
    <!-- Custom plugins ================================================ -->
    <dependency> 
        <groupId>org.jjazzlab.customplugins</groupId> 
        <artifactId>reharmonize</artifactId> 
        <version>${project.version}</version> 
    </dependency>
    @Override
    public void selectionChange(CL_SelectionUtilities selection)
    {
        // Action is enabled if at least 2 chord symbols are selected
        setEnabled(selection.getSelectedChordSymbols().size() >= 2);
    }
    
    @Override
    public void actionPerformed(ActionEvent e)
    {
        // Get current selection context: at least 2 chord symbols because of our selectionChange() implementation
        CL_SelectionUtilities selection = cap.getSelection();
    
        // Compute a possible reharmonization
        List<CLI_ChordSymbol> newChordSymbols = getReharmonizedChordSymbols(selection.getSelectedChordSymbols());
    
        // Start an undoable action which will collect the individual undoable edits
        ChordLeadSheet cls = selection.getChordLeadSheet();
        JJazzUndoManagerFinder.getDefault().get(cls).startCEdit(undoText);
    
        // Remove existing chord symbols
        selection.getSelectedChordSymbols().forEach(cliCs -> cls.removeItem(cliCs));
    
        // Add the new chord symbols to replace the old ones
        newChordSymbols.forEach(newCliCs -> cls.addItem(newCliCs));
    
        // End the undoable action: action can now be undone by user via the undo/redo UI
        JJazzUndoManagerFinder.getDefault().get(cls).endCEdit(undoText);         
    }
    
    List<CLI_ChordSymbol> getReharmonizedChordSymbols(List<CLI_ChordSymbol> selectedChords)
    {
        CLI_Factory cliFactory = CLI_Factory.getDefault();
    
        return selectedChords.stream()
            .map(cliCs -> cliFactory.createChordSymbol(
                ExtChordSymbol.createRandomChordSymbol(), cliCs.getPosition()
            )).collect(Collectors.toList());
    }
    MusicControlActions arrow-up-right
    SongEditorManager arrow-up-right
    @ActionReferencearrow-up-right