Cogs.Core
WaveSoundLoader.cpp
1#include "WaveSoundLoader.h"
2
3#include "Context.h"
4
5#include "Resources/ResourceStore.h"
6
7#include "Foundation/Logging/Logger.h"
8
9#define fourccRIFF 'FFIR'
10#define fourccDATA 'atad'
11#define fourccFMT ' tmf'
12#define fourccWAVE 'EVAW'
13#define fourccXWMA 'AMWX'
14#define fourccDPDS 'sdpd'
15
16namespace
17{
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("WaveSoundLoader");
19}
20
21namespace
22{
23 template<typename T>
24 bool read(uint8_t * & begin, uint8_t * end, T & t)
25 {
26 if (sizeof(T) >= (end - begin)) return false;
27
28 std::memcpy(&t, begin, sizeof(T));
29
30 begin += sizeof(T);
31
32 return true;
33 }
34
35 bool findChunk(uint8_t * begin, uint8_t * end, uint32_t fourCC, uint32_t & chunkSize, uint32_t & chunkPosition)
36 {
37 uint32_t RIFFDataSize;
38 uint32_t fileType;
39 uint32_t offset = 0;
40
41 while (true) {
42 uint32_t chunkType;
43 if (!read(begin, end, chunkType)) {
44 return false;
45 }
46
47 uint32_t chunkDataSize;
48 if (!read(begin, end, chunkDataSize)) {
49 return false;
50 }
51 switch (chunkType) {
52 case fourccRIFF:
53 RIFFDataSize = chunkDataSize;
54 chunkDataSize = 4;
55 if (!read(begin, end, fileType)) {
56 return false;
57 }
58 break;
59
60 default:
61 begin += chunkDataSize;
62 break;
63 }
64
65 offset += sizeof(uint32_t) * 2;
66
67 if (chunkType == fourCC) {
68 chunkSize = chunkDataSize;
69 chunkPosition = offset;
70 return true;
71 }
72
73 offset += chunkDataSize;
74 }
75
76 return true;
77 }
78
79 bool readChunkData(uint8_t * begin, size_t size, void * buffer, uint32_t bufferSize, uint32_t bufferOffset)
80 {
81 if (bufferOffset >= size) return false;
82
83 std::memcpy(buffer, begin + bufferOffset, bufferSize);
84
85 return true;
86 }
87}
88
89bool Cogs::Core::WaveSoundLoader::canLoad(Context * /*context*/, const SoundLoadInfo & /*loadInfo*/)
90{
91 return true;
92}
93
94bool Cogs::Core::WaveSoundLoader::load(Context * context, const SoundLoadInfo & loadInfo)
95{
96 auto content = context->resourceStore->getResourceContents(loadInfo.resourcePath);
97
98 if (content.empty()) {
99 LOG_ERROR(logger, "Could not open %s.", loadInfo.resourcePath.c_str());
100 return false;
101 }
102
103 uint32_t chunkSize;
104 uint32_t chunkPosition;
105
106 // Check the file type, should be fourccWAVE or 'XWMA'
107 findChunk(content.data(), content.data() + content.size(), fourccRIFF, chunkSize, chunkPosition);
108
109 uint32_t fileType;
110 readChunkData(content.data(), content.size(), &fileType, sizeof(fileType), chunkPosition);
111
112 if (fileType != fourccWAVE) {
113 LOG_ERROR(logger, "Only WAVE format supported.");
114 return false;
115 }
116
117 auto sound = (Sound *)(loadInfo.handle.get());
118
119 // Find format information
120 if (!findChunk(content.data(), content.data() + content.size(), fourccFMT, chunkSize, chunkPosition)) {
121 LOG_ERROR(logger, "Could not locate sound format information in %s.", loadInfo.resourcePath.c_str());
122 return false;
123 }
124
125 readChunkData(content.data(), content.size(), &sound->format, chunkSize, chunkPosition);
126
127 // Find and read sound data.
128 if (!findChunk(content.data(), content.data() + content.size(), fourccDATA, chunkSize, chunkPosition)) {
129 LOG_ERROR(logger, "Could not locate data chunk in sound.");
130 return false;
131 }
132
133 if (!chunkSize) {
134 LOG_WARNING(logger, "Empty sound data specified.");
135 }
136
137 sound->data.resize(chunkSize);
138 readChunkData(content.data(), content.size(), sound->data.data(), chunkSize, chunkPosition);
139
140 return true;
141}
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180