OpenTTD
libtimidity.cpp
Go to the documentation of this file.
1 /* $Id: libtimidity.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "../stdafx.h"
13 #include "../openttd.h"
14 #include "../sound_type.h"
15 #include "../debug.h"
16 #include "libtimidity.h"
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <sys/stat.h>
23 #include <errno.h>
24 #include <timidity.h>
25 #if defined(PSP)
26 #include <pspaudiolib.h>
27 #endif /* PSP */
28 
29 #include "../safeguards.h"
30 
32 enum MidiState {
33  MIDI_STOPPED = 0,
34  MIDI_PLAYING = 1,
35 };
36 
37 static struct {
38  MidIStream *stream;
39  MidSongOptions options;
40  MidSong *song;
41 
42  MidiState status;
43  uint32 song_length;
44  uint32 song_position;
45 } _midi;
46 
47 #if defined(PSP)
48 static void AudioOutCallback(void *buf, unsigned int _reqn, void *userdata)
49 {
50  memset(buf, 0, _reqn * PSP_NUM_AUDIO_CHANNELS);
51  if (_midi.status == MIDI_PLAYING) {
52  mid_song_read_wave(_midi.song, buf, _reqn * PSP_NUM_AUDIO_CHANNELS);
53  }
54 }
55 #endif /* PSP */
56 
59 
60 const char *MusicDriver_LibTimidity::Start(const char * const *param)
61 {
62  _midi.status = MIDI_STOPPED;
63  _midi.song = NULL;
64 
65  if (mid_init(param == NULL ? NULL : const_cast<char *>(param[0])) < 0) {
66  /* If init fails, it can be because no configuration was found.
67  * If it was not forced via param, try to load it without a
68  * configuration. Who knows that works. */
69  if (param != NULL || mid_init_no_config() < 0) {
70  return "error initializing timidity";
71  }
72  }
73  DEBUG(driver, 1, "successfully initialised timidity");
74 
75  _midi.options.rate = 44100;
76  _midi.options.format = MID_AUDIO_S16LSB;
77  _midi.options.channels = 2;
78 #if defined(PSP)
79  _midi.options.buffer_size = PSP_NUM_AUDIO_SAMPLES;
80 #else
81  _midi.options.buffer_size = _midi.options.rate;
82 #endif
83 
84 #if defined(PSP)
85  pspAudioInit();
86  pspAudioSetChannelCallback(_midi.options.channels, &AudioOutCallback, NULL);
87  pspAudioSetVolume(_midi.options.channels, PSP_VOLUME_MAX, PSP_VOLUME_MAX);
88 #endif /* PSP */
89 
90  return NULL;
91 }
92 
94 {
95  if (_midi.status == MIDI_PLAYING) this->StopSong();
96  mid_exit();
97 }
98 
99 void MusicDriver_LibTimidity::PlaySong(const char *filename)
100 {
101  this->StopSong();
102 
103  _midi.stream = mid_istream_open_file(filename);
104  if (_midi.stream == NULL) {
105  DEBUG(driver, 0, "Could not open music file");
106  return;
107  }
108 
109  _midi.song = mid_song_load(_midi.stream, &_midi.options);
110  mid_istream_close(_midi.stream);
111  _midi.song_length = mid_song_get_total_time(_midi.song);
112 
113  if (_midi.song == NULL) {
114  DEBUG(driver, 1, "Invalid MIDI file");
115  return;
116  }
117 
118  mid_song_start(_midi.song);
119  _midi.status = MIDI_PLAYING;
120 }
121 
123 {
124  _midi.status = MIDI_STOPPED;
125  /* mid_song_free cannot handle NULL! */
126  if (_midi.song != NULL) mid_song_free(_midi.song);
127  _midi.song = NULL;
128 }
129 
131 {
132  if (_midi.status == MIDI_PLAYING) {
133  _midi.song_position = mid_song_get_time(_midi.song);
134  if (_midi.song_position >= _midi.song_length) {
135  _midi.status = MIDI_STOPPED;
136  _midi.song_position = 0;
137  }
138  }
139 
140  return (_midi.status == MIDI_PLAYING);
141 }
142 
144 {
145  if (_midi.song != NULL) mid_song_set_volume(_midi.song, vol);
146 }