1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2009 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 // -----------------------------------------------------------------------
26
27 #include "systems/base/voice_cache.h"
28
29 #include <boost/algorithm/string.hpp>
30 #include <boost/filesystem/path.hpp>
31 #include <iomanip>
32 #include <sstream>
33 #include <string>
34
35 #include "systems/base/koepac_voice_archive.h"
36 #include "systems/base/nwk_voice_archive.h"
37 #include "systems/base/ovk_voice_archive.h"
38 #include "systems/base/ovk_voice_sample.h"
39 #include "systems/base/sound_system.h"
40 #include "systems/base/system.h"
41 #include "systems/base/voice_archive.h"
42 #include "utilities/exception.h"
43
44 const int ID_RADIX = 100000;
45
46 using boost::iends_with;
47 using std::string;
48
49 namespace fs = boost::filesystem;
50
VoiceCache(SoundSystem & sound_system)51 VoiceCache::VoiceCache(SoundSystem& sound_system)
52 : sound_system_(sound_system), file_cache_(7) {}
53
~VoiceCache()54 VoiceCache::~VoiceCache() {}
55
Find(int id)56 std::shared_ptr<VoiceSample> VoiceCache::Find(int id) {
57 int file_no = id / ID_RADIX;
58 int index = id % ID_RADIX;
59
60 std::shared_ptr<VoiceArchive> archive = file_cache_.fetch(file_no);
61 if (archive) {
62 return archive->FindSample(index);
63 } else {
64 archive = FindArchive(file_no);
65 if (archive) {
66 // Cache for later use.
67 file_cache_.insert(file_no, archive);
68 return archive->FindSample(index);
69 } else {
70 // There aren't any archives with |file_no|. Look for an individual file
71 // instead.
72 std::shared_ptr<VoiceSample> sample =
73 FindUnpackedSample(file_no, index);
74 if (sample) {
75 return sample;
76 } else {
77 throw rlvm::Exception("No such voice archive or sample");
78 }
79 }
80 }
81 }
82
FindArchive(int file_no) const83 std::shared_ptr<VoiceArchive> VoiceCache::FindArchive(int file_no) const {
84 std::ostringstream oss;
85 oss << "z" << std::setw(4) << std::setfill('0') << file_no;
86
87 fs::path file =
88 sound_system_.system().FindFile(oss.str(), KOE_ARCHIVE_FILETYPES);
89 if (file.empty()) {
90 return std::shared_ptr<VoiceArchive>();
91 }
92
93 string file_str = file.string();
94 if (iends_with(file_str, "ovk")) {
95 return std::shared_ptr<VoiceArchive>(new OVKVoiceArchive(file, file_no));
96 } else if (iends_with(file_str, "nwk")) {
97 return std::shared_ptr<VoiceArchive>(new NWKVoiceArchive(file, file_no));
98 } else if (iends_with(file_str, "koe")) {
99 return std::shared_ptr<VoiceArchive>(
100 new KOEPACVoiceArchive(file, file_no));
101 }
102
103 return std::shared_ptr<VoiceArchive>();
104 }
105
FindUnpackedSample(int file_no,int index) const106 std::shared_ptr<VoiceSample> VoiceCache::FindUnpackedSample(int file_no,
107 int index) const {
108 // Loose voice files are packed into directories, like:
109 // /KOE/0008/z000800073.ogg. We only need to search for the filename though.
110 std::ostringstream oss;
111 oss << "z" << std::setw(4) << std::setfill('0') << file_no << std::setw(5)
112 << std::setfill('0') << index;
113
114 fs::path file =
115 sound_system_.system().FindFile(oss.str(), KOE_LOOSE_FILETYPES);
116 string file_str = file.string();
117
118 if (iends_with(file_str, "ogg")) {
119 return std::shared_ptr<VoiceSample>(new OVKVoiceSample(file));
120 }
121
122 return std::shared_ptr<VoiceSample>();
123 }
124