root/music2/music.cc

Revision 65:4416cfac86ae, 12.0 KB (checked in by Thibaut Girka <thib@…>, 18 months ago)
Convert EUC-JP files to UTF8
Line 
1/*
2 * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*  music.cc    SDL_mixer を甚いた音楜再生ルヌチン */
29
30
31#include <string.h>
32#include <stdio.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <ctype.h>
36#include <signal.h>
37#include "system/system_config.h"
38#include "system/file.h"
39#include "music.h"
40#include <SDL.h>
41#include <SDL_mixer.h>
42#include "wavfile.h"
43
44using namespace std;
45
46MuSys * MuSys::_singleton = NULL;
47
48MuSys* MuSys::GetInstance(void)
49{
50        if (_singleton == NULL)
51                _singleton = new MuSys;
52        return _singleton;
53}
54
55void MuSys::Quit(void)
56{
57        if (_singleton != NULL) {
58                _singleton->FinalizeMusic();
59                delete _singleton;
60                _singleton = NULL;
61        }
62}
63
64MuSys::MuSys() : movie_id(-1), music_enable(1) {
65        int i;
66        config = AyuSysConfig::GetInstance();
67        for (i=0; i<MIX_PCM_SIZE; i++)
68                play_chunk[i] = 0;
69        cdrom_track[0] = 0;
70        effec_track[0] = 0;
71}
72
73
74// #define delete fprintf(stderr,"smus.cc: %d.",__LINE__), delete
75
76void bgm_start(const char* path, int loop_pt);
77void effec_start(int chn, const char* path, int loop, int fadein_time);
78void bgm_fadeout(int time);
79
80void MuSys::PlayCDROM(char* name, int play_count) {
81        config->GetParam("#VOLMOD", 4, &volmod[0], &volmod[1], &volmod[2], &volmod[3]);
82
83        char wave[128];
84        wave[127] = '\0';
85        wave[0] = '\0';
86
87        strcpy(cdrom_track, name);
88
89        StopCDROM(0);
90        strcpy(cdrom_track, name);
91
92        /* name -> track */
93        int track =config->track_name.CDTrack(name);
94        if (track == -1) track = atoi(name);
95        if (config->track_name.WaveTrack(name) != NULL)
96                strncpy(wave, config->track_name.WaveTrack(name), 127);
97        if (wave[0] == 0 && track != 0) { /* DSTRACK が芋぀からない堎合、CDTRACKを䜿甚する */
98                sprintf(wave, "audio_%02d", track);
99        }
100        if (wave == 0) return;
101        // BGM 再生
102        if (!pcm_enable) return;
103        if (play_count == 0)
104                bgm_start(wave, -1);
105        else
106                bgm_start(wave, config->track_name.TrackStart(name));
107        return;
108}
109
110void MuSys::StopCDROM(int time)
111{
112        cdrom_track[0] = '\0';
113        if (!pcm_enable) return;
114        bgm_fadeout(time);
115}
116
117void MuSys::PlaySE(const char* se, int loop_flag, int channel) {
118        if (!pcm_enable) return;
119        if (loop_flag)
120                effec_start(MIX_PCM_EFFEC, se, 10000, 0);
121        else
122                effec_start(MIX_PCM_EFFEC, se, 0, 0);
123        return;
124}
125void MuSys::PlaySE(int number) {
126        if (! pcm_enable) return;
127        const char* se_name = config->track_name.SETrack(number);
128        if (se_name == NULL) return;
129        effec_start(MIX_PCM_EFFEC, se_name, 0, 0);
130        return;
131}
132void MuSys::StopSE(int time) {
133        if (!pcm_enable) return;
134        if (time == 0) 
135                Mix_HaltChannel(MIX_PCM_EFFEC);
136        else
137                Mix_FadeOutChannel(MIX_PCM_EFFEC, time);
138}
139bool MuSys::IsStopSE(void) {
140        if (!pcm_enable) return true;
141        if (Mix_Playing(MIX_PCM_EFFEC) != 0) return false;
142        return true;
143}
144
145void MuSys::StopKoe(int time) {
146        if (!pcm_enable) return;
147        if (time == 0) Mix_HaltChannel(MIX_PCM_KOE);
148        else Mix_FadeOutChannel(MIX_PCM_KOE, time);
149}
150
151void MuSys::InitMusic(void)
152{
153        if (music_enable != 1) return;
154        cdrom_track[0] = '\0';
155        if ( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF ) < 0 ){
156//      if ( Mix_OpenAudio( 48000, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF ) < 0 ){
157                return;
158        }
159        int freq, channels; Uint16 format;
160        if ( Mix_QuerySpec(&freq, &format, &channels) ) {
161                WAVFILE::freq = freq;
162                WAVFILE::format = format;
163                WAVFILE::channels = channels;
164        }
165        pcm_enable = 1;
166        Mix_AllocateChannels( MIX_PCM_SIZE);
167        music_enable = 2;
168}
169
170void MuSys::FinalizeMusic(void)
171{
172        if (music_enable != 2) return;
173        int i;
174        for (i=0; i<MIX_PCM_SIZE; i++) {
175                Mix_HaltChannel(i);
176                if (play_chunk[i]) {
177                        Mix_FreeChunk(play_chunk[i]);
178                }
179                play_chunk[i] = 0;
180        }
181        Mix_HaltMusic();
182        Mix_HookMusic(0,0);
183        Mix_CloseAudio();
184        pcm_enable = 0;
185        music_enable = 1;
186}
187
188/*************************************************************************
189**
190** ファむル読み蟌み / 倖郚コマンド呌び出し
191*/
192
193struct WavChunk {
194        WAVFILE* wav;
195        int loop_pt;
196        int *volmod;
197        static void callback(void* userdata, Uint8* stream, int len);
198};
199
200WavChunk wav_playing;
201static int fadetime_total;
202static int fadecount;
203
204void WavChunk::callback(void *userdata, Uint8 *stream, int len)
205{
206        WavChunk* chunk = (WavChunk*)userdata;
207        int count;
208        if (chunk->loop_pt == -2) { // 再生終了埌
209                memset(stream, 0, len);
210                return;
211        }
212
213        char* stream_dup = new char[len];
214        count = chunk->wav->Read( (char*)stream_dup, 4, len/4);
215
216        if (count != len/4) {
217                // 最埌たで再生した
218                if (chunk->loop_pt == -1) { // 終了
219                        chunk->loop_pt = -2;
220                        memset(stream_dup+count*4, 0, len-count*4);
221                } else {
222                        chunk->wav->Seek(chunk->loop_pt);
223                        chunk->wav->Read( (char*)(stream_dup+count*4), 4, len/4-count);
224                }
225        }
226       
227        int cur_vol = (*chunk->volmod)*SDL_MIX_MAXVOLUME/255;
228       
229        if (fadetime_total) {
230                // 音楜を停止䞭 (fade out)
231                int count_total = fadetime_total*(WAVFILE::freq/1000);
232                if (fadecount > count_total || fadetime_total == 1) { // 音楜停止
233                        chunk->loop_pt = -2;
234                        memset(stream, 0, len);
235                        delete[] stream_dup;
236                        return;
237                }
238                cur_vol = cur_vol*(count_total-fadecount)/count_total;
239                fadecount += len/4;
240        }
241
242        SDL_MixAudio(stream, (Uint8*)stream_dup, len, cur_vol);
243        delete[] stream_dup;
244
245        return;
246}
247void bgm_fadeout(int time) {
248        fadecount = 0;
249        if (time <= 0) time = 1;
250        fadetime_total = time;
251}
252
253static SDL_RWops* OpenSDLRW(const char* path);
254static WAVFILE* OpenWaveFile(const char* path);
255void bgm_start(const char* path, int loop_pt) {
256        MuSys* mu = MuSys::GetInstance();
257
258        if (!mu->pcm_enable) return;
259fprintf(stderr,"bgm start %s\n",path);
260        WAVFILE* wav = OpenWaveFile(path);
261        if (wav == NULL) return;
262        Mix_PauseMusic();
263        Mix_HaltMusic();
264        Mix_HookMusic(0,0);
265        /* 前に再生しおいたのを終了 */
266        if (wav_playing.wav != NULL) {
267                delete wav_playing.wav;
268                wav_playing.wav = NULL;
269        }
270        wav_playing.wav = wav;
271        wav_playing.loop_pt = loop_pt;
272        wav_playing.volmod = mu->volmod;
273        fadetime_total = 0;
274        fadecount = 0;
275        Mix_HookMusic( &(WavChunk::callback), (void*)&wav_playing);
276}
277
278void effec_start(int chn, const char* path, int loop, int fadein_time) {
279        MuSys* mu = MuSys::GetInstance();
280
281        if (!mu->pcm_enable) return;
282
283        SDL_RWops* op = OpenSDLRW(path);
284        if (op == NULL) { // ファむルが芋付からない
285                return;
286        }
287        Mix_Pause(chn);
288
289        if (mu->play_chunk[chn] != NULL) {
290                Mix_FreeChunk(mu->play_chunk[chn]);
291        }
292        mu->play_chunk[chn] = Mix_LoadWAV_RW(op, 1);
293        if (fadein_time <= 0) {
294                Mix_Volume(chn, mu->volmod[3]*SDL_MIX_MAXVOLUME/255);
295                Mix_PlayChannel(chn, mu->play_chunk[chn], loop);
296        } else {
297                Mix_Volume(chn, mu->volmod[3]*SDL_MIX_MAXVOLUME/255);
298                Mix_FadeInChannel(chn, mu->play_chunk[chn], loop, fadein_time);
299        }
300}
301
302void MuSys::PlayKoe(const char* path) {
303        if (!pcm_enable) return;
304
305        MuSys* mu = MuSys::GetInstance();
306
307        static char* playing_koedata = NULL;
308        int len = 0;
309        AvgKoeInfo koeinfo;
310        int chn = MIX_PCM_KOE;
311
312        Mix_Pause(chn);
313        Mix_HaltChannel(chn); // これで RWop が解攟されるはず 
314        if (mu->play_chunk[chn] != NULL) {
315                Mix_FreeChunk(mu->play_chunk[chn]);
316                mu->play_chunk[chn] = NULL;
317        }
318
319        if (playing_koedata != NULL) {
320                free(playing_koedata);
321                playing_koedata = NULL;
322        }
323
324        koeinfo = OpenKoeFile(path);
325
326        if (koeinfo.stream == NULL) return;
327        playing_koedata = decode_koe(koeinfo, &len);
328        fclose(koeinfo.stream);
329        if (playing_koedata == NULL) {
330                return;
331        }
332        Mix_Volume(chn, mu->volmod[1]*SDL_MIX_MAXVOLUME/255);
333        mu->play_chunk[chn] = Mix_LoadWAV_RW(SDL_RWFromMem(playing_koedata, len+0x2c), 1);
334        Mix_PlayChannel(chn, mu->play_chunk[chn], 0);
335}
336
337AvgKoeInfo OpenKoeFile(const char* path) {
338        int radix = 10000;
339        /* if (global_system.Version() >= 2) */ radix *= 10;
340        AvgKoeInfo info;
341        info.stream = NULL;
342        info.length = 0;
343        info.offset = 0;
344        if (isdigit(path[0]) && strchr(path,'.') == NULL) { // 数倀 (拡匵子等なし)
345                /* avg32 圢匏の音声アヌカむブのキャッシュを怜玢 */
346                int pointer = atoi(path);
347                int file_no = pointer / radix;
348                int index = pointer % radix;
349                info = FindKoe(file_no, index);
350        } else { // ファむル
351                int length;
352                ARCINFO* arcinfo = FileSearcher::GetInstance()->Find(FileSearcher::KOE, path, ".WPD");
353                if (arcinfo == NULL) return info;
354                info.stream = arcinfo->OpenFile(&length);
355                info.rate = 22050;
356                info.length = length;
357                info.offset = ftell(info.stream);
358                info.type = koe_unknown;
359                delete arcinfo;
360        }
361        return info;
362}
363
364static SDL_RWops* OpenSDLRW(const char* path) {
365        /* たず wav ファむルを探す */
366        FileSearcher* file_searcher = FileSearcher::GetInstance();
367        ARCINFO* info = file_searcher->Find(FileSearcher::WAV, path, ".wav");
368        if (info == NULL) {
369                info = file_searcher->Find(FileSearcher::WAV, path, ".nwa");
370                if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "nwa");
371                if (info != NULL) { // read NWA file
372                        int dummy;
373                        FILE* f = info->OpenFile(&dummy);
374                        static char* d = 0;
375                        int sz;
376                        if (d != 0) delete[] d;
377                        d = NWAFILE::ReadAll(f, sz);
378                        return SDL_RWFromMem(d, sz);
379                }
380        }
381        if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "wav");
382        if (info == NULL) info = file_searcher->Find(FileSearcher::WAV, path, ".ogg");
383        if (info != NULL) {
384                int dummy;
385                FILE* f = info->OpenFile(&dummy);
386                delete info;
387                if (f == NULL) return NULL;
388                SDL_RWops* op = SDL_RWFromFP(f, 1);
389                return op;
390        }
391        return NULL;
392}
393
394static WAVFILE* OpenWaveFile(const char* path) {
395        /* たず wav ファむルを探す */
396        FileSearcher* file_searcher = FileSearcher::GetInstance();
397        ARCINFO* info = file_searcher->Find(FileSearcher::WAV, path, ".wav");
398        if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "wav");
399        if (info != NULL) {
400                int size;
401                FILE* f = info->OpenFile(&size);
402                delete info;
403                if (f == NULL) return NULL;
404                WAVFILE* w = WAVFILE::MakeConverter(new WAVFILE_Stream(f, size));
405                return w;
406        }
407        /* 次に nwa ファむル */
408        info = file_searcher->Find(FileSearcher::WAV, path, ".nwa");
409        if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "nwa");
410        if (info != NULL) {
411                int size;
412                FILE* f = info->OpenFile(&size);
413                delete info;
414                if (f == NULL) return NULL;
415                WAVFILE* w = WAVFILE::MakeConverter(new NWAFILE(f));
416                return w;
417        }
418
419        /* 次に mp3 ファむル */
420        info = file_searcher->Find(FileSearcher::WAV, path, ".mp3");
421        if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "mp3");
422        if (info != NULL) {
423                int size;
424                FILE* f = info->OpenFile(&size);
425                delete info;
426                if (f == NULL) return NULL;
427                MP3FILE* w = new MP3FILE(f, size);
428                if (w->pimpl != NULL) {
429                        return WAVFILE::MakeConverter(w);
430                }
431                delete w;
432        }
433
434        /* 次に ogg ファむル */
435        info = file_searcher->Find(FileSearcher::WAV, path, ".ogg");
436        if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "ogg");
437        if (info != NULL) {
438                int size;
439                FILE* f = info->OpenFile(&size);
440                delete info;
441                if (f == NULL) return NULL;
442                OggFILE* w = new OggFILE(f, size);
443                if (w->pimpl != NULL) {
444                        return WAVFILE::MakeConverter(w);
445                }
446                delete w;
447        }
448        return NULL;
449}
450
Note: See TracBrowser for help on using the browser.