diff --git a/SConstruct b/SConstruct index 710fd4505..d18c87b78 100755 --- a/SConstruct +++ b/SConstruct @@ -96,7 +96,6 @@ common_sources = [ 'main/gameseq.c', 'main/gauges.c', 'main/hash.c', -'main/hmp2mid.c', 'main/hostage.c', 'main/hud.c', 'main/hudlog.c', @@ -252,15 +251,16 @@ arch_linux_sources = [ 'arch/sdl/mouse.c' ] -# choosing a sound implementation for linux +# choosing a sound implementation for Linux +common_sound_hmp2mid = [ 'main/hmp2mid.c' ] arch_linux_sound_sdlmixer = [ 'arch/sdl/mixdigi.c', 'arch/sdl/mixmusic.c' ] arch_linux_sound_old = [ 'arch/sdl/digi.c', 'arch/linux/hmiplay.c' ] if (sdlmixer == 1): + common_sources += common_sound_hmp2mid arch_linux_sources += arch_linux_sound_sdlmixer else: arch_linux_sources += arch_linux_sound_old - # for windows arch_win32_sources = [ @@ -412,6 +412,8 @@ if (shareware == 1): if (shareware == 0) and (editor == 0): common_sources = ['main/loadrl2.c'] + common_sources +print '\n' + # finally building program... env.Program(target=str(target), source = common_sources, LIBS = alllibs, LINKFLAGS = str(lflags)) env.Install(BIN_DIR, str(target)) diff --git a/arch/sdl/mixmusic.c b/arch/sdl/mixmusic.c index 97651fc27..c0c084985 100644 --- a/arch/sdl/mixmusic.c +++ b/arch/sdl/mixmusic.c @@ -18,6 +18,7 @@ #include #include "cfile.h" +#define MIX_MUSIC_DEBUG 1 #define MUSIC_FADE_TIME 500 //milliseconds #define MUSIC_EXTENSION_ARG "-music_ext" @@ -29,10 +30,10 @@ void music_done() { current_music = NULL; } -void convert_hmp(char * filename) { - - char *mid_filename = "tmp.mid"; +void convert_hmp(char *filename, char *mid_filename) { + if (access(mid_filename, R_OK) != 0) { + if (MIX_MUSIC_DEBUG) printf("convert_hmp: converting %s to %s\n", filename, mid_filename); const char *err; CFILE *hmp_in; @@ -62,43 +63,50 @@ void convert_hmp(char * filename) { return; } } + else { + if (MIX_MUSIC_DEBUG) printf("convert_hmp: %s already exists\n", mid_filename); + } } void mix_play_music(char *filename, int loop) { - int got_end=0, i, t; - loop *= -1; + loop *= -1; + int i, t, got_end=0; int fn_buf_len = strlen(DESCENT_DATA_PATH) + strlen(filename) + 16; - char real_filename[fn_buf_len]; - char music_file_extension[8] = "mid"; - // Quick hack to suppress the .hmp extension + char real_filename[fn_buf_len]; + char midi_filename[16]; + char music_title[16]; + char music_file_extension[8]; + + // Quick hack to filter out the .hmp extension for (i=0; !got_end; i++) { switch (filename[i]) { case '.': - // prematurely end the string when we find the dot - filename[i] = '\0'; case '\0': + music_title[i] = '\0'; got_end = 1; + break; + default: + music_title[i] = filename[i]; } } // What is the extension of external files? If none, default to internal MIDI t = FindArg(MUSIC_EXTENSION_ARG); if (t > 0) { - sprintf(music_file_extension,"%.3s", Args[t+1]); + sprintf(music_file_extension, "%.3s", Args[t+1]); + // Building absolute path to the file + sprintf(real_filename, "%s%s.%s", DESCENT_DATA_PATH, music_title, music_file_extension); } else { - convert_hmp(filename); - //hmp2mid((hmp2mid_read_func_t)cfread, hmp_in, mid_out); + sprintf(midi_filename, "%s.mid", music_title); + convert_hmp(filename, midi_filename); + // Relative path for now (we're using $HOME/.d1x-rebirth/ as working dir) + strcpy(real_filename, midi_filename); } - // Building absolute path to the file - sprintf(real_filename, "%s%s.%s", DESCENT_DATA_PATH, filename, music_file_extension); - - current_music = Mix_LoadMUS(real_filename); - - if (current_music) { + if ((current_music = Mix_LoadMUS(real_filename))) { printf("Now playing: %s\n", real_filename); if (Mix_PlayingMusic()) { // Fade-in effect sounds cleaner if we're already playing something diff --git a/main/hmp2mid.c b/main/hmp2mid.c new file mode 100644 index 000000000..d567dbebc --- /dev/null +++ b/main/hmp2mid.c @@ -0,0 +1,232 @@ +/* hmp 2 midi file conversion. The conversion algorithm is based on the + conversion algorithms found in d1x, d2x-xl and jjffe. The code is mine. + + Copyright 2006 Hans de Goede + + This file and the acompanying hmp2mid.h file are free software; + you can redistribute them and/or modify them under the terms of the GNU + Library General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + These files are distributed in the hope that they will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with these files; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#include +#include +#include +#include "hmp2mid.h" + +/* Some convience macros to keep the code below more readable */ + +#define HMP_READ(buf, count) \ + {\ + if (read_func(buf, 1, count, hmp_in) != (count)) \ + { \ + free(mid_track_buf); \ + return hmp_read_error; \ + } \ + /* notice that when we are not actually in the track reading code this \ + is bogus, but does no harm. And in the track code it helps :) */ \ + track_length -= count; \ + } + +#define HMP_READ_DWORD(dest) \ + { \ + unsigned char _buf[4]; \ + HMP_READ(_buf, 4); \ + *(dest) = (_buf[3] << 24) | (_buf[2] << 16) | (_buf[1] << 8) | _buf[0]; \ + } + +#define MID_WRITE(buf, count) \ + if (fwrite(buf, 1, count, mid_out) != (count)) \ + { \ + free(mid_track_buf); \ + snprintf(hmp2mid_error, sizeof(hmp2mid_error), mid_write_error_templ, \ + strerror(errno)); \ + return hmp2mid_error; \ + } + +#define MID_TRACK_BUF(buf, count) \ + { \ + if ((mid_track_buf_used + count) > mid_track_buf_size) \ + { \ + void *tmp = mid_track_buf; \ + mid_track_buf = realloc(mid_track_buf, mid_track_buf_size + 65536); \ + if (!mid_track_buf) \ + { \ + free(tmp); \ + return "Error could not allocate midi track memory"; \ + } \ + } \ + memcpy(mid_track_buf + mid_track_buf_used, buf, count); \ + mid_track_buf_used += count; \ + } + + +static const char *hmp_read_error = "Error reading from hmp file"; +static const char *mid_write_error_templ = "Error writing to mid file: %s"; +static char hmp2mid_error[512]; +/* The beginning of the midi header */ +static const char midi_header1[10] = { 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1 }; +/* The last 2 bytes of the midi header and track0 */ +static const char midi_header2[21] = { 0, 0xC0, 'M', 'T', 'r', 'k', 0, 0, 0, + 0x0B, 0, 0xFF, 0x51, 0x03, 0x18, 0x80, 0, 0, 0xFF, 0x2F, 0 }; + +const char *hmp2mid(hmp2mid_read_func_t read_func, void *hmp_in, FILE* mid_out) +{ + unsigned char last_com = 0, buf[0x300]; + unsigned int num_tracks, track_length = 0, i, t; + unsigned char *mid_track_buf = NULL; + int n1, n2, mid_track_buf_used, mid_track_buf_size = 0; + + /* Read the header and verify that this is a hmp file */ + HMP_READ(buf, 8); + buf[8] = 0; + if (strcmp((char *)buf, "HMIMIDIP")) + return "Error not a hmp file"; + + /* Discard the next 0x28 bytes, taking us to location 0x30 and read the + number of tracks there */ + HMP_READ(buf, 0x30 - 8); + HMP_READ_DWORD(&num_tracks); + + /* Discard bytes taking us to location 0x300 around which track 1 starts */ + HMP_READ(buf, 0x300 - 0x34); + + /* Now search for the end of track marker of track 0 */ + HMP_READ(buf, 3); + while ((buf[0] != 0xFF) || (buf[1] != 0x2F) || (buf[2] != 0x00)) + { + buf[0] = buf[1]; + buf[1] = buf[2]; + HMP_READ(buf + 2, 1); + } + + /* Sofar so good, write out the midi header */ + MID_WRITE(midi_header1, sizeof(midi_header1)); + /* number of tracks is a 16 bit MSB word, better not have more then 65535 + tracks :) */ + buf[0] = (num_tracks >> 8) & 0xFF; + buf[1] = num_tracks & 0xFF; + MID_WRITE(buf, 2); + /* Write the last word of the header and track0 */ + MID_WRITE(midi_header2, sizeof(midi_header2)); + + /* Read and convert all the tracks */ + for (i = 1; i < num_tracks; i++) + { + /* Read and verify hmp track number */ + HMP_READ_DWORD(&t); + if (t != i) + { + free(mid_track_buf); + return "Error invalid hmp track number"; + } + /* Read number of bytes in this track */ + HMP_READ_DWORD(&track_length); + /* Above we've already read the first 8 bytes of this track, adjust + track_lenght accordingly. */ + track_length -= 8; + /* Read and skip the next 4 unidentified header bytes */ + HMP_READ(buf, 4); + + /* Sofar so good write midi track header */ + MID_WRITE("MTrk", 4); + + /* Now we need to write the track length, but we don't know that yet, so + the track gets written to a dynamicly growing buffer (which is hidden + in the MID_TRACK_BUF macro) */ + mid_track_buf_used = 0; + + /* And finally start the real conversion */ + while (track_length > 0) + { + n1 = -1; /* -1 to "counter" the intital n1++ */ + do + { + n1++; + HMP_READ(buf + n1, 1); + } while (!(buf[n1] & 0x80)); + + if (n1 >= 4) + { + free(mid_track_buf); + return "Error parsing hmp track"; + } + + for (n2 = 0; n2 <= n1; n2++) + { + unsigned char u = buf[n1-n2] & 0x7F; + + if (n2 != n1) + u |= 0x80; + MID_TRACK_BUF(&u, 1); + } + + HMP_READ(buf, 1); + + if (buf[0] == 0xFF) /* meta? */ + { + HMP_READ(buf + 1, 2); + HMP_READ(buf + 3, buf[2]); + MID_TRACK_BUF(buf, 3 + buf[2]); + if (buf[1] == 0x2F) /* end of track? */ + { + if (buf[2] != 0x00) + { + free(mid_track_buf); + return "Error hmp meta end of track with non zero size"; + } + break; + } + else + continue; + } + + switch (buf[0] & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + t = 2; + break; + case 0xC0: + case 0xD0: + t = 1; + break; + default: + free(mid_track_buf); + return "Error invalid hmp command"; + } + if (buf[0] != last_com) + MID_TRACK_BUF(buf, 1); + HMP_READ(buf + 1, t); + MID_TRACK_BUF(buf + 1, t); + last_com = buf[0]; + } + if (track_length != 0) + { + free(mid_track_buf); + return "Error invalid track length"; + } + /* write the midi track length */ + buf [0] = mid_track_buf_used >> 24; + buf [1] = (mid_track_buf_used >> 16) & 0xFF; + buf [2] = (mid_track_buf_used >> 8) & 0xFF; + buf [3] = mid_track_buf_used & 0xFF; + MID_WRITE(buf, 4); + /* and the track itself */ + MID_WRITE(mid_track_buf, mid_track_buf_used); + } + free (mid_track_buf); + return NULL; +} diff --git a/main/hmp2mid.h b/main/hmp2mid.h new file mode 100644 index 000000000..287d044b1 --- /dev/null +++ b/main/hmp2mid.h @@ -0,0 +1,31 @@ +/* hmp 2 midi file conversion. The conversion algorithm is based on the + conversion algorithms found in d1x, d2x-xl and jjffe. The code is mine. + + Copyright 2006 Hans de Goede + + This file and the acompanying hmp2mid.c file are free software; + you can redistribute them and/or modify them under the terms of the GNU + Library General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + These files are distributed in the hope that they will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with these files; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#ifndef __HMP2MID_H +#define __HMP2MID_H +#include + +typedef size_t (*hmp2mid_read_func_t)(void *ptr, size_t size, size_t nmemb, + void *stream); + +/* Returns NULL on success, otherwise a c-string with an error message */ +const char *hmp2mid(hmp2mid_read_func_t read_func, void *hmp_in, FILE* mid_out); + +#endif diff --git a/main/inferno.c b/main/inferno.c index 696e1a972..0da0f561a 100755 --- a/main/inferno.c +++ b/main/inferno.c @@ -449,10 +449,7 @@ int main(int argc,char **argv) if (Inferno_verbose) printf ("%s", TXT_VERBOSE_1); - arch_init(); - cd_init(); - - if (init_graphics()) return 1; + //MD2211, 2006-08-30 : moving sound init *before* ReadConfigFile(), so that we restore music volume properly. //------------ Init sound --------------- if (!FindArg( "-nosound" )) { @@ -471,6 +468,14 @@ int main(int argc,char **argv) else { if (Inferno_verbose) printf( "\n%s",TXT_SOUND_DISABLED ); } + + ReadConfigFile(); + + arch_init(); + cd_init(); + + if (init_graphics()) return 1; + #ifdef NETWORK if (!FindArg("-noserial")) serial_active = 1;