OpenTTD
music.cpp
Go to the documentation of this file.
1 /* $Id$ */
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 
14 
16 #define SET_TYPE "music"
17 #include "base_media_func.h"
18 
19 #include "safeguards.h"
20 #include "fios.h"
21 
22 
30 char *GetMusicCatEntryName(const char *filename, size_t entrynum)
31 {
32  if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL;
33 
35  uint32 ofs = FioReadDword();
36  size_t entry_count = ofs / 8;
37  if (entrynum < entry_count) {
38  FioSeekTo(entrynum * 8, SEEK_SET);
39  FioSeekTo(FioReadDword(), SEEK_SET);
40  byte namelen = FioReadByte();
41  char *name = MallocT<char>(namelen + 1);
42  FioReadBlock(name, namelen);
43  name[namelen] = '\0';
44  return name;
45  }
46  return NULL;
47 }
48 
57 byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen)
58 {
59  entrylen = 0;
60  if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL;
61 
63  uint32 ofs = FioReadDword();
64  size_t entry_count = ofs / 8;
65  if (entrynum < entry_count) {
66  FioSeekTo(entrynum * 8, SEEK_SET);
67  size_t entrypos = FioReadDword();
68  entrylen = FioReadDword();
69  FioSeekTo(entrypos, SEEK_SET);
71  byte *data = MallocT<byte>(entrylen);
72  FioReadBlock(data, entrylen);
73  return data;
74  }
75  return NULL;
76 }
77 
79 
80 
81 static const char * const _music_file_names[] = {
82  "theme",
83  "old_0", "old_1", "old_2", "old_3", "old_4", "old_5", "old_6", "old_7", "old_8", "old_9",
84  "new_0", "new_1", "new_2", "new_3", "new_4", "new_5", "new_6", "new_7", "new_8", "new_9",
85  "ezy_0", "ezy_1", "ezy_2", "ezy_3", "ezy_4", "ezy_5", "ezy_6", "ezy_7", "ezy_8", "ezy_9",
86 };
89 
90 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
92 
93 template <class Tbase_set>
94 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
95 {
96  return ".obm"; // OpenTTD Base Music
97 }
98 
99 template <class Tbase_set>
100 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
101 {
102  if (BaseMedia<Tbase_set>::used_set != NULL) return true;
103 
104  const Tbase_set *best = NULL;
105  for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
106  if (c->GetNumMissing() != 0) continue;
107 
108  if (best == NULL ||
109  (best->fallback && !c->fallback) ||
110  best->valid_files < c->valid_files ||
111  (best->valid_files == c->valid_files &&
112  (best->shortname == c->shortname && best->version < c->version))) {
113  best = c;
114  }
115  }
116 
118  return BaseMedia<Tbase_set>::used_set != NULL;
119 }
120 
121 bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename)
122 {
123  bool ret = this->BaseSet<MusicSet, NUM_SONGS_AVAILABLE, false>::FillSetDetails(ini, path, full_filename);
124  if (ret) {
125  this->num_available = 0;
126  IniGroup *names = ini->GetGroup("names");
127  IniGroup *catindex = ini->GetGroup("catindex");
128  IniGroup *timingtrim = ini->GetGroup("timingtrim");
129  uint tracknr = 1;
130  for (uint i = 0; i < lengthof(this->songinfo); i++) {
131  const char *filename = this->files[i].filename;
132  if (names == NULL || StrEmpty(filename) || this->files[i].check_result == MD5File::CR_NO_FILE) {
133  this->songinfo[i].songname[0] = '\0';
134  continue;
135  }
136 
137  this->songinfo[i].filename = filename; // non-owned pointer
138 
139  IniItem *item = catindex->GetItem(_music_file_names[i], false);
140  if (item != NULL && !StrEmpty(item->value)) {
141  /* Song has a CAT file index, assume it's MPS MIDI format */
142  this->songinfo[i].filetype = MTT_MPSMIDI;
143  this->songinfo[i].cat_index = atoi(item->value);
144  char *songname = GetMusicCatEntryName(filename, this->songinfo[i].cat_index);
145  if (songname == NULL) {
146  DEBUG(grf, 0, "Base music set song missing from CAT file: %s/%d", filename, this->songinfo[i].cat_index);
147  this->songinfo[i].songname[0] = '\0';
148  continue;
149  }
150  strecpy(this->songinfo[i].songname, songname, lastof(this->songinfo[i].songname));
151  free(songname);
152  } else {
154  }
155 
156  const char *trimmed_filename = filename;
157  /* As we possibly add a path to the filename and we compare
158  * on the filename with the path as in the .obm, we need to
159  * keep stripping path elements until we find a match. */
160  for (; trimmed_filename != NULL; trimmed_filename = strchr(trimmed_filename, PATHSEPCHAR)) {
161  /* Remove possible double path separator characters from
162  * the beginning, so we don't start reading e.g. root. */
163  while (*trimmed_filename == PATHSEPCHAR) trimmed_filename++;
164 
165  item = names->GetItem(trimmed_filename, false);
166  if (item != NULL && !StrEmpty(item->value)) break;
167  }
168 
169  if (this->songinfo[i].filetype == MTT_STANDARDMIDI) {
170  if (item != NULL && !StrEmpty(item->value)) {
171  strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname));
172  } else {
173  DEBUG(grf, 0, "Base music set song name missing: %s", filename);
174  return false;
175  }
176  }
177  this->num_available++;
178 
179  /* Number the theme song (if any) track 0, rest are normal */
180  if (i == 0) {
181  this->songinfo[i].tracknr = 0;
182  } else {
183  this->songinfo[i].tracknr = tracknr++;
184  }
185 
186  item = timingtrim->GetItem(trimmed_filename, false);
187  if (item != NULL && !StrEmpty(item->value)) {
188  const char *endpos = strchr(item->value, ':');
189  if (endpos != NULL) {
190  this->songinfo[i].override_start = atoi(item->value);
191  this->songinfo[i].override_end = atoi(endpos + 1);
192  }
193  }
194  }
195  }
196  return ret;
197 }
int override_end
MIDI tick to end the song at (0 if no override)
Standard MIDI file.
A group within an ini file.
Definition: ini_type.h:38
MusicSongInfo songinfo[NUM_SONGS_AVAILABLE]
Data about individual songs in set.
ChecksumResult check_result
cached result of md5 check
Generic function implementations for base data (graphics, sounds).
char * GetMusicCatEntryName(const char *filename, size_t entrynum)
Read the name of a music CAT file entry.
Definition: music.cpp:30
The file did not exist.
static const char * GetExtension()
Get the extension that is used to identify this set.
Definition: gfxinit.cpp:459
static const uint NUM_SONGS_AVAILABLE
Maximum number of songs in the full playlist; theme song + the classes.
static const char *const _music_file_names[]
Names corresponding to the music set&#39;s files.
Definition: music.cpp:81
int override_start
MIDI ticks to skip over in beginning.
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
byte * GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen)
Read the full data of a music CAT file entry.
Definition: music.cpp:57
IniGroup * GetGroup(const char *name, size_t len=0, bool create_new=true)
Get the group with the given name.
Definition: ini_load.cpp:156
char songname[32]
name of song displayed in UI
Slot used for the GRF scanning and such.
Definition: fios.h:95
MD5File files[NUM_FILES]
All files part of this set.
Subdirectory for all base data (base sets, intro game)
Definition: fileio_type.h:118
byte FioReadByte()
Read a byte from the file.
Definition: fileio.cpp:133
A single "line" in an ini file.
Definition: ini_type.h:25
All data of a music set.
const char * filename
filename
Definition of base types and functions in a cross-platform compatible way.
assert_compile(lengthof(_music_file_names)==NUM_SONGS_AVAILABLE)
Make sure we aren&#39;t messing things up.
A number of safeguards to prevent using unsafe methods.
void FioSeekTo(size_t pos, int mode)
Seek in the current file.
Definition: fileio.cpp:88
MPS GM driver MIDI format (contained in a CAT file)
char * value
The value of this item.
Definition: ini_type.h:28
const char * filename
file on disk containing song (when used in MusicSet class, this pointer is owned by MD5File object fo...
void FioReadBlock(void *ptr, size_t size)
Read a block.
Definition: fileio.cpp:187
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
bool FioCheckFileExists(const char *filename, Subdirectory subdir)
Check whether the given file exists.
Definition: fileio.cpp:312
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:36
void FioOpenFile(int slot, const char *filename, Subdirectory subdir)
Open a slotted file.
Definition: fileio.cpp:250
uint32 FioReadDword()
Read a double word (32 bits) from the file (in low endian format).
Definition: fileio.cpp:176
Ini file that supports both loading and saving.
Definition: ini_type.h:88
byte tracknr
track number of song displayed in UI
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:59
Declarations for savegames operations.
void FioSkipBytes(int n)
Skip n bytes ahead in the file.
Definition: fileio.cpp:150
bool FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename=true)
Read the set information from a loaded ini.
#define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type)
Force instantiation of methods so we don&#39;t get linker errors.
IniItem * GetItem(const char *name, bool create)
Get the item with the given name, and if it doesn&#39;t exist and create is true it creates a new item...
Definition: ini_load.cpp:105
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: depend.cpp:68
Information about a single base set.
int cat_index
entry index in CAT file, for filetype==MTT_MPSMIDI
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
MusicTrackType filetype
decoder required for song file
byte num_available
Number of valid songs in set.
static bool DetermineBestSet()
Determine the graphics pack that has to be used.
Definition: gfxinit.cpp:435