Source for gnu.javax.sound.midi.dssi.DSSISynthesizer

   1: /* DSSISynthesizer.java -- DSSI Synthesizer Provider
   2:    Copyright (C) 2005, 2006, 2012 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.javax.sound.midi.dssi;
  40: 
  41: import java.util.ArrayList;
  42: import java.util.Iterator;
  43: import java.util.List;
  44: 
  45: import javax.sound.midi.Instrument;
  46: import javax.sound.midi.MidiChannel;
  47: import javax.sound.midi.MidiMessage;
  48: import javax.sound.midi.MidiUnavailableException;
  49: import javax.sound.midi.Patch;
  50: import javax.sound.midi.Receiver;
  51: import javax.sound.midi.ShortMessage;
  52: import javax.sound.midi.Soundbank;
  53: import javax.sound.midi.SoundbankResource;
  54: import javax.sound.midi.Synthesizer;
  55: import javax.sound.midi.Transmitter;
  56: import javax.sound.midi.VoiceStatus;
  57: 
  58: /**
  59:  * DSSI soft-synth support.
  60:  *
  61:  * All DSSI soft-synths are expected to be installed in /usr/lib/dssi.
  62:  *
  63:  * @author Anthony Green (green@redhat.com)
  64:  *
  65:  */
  66: public class DSSISynthesizer implements Synthesizer
  67: {
  68:   /**
  69:    * The DSSI Instrument class.
  70:    *
  71:    * @author Anthony Green (green@redhat.com)
  72:    *
  73:    */
  74:   class DSSIInstrument extends Instrument
  75:   {
  76:     DSSIInstrument (Soundbank soundbank, Patch patch, String name)
  77:     {
  78:       super (soundbank, patch, name, null);
  79:     }
  80: 
  81:     /* @see javax.sound.midi.SoundbankResource#getData()
  82:      */
  83:     public Object getData()
  84:     {
  85:       return null;
  86:     }
  87: 
  88:   }
  89: 
  90: /**
  91:    * DSSISoundbank holds all instruments.
  92:    *
  93:    * @author Anthony Green (green@redhat.com)
  94:    *
  95:    */
  96:   class DSSISoundbank implements Soundbank
  97:   {
  98:     private String name;
  99:     private String description;
 100:     private List<Instrument> instruments = new ArrayList<Instrument>();
 101:     private List<SoundbankResource> resources = new ArrayList<SoundbankResource>();
 102:     private String vendor;
 103:     private String version;
 104: 
 105:     public DSSISoundbank(String name, String description, String vendor, String version)
 106:     {
 107:       this.name = name;
 108:       this.description = description;
 109:       this.vendor = vendor;
 110:       this.version = version;
 111:     }
 112: 
 113:     void add(Instrument instrument)
 114:     {
 115:       instruments.add(instrument);
 116:     }
 117: 
 118:     /* @see javax.sound.midi.Soundbank#getName()
 119:      */
 120:     public String getName()
 121:     {
 122:       return name;
 123:     }
 124: 
 125:     /* @see javax.sound.midi.Soundbank#getVersion()
 126:      */
 127:     public String getVersion()
 128:     {
 129:       return version;
 130:     }
 131: 
 132:     /* @see javax.sound.midi.Soundbank#getVendor()
 133:      */
 134:     public String getVendor()
 135:     {
 136:       return vendor;
 137:     }
 138: 
 139:     /* @see javax.sound.midi.Soundbank#getDescription()
 140:      */
 141:     public String getDescription()
 142:     {
 143:       return description;
 144:     }
 145: 
 146:     /* @see javax.sound.midi.Soundbank#getResources()
 147:      */
 148:     public SoundbankResource[] getResources()
 149:     {
 150:       return resources.toArray(new SoundbankResource[resources.size()]);
 151:     }
 152: 
 153:     /* @see javax.sound.midi.Soundbank#getInstruments()
 154:      */
 155:     public Instrument[] getInstruments()
 156:     {
 157:       return instruments.toArray(new Instrument[instruments.size()]);
 158:     }
 159: 
 160:     /* @see javax.sound.midi.Soundbank#getInstrument(javax.sound.midi.Patch)
 161:      */
 162:     public Instrument getInstrument(Patch patch)
 163:     {
 164:       Iterator<Instrument> itr = instruments.iterator();
 165: 
 166:       while (itr.hasNext())
 167:       {
 168:         Instrument i = itr.next();
 169:         if (i.getPatch().equals(patch))
 170:           return i;
 171:       }
 172: 
 173:       return null;
 174:     }
 175:   }
 176: 
 177: /**
 178:    * The Receiver class receives all MIDI messages from a connected
 179:    * Transmitter.
 180:    *
 181:    * @author Anthony Green (green@redhat.com)
 182:    *
 183:    */
 184:   class DSSIReceiver implements Receiver
 185:   {
 186:     /* (non-Javadoc)
 187:      * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long)
 188:      */
 189:     public void send(MidiMessage message, long timeStamp)
 190:         throws IllegalStateException
 191:     {
 192:       if (message instanceof ShortMessage)
 193:       {
 194:         ShortMessage smessage = (ShortMessage) message;
 195: 
 196:         switch (message.getStatus())
 197:         {
 198:         case ShortMessage.NOTE_ON:
 199:           int velocity = smessage.getData2();
 200:           if (velocity > 0)
 201:             channels[smessage.getChannel()].noteOn(smessage.getData1(),
 202:                                                    smessage.getData2());
 203:           else
 204:             channels[smessage.getChannel()].noteOff(smessage.getData1());
 205:           break;
 206:         case ShortMessage.CONTROL_CHANGE:
 207:           channels[smessage.getChannel()].controlChange(smessage.getData1(),
 208:                                                         smessage.getData2());
 209:           break;
 210:         default:
 211:           System.out.println ("Unhandled message: " + message.getStatus());
 212:           break;
 213:         }
 214:       }
 215:     }
 216: 
 217:     /* (non-Javadoc)
 218:      * @see javax.sound.midi.Receiver#close()
 219:      */
 220:     public void close()
 221:     {
 222:       // TODO Auto-generated method stub
 223:     }
 224: 
 225:   }
 226: 
 227:   static native void noteOn_(long handle, int channel, int noteNumber, int velocity);
 228:   static native void noteOff_(long handle, int channel, int noteNumber, int velocity);
 229:   static native void setPolyPressure_(long handle, int channel, int noteNumber, int pressure);
 230:   static native int getPolyPressure_(long handle, int channel, int noteNumber);
 231:   static native void controlChange_(long handle, int channel, int control, int value);
 232:   static native void open_(long handle);
 233:   static native void close_(long handle);
 234:   static native String getProgramName_(long handle, int index);
 235:   static native int getProgramBank_(long handle, int index);
 236:   static native int getProgramProgram_(long handle, int index);
 237:   static native void selectProgram_(long handle, int bank, int program);
 238: 
 239:   /**
 240:    * @author Anthony Green (green@redhat.com)
 241:    *
 242:    */
 243:   public class DSSIMidiChannel implements MidiChannel
 244:   {
 245:     int channel = 0;
 246: 
 247:     /**
 248:      * Default contructor.
 249:      */
 250:     public DSSIMidiChannel(int channel)
 251:     {
 252:       super();
 253:       this.channel = channel;
 254:     }
 255: 
 256:     /* (non-Javadoc)
 257:      * @see javax.sound.midi.MidiChannel#noteOn(int, int)
 258:      */
 259:     public void noteOn(int noteNumber, int velocity)
 260:     {
 261:       noteOn_(sohandle, channel, noteNumber, velocity);
 262:     }
 263: 
 264:     /* (non-Javadoc)
 265:      * @see javax.sound.midi.MidiChannel#noteOff(int, int)
 266:      */
 267:     public void noteOff(int noteNumber, int velocity)
 268:     {
 269:       noteOff_(sohandle, channel, noteNumber, velocity);
 270:     }
 271: 
 272:     /* (non-Javadoc)
 273:      * @see javax.sound.midi.MidiChannel#noteOff(int)
 274:      */
 275:     public void noteOff(int noteNumber)
 276:     {
 277:       noteOff_(sohandle, channel, noteNumber, -1);
 278:     }
 279: 
 280:     /* (non-Javadoc)
 281:      * @see javax.sound.midi.MidiChannel#setPolyPressure(int, int)
 282:      */
 283:     public void setPolyPressure(int noteNumber, int pressure)
 284:     {
 285:       setPolyPressure_(sohandle, channel, noteNumber, pressure);
 286:     }
 287: 
 288:     /* (non-Javadoc)
 289:      * @see javax.sound.midi.MidiChannel#getPolyPressure(int)
 290:      */
 291:     public int getPolyPressure(int noteNumber)
 292:     {
 293:       return getPolyPressure_(sohandle, channel, noteNumber);
 294:     }
 295: 
 296:     /* (non-Javadoc)
 297:      * @see javax.sound.midi.MidiChannel#setChannelPressure(int)
 298:      */
 299:     public void setChannelPressure(int pressure)
 300:     {
 301:       // TODO Auto-generated method stub
 302: 
 303:     }
 304: 
 305:     /* (non-Javadoc)
 306:      * @see javax.sound.midi.MidiChannel#getChannelPressure()
 307:      */
 308:     public int getChannelPressure()
 309:     {
 310:       // TODO Auto-generated method stub
 311:       return 0;
 312:     }
 313: 
 314:     /* @see javax.sound.midi.MidiChannel#controlChange(int, int)  */
 315:     public void controlChange(int controller, int value)
 316:     {
 317:       controlChange_(sohandle, channel, controller, value);
 318:     }
 319: 
 320:     /* (non-Javadoc)
 321:      * @see javax.sound.midi.MidiChannel#getController(int)
 322:      */
 323:     public int getController(int controller)
 324:     {
 325:       // TODO Auto-generated method stub
 326:       return 0;
 327:     }
 328: 
 329:     /* (non-Javadoc)
 330:      * @see javax.sound.midi.MidiChannel#programChange(int)
 331:      */
 332:     public void programChange(int program)
 333:     {
 334:       // TODO Auto-generated method stub
 335: 
 336:     }
 337: 
 338:     /* (non-Javadoc)
 339:      * @see javax.sound.midi.MidiChannel#programChange(int, int)
 340:      */
 341:     public void programChange(int bank, int program)
 342:     {
 343:       // TODO Auto-generated method stub
 344: 
 345:     }
 346: 
 347:     /* (non-Javadoc)
 348:      * @see javax.sound.midi.MidiChannel#getProgram()
 349:      */
 350:     public int getProgram()
 351:     {
 352:       // TODO Auto-generated method stub
 353:       return 0;
 354:     }
 355: 
 356:     /* (non-Javadoc)
 357:      * @see javax.sound.midi.MidiChannel#setPitchBend(int)
 358:      */
 359:     public void setPitchBend(int bend)
 360:     {
 361:       // TODO Auto-generated method stub
 362: 
 363:     }
 364: 
 365:     /* (non-Javadoc)
 366:      * @see javax.sound.midi.MidiChannel#getPitchBend()
 367:      */
 368:     public int getPitchBend()
 369:     {
 370:       // TODO Auto-generated method stub
 371:       return 0;
 372:     }
 373: 
 374:     /* (non-Javadoc)
 375:      * @see javax.sound.midi.MidiChannel#resetAllControllers()
 376:      */
 377:     public void resetAllControllers()
 378:     {
 379:       // TODO Auto-generated method stub
 380: 
 381:     }
 382: 
 383:     /* (non-Javadoc)
 384:      * @see javax.sound.midi.MidiChannel#allNotesOff()
 385:      */
 386:     public void allNotesOff()
 387:     {
 388:       // TODO Auto-generated method stub
 389: 
 390:     }
 391: 
 392:     /* (non-Javadoc)
 393:      * @see javax.sound.midi.MidiChannel#allSoundOff()
 394:      */
 395:     public void allSoundOff()
 396:     {
 397:       // TODO Auto-generated method stub
 398: 
 399:     }
 400: 
 401:     /* (non-Javadoc)
 402:      * @see javax.sound.midi.MidiChannel#localControl(boolean)
 403:      */
 404:     public boolean localControl(boolean on)
 405:     {
 406:       // TODO Auto-generated method stub
 407:       return false;
 408:     }
 409: 
 410:     /* (non-Javadoc)
 411:      * @see javax.sound.midi.MidiChannel#setMono(boolean)
 412:      */
 413:     public void setMono(boolean on)
 414:     {
 415:       // TODO Auto-generated method stub
 416: 
 417:     }
 418: 
 419:     /* (non-Javadoc)
 420:      * @see javax.sound.midi.MidiChannel#getMono()
 421:      */
 422:     public boolean getMono()
 423:     {
 424:       // TODO Auto-generated method stub
 425:       return false;
 426:     }
 427: 
 428:     /* (non-Javadoc)
 429:      * @see javax.sound.midi.MidiChannel#setOmni(boolean)
 430:      */
 431:     public void setOmni(boolean on)
 432:     {
 433:       // TODO Auto-generated method stub
 434: 
 435:     }
 436: 
 437:     /* (non-Javadoc)
 438:      * @see javax.sound.midi.MidiChannel#getOmni()
 439:      */
 440:     public boolean getOmni()
 441:     {
 442:       // TODO Auto-generated method stub
 443:       return false;
 444:     }
 445: 
 446:     /* (non-Javadoc)
 447:      * @see javax.sound.midi.MidiChannel#setMute(boolean)
 448:      */
 449:     public void setMute(boolean mute)
 450:     {
 451:       // TODO Auto-generated method stub
 452: 
 453:     }
 454: 
 455:     /* (non-Javadoc)
 456:      * @see javax.sound.midi.MidiChannel#getMute()
 457:      */
 458:     public boolean getMute()
 459:     {
 460:       // TODO Auto-generated method stub
 461:       return false;
 462:     }
 463: 
 464:     /* (non-Javadoc)
 465:      * @see javax.sound.midi.MidiChannel#setSolo(boolean)
 466:      */
 467:     public void setSolo(boolean solo)
 468:     {
 469:       // TODO Auto-generated method stub
 470: 
 471:     }
 472: 
 473:     /* (non-Javadoc)
 474:      * @see javax.sound.midi.MidiChannel#getSolo()
 475:      */
 476:     public boolean getSolo()
 477:     {
 478:       // TODO Auto-generated method stub
 479:       return false;
 480:     }
 481: 
 482:   }
 483: 
 484:   long sohandle;
 485:   long handle;
 486:   private Info info;
 487: 
 488:   MidiChannel channels[] = new MidiChannel[16];
 489: 
 490:   // The list of known soundbanks, and the default one.
 491:   List<Soundbank> soundbanks = new ArrayList<Soundbank>();
 492:   DSSISoundbank defaultSoundbank;
 493: 
 494:   /**
 495:    * Create a DSSI Synthesizer.
 496:    *
 497:    * @param info the DSSIInfo for this soft-synth
 498:    * @param soname the name of the .so file for this DSSI synth
 499:    * @param index the DSSI index for this soft-synth
 500:    */
 501:   public DSSISynthesizer(Info info, String soname, long index)
 502:   {
 503:     super();
 504:     this.info = info;
 505:     sohandle = DSSIMidiDeviceProvider.dlopen_(soname);
 506:     handle = DSSIMidiDeviceProvider.getDSSIHandle_(sohandle, index);
 507:     channels[0] = new DSSIMidiChannel(0);
 508:     defaultSoundbank = new DSSISoundbank("name", "description",
 509:                                          "vendor", "version");
 510:     soundbanks.add(defaultSoundbank);
 511: 
 512:     int i = 0;
 513:     String name;
 514:     do
 515:     {
 516:       name = getProgramName_(sohandle, i);
 517:       if (name != null)
 518:       {
 519:         defaultSoundbank.
 520:           add(new DSSIInstrument(defaultSoundbank,
 521:                                  new Patch(getProgramBank_(sohandle, i),
 522:                                            getProgramProgram_(sohandle, i)),
 523:                                  name));
 524:         i++;
 525:       }
 526:     } while (name != null);
 527:   }
 528: 
 529:   /* (non-Javadoc)
 530:    * @see javax.sound.midi.Synthesizer#getMaxPolyphony()
 531:    */
 532:   public int getMaxPolyphony()
 533:   {
 534:     // TODO Auto-generated method stub
 535:     return 0;
 536:   }
 537: 
 538:   /* (non-Javadoc)
 539:    * @see javax.sound.midi.Synthesizer#getLatency()
 540:    */
 541:   public long getLatency()
 542:   {
 543:     // DSSI and LADSPA provide no way to determine the latency.
 544:     // Let's just return 0 for now.
 545:     return 0;
 546:   }
 547: 
 548:   /* (non-Javadoc)
 549:    * @see javax.sound.midi.Synthesizer#getChannels()
 550:    */
 551:   public MidiChannel[] getChannels()
 552:   {
 553:     return channels;
 554:   }
 555: 
 556:   /* (non-Javadoc)
 557:    * @see javax.sound.midi.Synthesizer#getVoiceStatus()
 558:    */
 559:   public VoiceStatus[] getVoiceStatus()
 560:   {
 561:     // TODO Auto-generated method stub
 562:     return null;
 563:   }
 564: 
 565:   /* (non-Javadoc)
 566:    * @see javax.sound.midi.Synthesizer#isSoundbankSupported(javax.sound.midi.Soundbank)
 567:    */
 568:   public boolean isSoundbankSupported(Soundbank soundbank)
 569:   {
 570:     // TODO Auto-generated method stub
 571:     return false;
 572:   }
 573: 
 574:   /* @see javax.sound.midi.Synthesizer#loadInstrument(javax.sound.midi.Instrument)
 575:    */
 576:   public boolean loadInstrument(Instrument instrument)
 577:   {
 578:     // FIXME: perhaps this isn't quite right.  It can probably
 579:     // be in any soundbank.
 580:     if (instrument.getSoundbank() != defaultSoundbank)
 581:       throw new IllegalArgumentException ("Synthesizer doesn't support this instrument's soundbank");
 582: 
 583:     Patch patch = instrument.getPatch();
 584:     selectProgram_(sohandle, patch.getBank(), patch.getProgram());
 585:     return true;
 586:   }
 587: 
 588:   /* (non-Javadoc)
 589:    * @see javax.sound.midi.Synthesizer#unloadInstrument(javax.sound.midi.Instrument)
 590:    */
 591:   public void unloadInstrument(Instrument instrument)
 592:   {
 593:     // TODO Auto-generated method stub
 594: 
 595:   }
 596: 
 597:   /* (non-Javadoc)
 598:    * @see javax.sound.midi.Synthesizer#remapInstrument(javax.sound.midi.Instrument, javax.sound.midi.Instrument)
 599:    */
 600:   public boolean remapInstrument(Instrument from, Instrument to)
 601:   {
 602:     // TODO Auto-generated method stub
 603:     return false;
 604:   }
 605: 
 606:   /* @see javax.sound.midi.Synthesizer#getDefaultSoundbank()
 607:    */
 608:   public Soundbank getDefaultSoundbank()
 609:   {
 610:     return defaultSoundbank;
 611:   }
 612: 
 613:   /* @see javax.sound.midi.Synthesizer#getAvailableInstruments()
 614:    */
 615:   public Instrument[] getAvailableInstruments()
 616:   {
 617:     List<Instrument> instruments = new ArrayList<Instrument>();
 618:     Iterator<Soundbank> itr = soundbanks.iterator();
 619:     while (itr.hasNext())
 620:     {
 621:       Soundbank sb = itr.next();
 622:       Instrument ins[] = sb.getInstruments();
 623:       for (int i = 0; i < ins.length; i++)
 624:         instruments.add(ins[i]);
 625:     }
 626:     return instruments.toArray(new Instrument[instruments.size()]);
 627:   }
 628: 
 629:   /* (non-Javadoc)
 630:    * @see javax.sound.midi.Synthesizer#getLoadedInstruments()
 631:    */
 632:   public Instrument[] getLoadedInstruments()
 633:   {
 634:     // TODO Auto-generated method stub
 635:     return null;
 636:   }
 637: 
 638:   /* (non-Javadoc)
 639:    * @see javax.sound.midi.Synthesizer#loadAllInstruments(javax.sound.midi.Soundbank)
 640:    */
 641:   public boolean loadAllInstruments(Soundbank soundbank)
 642:   {
 643:     // TODO Auto-generated method stub
 644:     return false;
 645:   }
 646: 
 647:   /* (non-Javadoc)
 648:    * @see javax.sound.midi.Synthesizer#unloadAllInstruments(javax.sound.midi.Soundbank)
 649:    */
 650:   public void unloadAllInstruments(Soundbank soundbank)
 651:   {
 652:     // TODO Auto-generated method stub
 653:   }
 654: 
 655:   /* (non-Javadoc)
 656:    * @see javax.sound.midi.Synthesizer#loadInstruments(javax.sound.midi.Soundbank, javax.sound.midi.Patch[])
 657:    */
 658:   public boolean loadInstruments(Soundbank soundbank, Patch[] patchList)
 659:   {
 660:     // TODO Auto-generated method stub
 661:     return false;
 662:   }
 663: 
 664:   /* (non-Javadoc)
 665:    * @see javax.sound.midi.Synthesizer#unloadInstruments(javax.sound.midi.Soundbank, javax.sound.midi.Patch[])
 666:    */
 667:   public void unloadInstruments(Soundbank soundbank, Patch[] patchList)
 668:   {
 669:     // TODO Auto-generated method stub
 670: 
 671:   }
 672: 
 673:   /* @see javax.sound.midi.MidiDevice#getDeviceInfo()
 674:    */
 675:   public Info getDeviceInfo()
 676:   {
 677:     return info;
 678:   }
 679: 
 680:   /* @see javax.sound.midi.MidiDevice#open()
 681:    */
 682:   public void open() throws MidiUnavailableException
 683:   {
 684:     open_(sohandle);
 685:   }
 686: 
 687:   /* @see javax.sound.midi.MidiDevice#close()
 688:    */
 689:   public void close()
 690:   {
 691:     close_(sohandle);
 692:   }
 693: 
 694:   /* (non-Javadoc)
 695:    * @see javax.sound.midi.MidiDevice#isOpen()
 696:    */
 697:   public boolean isOpen()
 698:   {
 699:     // TODO Auto-generated method stub
 700:     return false;
 701:   }
 702: 
 703:   /* (non-Javadoc)
 704:    * @see javax.sound.midi.MidiDevice#getMicrosecondPosition()
 705:    */
 706:   public long getMicrosecondPosition()
 707:   {
 708:     // TODO Auto-generated method stub
 709:     return 0;
 710:   }
 711: 
 712:   /* @see javax.sound.midi.MidiDevice#getMaxReceivers()
 713:    */
 714:   public int getMaxReceivers()
 715:   {
 716:     return 1;
 717:   }
 718: 
 719:   /* @see javax.sound.midi.MidiDevice#getMaxTransmitters()
 720:    */
 721:   public int getMaxTransmitters()
 722:   {
 723:     return 0;
 724:   }
 725: 
 726:   /* @see javax.sound.midi.MidiDevice#getReceiver()
 727:    */
 728:   public Receiver getReceiver() throws MidiUnavailableException
 729:   {
 730:     return new DSSIReceiver();
 731:   }
 732: 
 733:   /* @see javax.sound.midi.MidiDevice#getTransmitter()
 734:    */
 735:   public Transmitter getTransmitter() throws MidiUnavailableException
 736:   {
 737:     return null;
 738:   }
 739: }