View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.tika.parser.audio;
18  
19  import java.io.BufferedInputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.Set;
26  
27  import javax.sound.midi.InvalidMidiDataException;
28  import javax.sound.midi.MetaMessage;
29  import javax.sound.midi.MidiMessage;
30  import javax.sound.midi.MidiSystem;
31  import javax.sound.midi.Patch;
32  import javax.sound.midi.Sequence;
33  import javax.sound.midi.Track;
34  
35  import org.apache.tika.exception.TikaException;
36  import org.apache.tika.metadata.Metadata;
37  import org.apache.tika.mime.MediaType;
38  import org.apache.tika.parser.ParseContext;
39  import org.apache.tika.parser.Parser;
40  import org.apache.tika.sax.XHTMLContentHandler;
41  import org.xml.sax.ContentHandler;
42  import org.xml.sax.SAXException;
43  
44  public class MidiParser implements Parser {
45  
46      private static final Set<MediaType> SUPPORTED_TYPES =
47          Collections.unmodifiableSet(new HashSet<MediaType>(Arrays.asList(
48                  MediaType.application("x-midi"),
49                  MediaType.audio("midi"))));
50  
51      public Set<MediaType> getSupportedTypes(ParseContext context) {
52          return SUPPORTED_TYPES;
53      }
54  
55      public void parse(
56              InputStream stream, ContentHandler handler,
57              Metadata metadata, ParseContext context)
58              throws IOException, SAXException, TikaException {
59          metadata.set(Metadata.CONTENT_TYPE, "audio/midi");
60  
61          XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata);
62          xhtml.startDocument();
63  
64          // MidiSystem expects the stream to support the mark feature
65          InputStream buffered = new BufferedInputStream(stream);
66          try {
67              Sequence sequence = MidiSystem.getSequence(buffered);
68  
69              Track[] tracks = sequence.getTracks();
70              metadata.set("tracks", String.valueOf(tracks.length));
71              // TODO: Use XMPDM.TRACKS?
72  
73              Patch[] patches = sequence.getPatchList();
74              metadata.set("patches", String.valueOf(patches.length));
75  
76              float type = sequence.getDivisionType();
77              if (type == Sequence.PPQ) {
78                  metadata.set("divisionType", "PPQ");
79              } else if (type == Sequence.SMPTE_24) {
80                  metadata.set("divisionType", "SMPTE_24");
81              } else if (type == Sequence.SMPTE_25) {
82                  metadata.set("divisionType", "SMPTE_25");
83              } else if (type == Sequence.SMPTE_30) {
84                  metadata.set("divisionType", "SMPTE_30");
85              } else if (type == Sequence.SMPTE_30DROP) {
86                  metadata.set("divisionType", "SMPTE_30DROP");
87              } else if (type == Sequence.SMPTE_24) {
88                  metadata.set("divisionType", String.valueOf(type));
89              }
90  
91              for (Track track : tracks) {
92                  xhtml.startElement("p");
93                  for (int i = 0; i < track.size(); i++) {
94                      MidiMessage message = track.get(i).getMessage();
95                      if (message instanceof MetaMessage) {
96                          MetaMessage meta = (MetaMessage) message;
97                          // Types 1-15 are reserved for text events
98                          if (meta.getType() >= 1 && meta.getType() <= 15) {
99                              // FIXME: What's the encoding?
100                             xhtml.characters(
101                                     new String(meta.getData(), "ISO-8859-1"));
102                         }
103                     }
104                 }
105                 xhtml.endElement("p");
106             }
107         } catch (InvalidMidiDataException ignore) {
108             // There is no way to know whether this exception was
109             // caused by the document being corrupted or by the format
110             // just being unsupported. So we do nothing.
111         }
112 
113         xhtml.endDocument();
114     }
115 
116     /**
117      * @deprecated This method will be removed in Apache Tika 1.0.
118      */
119     public void parse(
120             InputStream stream, ContentHandler handler, Metadata metadata)
121             throws IOException, SAXException, TikaException {
122         parse(stream, handler, metadata, new ParseContext());
123     }
124 
125 }