Only this pageAll pages
Powered by GitBook
1 of 7

Developer Guide

Loading...

Loading...

Loading...

Loading...

API

Loading...

Loading...

Build 4.1.2 from source code

Building from the source code is easy, but there are a few specific requirements at the moment:

  • jdk-17 is required *

  • maven 3 or higher

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

Maven is been used since version 4, previous versions used Ant.

(*) JJazzlab 4.1.2 needs jdk-17 because the FluidSynth integration depends on JEP 419 Foreign Function & Memory API which was in the incubator state.

Preparation

These steps are required for building JJazzlab, both from the command line or from Netbeans. Follow these steps to prepare for the build:

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

  • Change the value of the property `jjazzlab.surefire.skipTests` in the pom.xml in the root folder of the project to true **

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

(**) This is due to a known problem in master, it should get fixed before the next release.

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/Download

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.

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.

Troubleshooting

If the instructions don't work as expected, consider creating an issue in github JJazzLab repository or asking in jjazzlab forums.

Add a rhythm engine

Architecture

The main APIs you'll be using are found in the Rhythm and RhythmMusicGeneration modules:

  • RhythmProvider

    Give JJazzLab access to one or more Rhythm objects provided by your engine

  • Rhythm

    The main interface which provides descriptive information about the rhythm, with its RhythmVoices, and RhythmParameters.

  • MusicGenerator A Rhythm implementation should also implement the MusicGenerator interface to be able to generate music

  • RhythmVoice

    There is one RhythmVoice for each track generated by your rhythm, e.g. "Drums", "Bass", "Piano"

  • RhythmParameter

    The parameters to modulate the rhythm, e.g. "Complexity" or "Fill"

Create your code

You should first create your own Netbeans module, as explained in the Getting started page.

Your engine must be recognized by the JJazzLab framework, so that it can be accessible to the end-user. For this you'll need to start by adding a RhythmProvider implementation, as explained below.

Main interfaces

RhythmProvider

The RhythmProvider interface is defined in the Rhythm module.

Your implementation must use the @ServiceProvider annotation so that the RhythmDatabase instance can automatically find it upon startup. The general Netbeans mechanism used is described here.

When user needs to pick up a rhythm, the rhythm selection dialog asks the RhythmDatabase to provide the available RhythmProvider instances (e.g. "Yamaha style based generator") and their list of rhythms (e.g. "jazz", "pop", ...).

The RhythmProvider implementation is responsible to provide:

  • An Info object (name, description, author, version, uniqueId)

  • The list of built-in Rhythm objects provided by this implementation

  • The list of file-based Rhythm objects provided by this implementation

  • An optional settings dialog to tune the rhythm generation engine

Example: See RhythmStubProviderImpl.java for a simple RhythmProvider implementation example.

Rhythm

A Rhythm interface describes... a rhythm !

  • name, for example "samba-fast"

  • description

  • time signature

  • preferred tempo

  • feel : ternary/binary

  • etc...

It also defines the RhythmVoices, RhythmParameters.

The Rhythm implementation must also implement the MusicGenerator interface to be able to generate music.

Example: See RhythmStub.java for a very simple Rhythm implementation example.

RhythmVoice

There is one RhythmVoice for each track generated by this rhythm, e.g. "Drums", "Bass", "Piano". The RhythmVoice provides the recommended Midi instrument and settings for the track.

The RhythmVoices information is used for example by the Mix Console to display the relevant tracks.

RhythmParameter

Examples of RhythmParameters are "Variation", "Fill", or "Complexity".

The RhythmParameters are the control knobs given to the user so he can modulate the rhythm for each song part. You see them in the Song Structure Editor, for each Song Part.

There are ready-to-use classes to quickly define your RhythmParameters depending on their type (a boolean value, one value amongst a set of values, etc). When these classes are used the framework will automatically show the relevant UI widget in the Song Structure Editor. You can also define your own UI widgets if you prefer.

MusicGenerator

This is an interface which indicates the capability to generate rhythm music. It has just a single method which takes the music generation context as a parameter, and returns the musical phrases (one per track) that make the backing track.

When user presses the Play button for a given song, JJazzLab will:

  • prepare the SongContext (e.g. mainly a Song object which contains a ChordLeadSheet and a SongStructure),

  • If Rhythm implements the MusicGenerator interface, pass it the context data and ask it to generate the backing track,

  • wait until the MusicGenerator has finished the music generation,

  • convert the received music data into a Midi sequence,

  • play the sequence.

So the MusicGenerator is really where the heavy stuff will be done by your engine. There is no synchronization constraint since JJazzLab will simply block until music generation is complete.

Note that you can use any technology to perform the generation, including non-Java ones. Only the lightweight API that connects to JJazzLab needs to be in Java.

Example: See DummyGenerator.java for a very simple MusicGenerator implementation example.

JJazzLab

JJazzLab is a Midi-based application dedicated to backing tracks generation.

The ultimate objective is to develop a jam buddy able to quickly generate intelligent and interesting backing tracks: realistic and non-boring backing tracks which you can easily adjust to specific songs.

Architecture

JJazzLab has a rather well-commented source code: don't hesitate to browse the GitHub repository or the Javadoc API.

Develop your own rhythm generation engine without hassle

Thanks to JJazzLab developers can save a huge amount of work by only focusing on their music generation engine. Out of the box, the JJazzLab framework provides all the infrastructure, all the “plumbing” that, before, every developer had to write themselves.

JJazzLab can host any number of music generation engines as plugins. What happens when you load a song file and press the Play button?

  1. The framework shows the song in the editors

  2. The framework sends Midi messages to initialize the connected Midi sound device

  3. When user press Play, the framework sends the song data to the music generation engine

  4. The music engine uses the song data to generate the Midi data for the backing tracks

  5. The framework retrieves the Midi data and plays it

Easily add new features

JJazzLab is based on the Apache Netbeans Platform. It provides a reliable and extensible application architecture.

The Netbeans Platform turns JJazzLab into a pluggable application where plugins can be installed or deactivated at runtime. Plugins can easily add or alter features and the related UI elements such as menu items.

For example suppose that you work on reharmonization algorithms (e.g. replace | A7 | D7M | by | Em7 A7 | D7M). It's easy to add a feature which propose possible reharmonizations when user selects multiple chord symbols. You'll just create a new action class which implements the algorithm on the current chord symbols selection, and "connect" (via annotations, no code required) this action to a new menu item in the Chord Symbol popup menu, as explained in the Getting started page.

Main modules

JJazzLab relies on the Netbeans Platform which provides a modular infrastructure. You'll find below the most important modules of JJazzLab.

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

ChordLeadSheet The model for the chord leadsheet: it defines a number of bars and a list of ChordLeadSheetItem : CLI_ChordSymbol (chord symbol at a given position) and CLI_Section (section name and time signatue at a given bar).

CL_Editor The graphical editor for a ChordLeadSheet object.

Harmony All the harmony related base classes, Note, Degree, TimeSignature, ChordSymbol, ChordType, Scale, etc.

Midi General Midi related classes.

MidiMix The model to store a set of instruments and settings (e.g. which Midi bank/program change for the piano voice, which volume, reverb, transposition, etc.). Also contains the MidiMixManager which associates a MidiMix to a song object.

MixConsole The graphical editor for a MidiMix object.

MusicControl Control the music playback (start, pause, etc.), which includes the launch of the backing track generation process.

Rhythm The model for a rhythm (a style). Also define the RhythmProvider interface which should be implemented by third-party rhythm generation engines.

RhythmDatabase Manage the available rhythms on the system. Upon startup the RhythmDatabase scans the available RhythmProvider implementations which provide the rhythm instances.

RhythmMusicGeneration Utility classes for music generation. Defines the MusicGenerator service provider interface.

Song The model for a song. A song mainly contains a chord leadsheet and a song structure.

SongEditorManager The central place where all song editors are created (from scratch, loaded from file, etc.) and managed.

SongStructure The model for a song structure: a list of SongParts. A SongPart defines a parent CLI_Section (see ChordLeadsheet model), a rhythm, and the value of each of the rhythm parameters.

SptEditor The graphical editor for a SongPart.

SS_Editor The graphical editor for a SongStructure object.

Getting started

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

JJazzLab is based on the Apache Netbeans Platform. 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.

Create a Netbeans module

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:

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 .

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_Editor module : Chord Leadsheet editor actions such as insert bar, transpose chord symbols, etc

  • SS_Editor module : Song Structure editor actions such as delete song part, change rhythm, etc

  • MixConsole module : save default rhythm mix, mute all, etc

  • MusicControlActions module: play, stop, etc

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

The chord leadsheet editor action TransposeDown 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...

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:

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

  • @ActionRegistration 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

  • @ActionReference 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

Check the Netbeans Platform online documentation 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#getString. 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:

<!-- Custom plugins ================================================ -->
<dependency> 
    <groupId>org.jjazzlab.customplugins</groupId> 
    <artifactId>reharmonize</artifactId> 
    <version>${project.version}</version> 
</dependency>

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.

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.

For more information on the Lookup Mechanism, see this DZone article recommended 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!

@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());
}

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.

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)

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

Data model

Song

The Song object is the main data model. It is mainly composed of a ChordLeadSheet and a SongStructure.

The ChordLeadSheet object is the model of the Chord leadsheet editor. It holds the sections and the chord symbols.

The SongStructure object is the model of the Song structure editor. It holds the SongParts, each one being linked to a parent section, and each one defining a set of RhythmParameter values.

Combining the SongStructure and the ChordLeadSheet will give you the "unrolled" chord lead sheet for which the backing track must be generated.

MidiMix

The MidiMix stores the Midi configuration of a given Song. It is mainly used by the framework to control the Midi output device. Your MusicGenerator will use it only to retrieve the Midi channel associated to a Rhythm track (RhythmVoice).

Helper classes

Harmony module

Supporting classes used in the Song: TimeSignature, ChordSymbol, Degree, etc.

Phrases and RhythmMusicGeneration modules

Supporting classes useful for your MusicGenerator:

  • Phrase and NoteEvent: the MusicGenerator needs to create a Phrase for each rhythm track.

  • SongChordSequence: a helper class to get the "unrolled" chord leadsheet described above.

  • Grid: music phrase manipulation methods

  • Phrases: music phrase manipulation methods, including methods to adapt a music source phrase (e.g. a bass pattern for C7M) into a different chord (e.g. Ab-6)

  • etc.