Search code examples
jfugue

How to transform pattern in jFugue 5.0?


In jFugue 4.0 there's a nice function: Transforming Patterns with PatternTransformer

but all pattern transformers are removed in jFugue 5.0. I understand it must be replaced with something cool. but what to do in jFugue 5.0 please? i get no clue. I googled but have so far had no outcome.


Solution

  • The class "PatternTransformer" has gone, but transforming patterns has never been easier!

    In older versions of JFugue, there was actually very little difference between a PatternTransformer and a ParserListener. Older versions of JFugue also referred to a PatternTool, which was like a Transformer but instead of transforming a pattern, it would just measure it; for example, you could write a tool to tell you what instruments were used in a piece.

    To transform a Pattern in JFugue, just create a class that implements ParserListener (or extends ParserListenerAdapter), and add it as a listener to a parser - such as a StaccatoParser:

    For example, here's a tool that finds what instruments are used in a piece:

    public class InstrumentTool extends ParserListenerAdapter 
    {
        private List<String> instrumentNames;
    
        public InstrumentTool() {
            super();
            instrumentNames = new ArrayList<String>();
        }
    
        @Override
        public void onInstrumentParsed(byte instrument) {
            String instrumentName = MidiDictionary.INSTRUMENT_BYTE_TO_STRING.get(instrument);
            if (!instrumentNames.contains(instrumentName)) {
                instrumentNames.add(instrumentName);
            }
    
        }
    
        public List<String> getInstrumentNames() {
            return this.instrumentNames;
        }
    }
    

    and here's how to use it:

    MidiParser midiParser = new MidiParser();
    InstrumentTool instrumentTool = new InstrumentTool();
    midiParser.addParserListener(instrumentTool);
    midiParser.parse(MidiSystem.getSequence(new File("filename")));
    List<String> instrumentNames = instrumentTool.getInstrumentNames();
    for (String name : instrumentNames) {
        System.out.println(name);
    }
    

    There's a new class in JFugue 5 that lets you chain ParserListeners together. This would let you create a chain of listeners that each modify a pattern before sending events to the next listener in the chain. For example, suppose you have a pattern, and you want to transform all of the instruments (say, change GUITAR to PIANO); then you want to take any note played with PIANO and stretch its duration by two; then you want to take any note with a new duration greater than 2.0 (two whole notes) and you want to change its octave. A bit of a crazy example, but it shows the need for a "chaining" series of parser listeners.

    Here's a demo example that uses chaining. This class reads a MIDI pattern; it then changes all of the instruments, and then it creates a Staccato pattern from the original MIDI.

    public class ChainingParserListenerDemo {
        public static void main(String[] args) throws InvalidMidiDataException, IOException {
            MidiParser parser = new MidiParser();
            InstrumentChangingParserListener instrumentChanger = new InstrumentChangingParserListener();
            StaccatoParserListener staccatoListener = new StaccatoParserListener();
            instrumentChanger.addParserListener(staccatoListener);
            parser.addParserListener(instrumentChanger);
            parser.parse(MidiSystem.getSequence(new File("filename")));
            System.out.println("Changed "+instrumentChanger.counter+" Piano's to Guitar! "+ staccatoListener.getPattern().toString());
        }
    }
    
    class InstrumentChangingParserListener extends ChainingParserListenerAdapter {
        int counter = 0;
    
        @Override 
        public void onInstrumentParsed(byte instrument) {
            if (instrument == MidiDictionary.INSTRUMENT_STRING_TO_BYTE.get("PIANO")) {
                instrument = MidiDictionary.INSTRUMENT_STRING_TO_BYTE.get("GUITAR");
                counter++;
            }
            super.onInstrumentParsed(instrument);
        }
    }