Mercurial > otakunoraifu
view music2/music.cc @ 55:f1a27ee7e03c
* started the same changes on scn2k_text.cc
* handle opcodes childObj*. In fact, it was handled (in a strange way, but it worked) before the previous changeset
author | thib |
---|---|
date | Wed, 22 Apr 2009 15:01:42 +0000 |
parents | ddbcbd000206 |
children | 4416cfac86ae |
line wrap: on
line source
/* * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* music.cc SDL_mixer を用いた音楽再生ルーチン */ #include <string.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <ctype.h> #include <signal.h> #include "system/system_config.h" #include "system/file.h" #include "music.h" #include <SDL.h> #include <SDL_mixer.h> #include "wavfile.h" using namespace std; MuSys * MuSys::_singleton = NULL; MuSys* MuSys::GetInstance(void) { if (_singleton == NULL) _singleton = new MuSys; return _singleton; } void MuSys::Quit(void) { if (_singleton != NULL) { _singleton->FinalizeMusic(); delete _singleton; _singleton = NULL; } } MuSys::MuSys() : movie_id(-1), music_enable(1) { int i; config = AyuSysConfig::GetInstance(); for (i=0; i<MIX_PCM_SIZE; i++) play_chunk[i] = 0; cdrom_track[0] = 0; effec_track[0] = 0; } // #define delete fprintf(stderr,"smus.cc: %d.",__LINE__), delete void bgm_start(const char* path, int loop_pt); void effec_start(int chn, const char* path, int loop, int fadein_time); void bgm_fadeout(int time); void MuSys::PlayCDROM(char* name, int play_count) { config->GetParam("#VOLMOD", 4, &volmod[0], &volmod[1], &volmod[2], &volmod[3]); char wave[128]; wave[127] = '\0'; wave[0] = '\0'; strcpy(cdrom_track, name); StopCDROM(0); strcpy(cdrom_track, name); /* name -> track */ int track =config->track_name.CDTrack(name); if (track == -1) track = atoi(name); if (config->track_name.WaveTrack(name) != NULL) strncpy(wave, config->track_name.WaveTrack(name), 127); if (wave[0] == 0 && track != 0) { /* DSTRACK が見つからない場合、CDTRACKを使用する */ sprintf(wave, "audio_%02d", track); } if (wave == 0) return; // BGM 再生 if (!pcm_enable) return; if (play_count == 0) bgm_start(wave, -1); else bgm_start(wave, config->track_name.TrackStart(name)); return; } void MuSys::StopCDROM(int time) { cdrom_track[0] = '\0'; if (!pcm_enable) return; bgm_fadeout(time); } void MuSys::PlaySE(const char* se, int loop_flag, int channel) { if (!pcm_enable) return; if (loop_flag) effec_start(MIX_PCM_EFFEC, se, 10000, 0); else effec_start(MIX_PCM_EFFEC, se, 0, 0); return; } void MuSys::PlaySE(int number) { if (! pcm_enable) return; const char* se_name = config->track_name.SETrack(number); if (se_name == NULL) return; effec_start(MIX_PCM_EFFEC, se_name, 0, 0); return; } void MuSys::StopSE(int time) { if (!pcm_enable) return; if (time == 0) Mix_HaltChannel(MIX_PCM_EFFEC); else Mix_FadeOutChannel(MIX_PCM_EFFEC, time); } bool MuSys::IsStopSE(void) { if (!pcm_enable) return true; if (Mix_Playing(MIX_PCM_EFFEC) != 0) return false; return true; } void MuSys::StopKoe(int time) { if (!pcm_enable) return; if (time == 0) Mix_HaltChannel(MIX_PCM_KOE); else Mix_FadeOutChannel(MIX_PCM_KOE, time); } void MuSys::InitMusic(void) { if (music_enable != 1) return; cdrom_track[0] = '\0'; if ( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF ) < 0 ){ // if ( Mix_OpenAudio( 48000, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF ) < 0 ){ return; } int freq, channels; Uint16 format; if ( Mix_QuerySpec(&freq, &format, &channels) ) { WAVFILE::freq = freq; WAVFILE::format = format; WAVFILE::channels = channels; } pcm_enable = 1; Mix_AllocateChannels( MIX_PCM_SIZE); music_enable = 2; } void MuSys::FinalizeMusic(void) { if (music_enable != 2) return; int i; for (i=0; i<MIX_PCM_SIZE; i++) { Mix_HaltChannel(i); if (play_chunk[i]) { Mix_FreeChunk(play_chunk[i]); } play_chunk[i] = 0; } Mix_HaltMusic(); Mix_HookMusic(0,0); Mix_CloseAudio(); pcm_enable = 0; music_enable = 1; } /************************************************************************* ** ** ファイル読み込み / 外部コマンド呼び出し */ struct WavChunk { WAVFILE* wav; int loop_pt; int *volmod; static void callback(void* userdata, Uint8* stream, int len); }; WavChunk wav_playing; static int fadetime_total; static int fadecount; void WavChunk::callback(void *userdata, Uint8 *stream, int len) { WavChunk* chunk = (WavChunk*)userdata; int count; if (chunk->loop_pt == -2) { // 再生終了後 memset(stream, 0, len); return; } char* stream_dup = new char[len]; count = chunk->wav->Read( (char*)stream_dup, 4, len/4); if (count != len/4) { // 最後まで再生した if (chunk->loop_pt == -1) { // 終了 chunk->loop_pt = -2; memset(stream_dup+count*4, 0, len-count*4); } else { chunk->wav->Seek(chunk->loop_pt); chunk->wav->Read( (char*)(stream_dup+count*4), 4, len/4-count); } } int cur_vol = (*chunk->volmod)*SDL_MIX_MAXVOLUME/255; if (fadetime_total) { // 音楽を停止中 (fade out) int count_total = fadetime_total*(WAVFILE::freq/1000); if (fadecount > count_total || fadetime_total == 1) { // 音楽停止 chunk->loop_pt = -2; memset(stream, 0, len); delete[] stream_dup; return; } cur_vol = cur_vol*(count_total-fadecount)/count_total; fadecount += len/4; } SDL_MixAudio(stream, (Uint8*)stream_dup, len, cur_vol); delete[] stream_dup; return; } void bgm_fadeout(int time) { fadecount = 0; if (time <= 0) time = 1; fadetime_total = time; } static SDL_RWops* OpenSDLRW(const char* path); static WAVFILE* OpenWaveFile(const char* path); void bgm_start(const char* path, int loop_pt) { MuSys* mu = MuSys::GetInstance(); if (!mu->pcm_enable) return; fprintf(stderr,"bgm start %s\n",path); WAVFILE* wav = OpenWaveFile(path); if (wav == NULL) return; Mix_PauseMusic(); Mix_HaltMusic(); Mix_HookMusic(0,0); /* 前に再生していたのを終了 */ if (wav_playing.wav != NULL) { delete wav_playing.wav; wav_playing.wav = NULL; } wav_playing.wav = wav; wav_playing.loop_pt = loop_pt; wav_playing.volmod = mu->volmod; fadetime_total = 0; fadecount = 0; Mix_HookMusic( &(WavChunk::callback), (void*)&wav_playing); } void effec_start(int chn, const char* path, int loop, int fadein_time) { MuSys* mu = MuSys::GetInstance(); if (!mu->pcm_enable) return; SDL_RWops* op = OpenSDLRW(path); if (op == NULL) { // ファイルが見付からない return; } Mix_Pause(chn); if (mu->play_chunk[chn] != NULL) { Mix_FreeChunk(mu->play_chunk[chn]); } mu->play_chunk[chn] = Mix_LoadWAV_RW(op, 1); if (fadein_time <= 0) { Mix_Volume(chn, mu->volmod[3]*SDL_MIX_MAXVOLUME/255); Mix_PlayChannel(chn, mu->play_chunk[chn], loop); } else { Mix_Volume(chn, mu->volmod[3]*SDL_MIX_MAXVOLUME/255); Mix_FadeInChannel(chn, mu->play_chunk[chn], loop, fadein_time); } } void MuSys::PlayKoe(const char* path) { if (!pcm_enable) return; MuSys* mu = MuSys::GetInstance(); static char* playing_koedata = NULL; int len = 0; AvgKoeInfo koeinfo; int chn = MIX_PCM_KOE; Mix_Pause(chn); Mix_HaltChannel(chn); // これで RWop が解放されるはず… if (mu->play_chunk[chn] != NULL) { Mix_FreeChunk(mu->play_chunk[chn]); mu->play_chunk[chn] = NULL; } if (playing_koedata != NULL) { free(playing_koedata); playing_koedata = NULL; } koeinfo = OpenKoeFile(path); if (koeinfo.stream == NULL) return; playing_koedata = decode_koe(koeinfo, &len); fclose(koeinfo.stream); if (playing_koedata == NULL) { return; } Mix_Volume(chn, mu->volmod[1]*SDL_MIX_MAXVOLUME/255); mu->play_chunk[chn] = Mix_LoadWAV_RW(SDL_RWFromMem(playing_koedata, len+0x2c), 1); Mix_PlayChannel(chn, mu->play_chunk[chn], 0); } AvgKoeInfo OpenKoeFile(const char* path) { int radix = 10000; /* if (global_system.Version() >= 2) */ radix *= 10; AvgKoeInfo info; info.stream = NULL; info.length = 0; info.offset = 0; if (isdigit(path[0]) && strchr(path,'.') == NULL) { // 数値 (拡張子等なし) /* avg32 形式の音声アーカイブのキャッシュを検索 */ int pointer = atoi(path); int file_no = pointer / radix; int index = pointer % radix; info = FindKoe(file_no, index); } else { // ファイル int length; ARCINFO* arcinfo = FileSearcher::GetInstance()->Find(FileSearcher::KOE, path, ".WPD"); if (arcinfo == NULL) return info; info.stream = arcinfo->OpenFile(&length); info.rate = 22050; info.length = length; info.offset = ftell(info.stream); info.type = koe_unknown; delete arcinfo; } return info; } static SDL_RWops* OpenSDLRW(const char* path) { /* まず wav ファイルを探す */ FileSearcher* file_searcher = FileSearcher::GetInstance(); ARCINFO* info = file_searcher->Find(FileSearcher::WAV, path, ".wav"); if (info == NULL) { info = file_searcher->Find(FileSearcher::WAV, path, ".nwa"); if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "nwa"); if (info != NULL) { // read NWA file int dummy; FILE* f = info->OpenFile(&dummy); static char* d = 0; int sz; if (d != 0) delete[] d; d = NWAFILE::ReadAll(f, sz); return SDL_RWFromMem(d, sz); } } if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "wav"); if (info == NULL) info = file_searcher->Find(FileSearcher::WAV, path, ".ogg"); if (info != NULL) { int dummy; FILE* f = info->OpenFile(&dummy); delete info; if (f == NULL) return NULL; SDL_RWops* op = SDL_RWFromFP(f, 1); return op; } return NULL; } static WAVFILE* OpenWaveFile(const char* path) { /* まず wav ファイルを探す */ FileSearcher* file_searcher = FileSearcher::GetInstance(); ARCINFO* info = file_searcher->Find(FileSearcher::WAV, path, ".wav"); if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "wav"); if (info != NULL) { int size; FILE* f = info->OpenFile(&size); delete info; if (f == NULL) return NULL; WAVFILE* w = WAVFILE::MakeConverter(new WAVFILE_Stream(f, size)); return w; } /* 次に nwa ファイル */ info = file_searcher->Find(FileSearcher::WAV, path, ".nwa"); if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "nwa"); if (info != NULL) { int size; FILE* f = info->OpenFile(&size); delete info; if (f == NULL) return NULL; WAVFILE* w = WAVFILE::MakeConverter(new NWAFILE(f)); return w; } /* 次に mp3 ファイル */ info = file_searcher->Find(FileSearcher::WAV, path, ".mp3"); if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "mp3"); if (info != NULL) { int size; FILE* f = info->OpenFile(&size); delete info; if (f == NULL) return NULL; MP3FILE* w = new MP3FILE(f, size); if (w->pimpl != NULL) { return WAVFILE::MakeConverter(w); } delete w; } /* 次に ogg ファイル */ info = file_searcher->Find(FileSearcher::WAV, path, ".ogg"); if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "ogg"); if (info != NULL) { int size; FILE* f = info->OpenFile(&size); delete info; if (f == NULL) return NULL; OggFILE* w = new OggFILE(f, size); if (w->pimpl != NULL) { return WAVFILE::MakeConverter(w); } delete w; } return NULL; }