Sound Bakery  v0.1.0
Open-source audio middleware for games
Loading...
Searching...
No Matches
serializer.h
1#pragma once
2
3#include <rttr/type.h>
4#include <cstdint>
5#include <boost/archive/binary_iarchive.hpp>
6#include <boost/archive/binary_oarchive.hpp>
7#include <boost/archive/text_iarchive.hpp>
8#include <boost/archive/text_oarchive.hpp>
9#include <boost/archive/xml_iarchive.hpp>
10#include <boost/archive/xml_oarchive.hpp>
11#include <boost/archive/yaml_iarchive.hpp>
12#include <boost/archive/yaml_oarchive.hpp>
13#include <boost/serialization/binary_object.hpp>
14
15#include "sound_bakery/system.h"
16#include "sound_bakery/node/bus/bus.h"
17#include "sound_bakery/core/database/database_object.h"
18#include "sound_bakery/core/object/object_owner.h"
19#include "sound_bakery/event/event.h"
20#include "sound_bakery/sound/sound.h"
21#include "sound_bakery/soundbank/soundbank.h"
22
23namespace sbk::core
24{
25 class object;
26}
27
28namespace sbk::engine
29{
30 class soundbank;
31 class system;
32} // namespace sbk::engine
33
34namespace sbk::core::serialization
35{
36 auto make_default_variant(const rttr::type& type) -> rttr::variant;
37 auto read_binary_file(const std::filesystem::path& file) -> std::vector<uint8_t>;
38
44 struct SB_CLASS serialized_version
45 {
46 unsigned int major = SBK_VERSION_MAJOR;
47 unsigned int minor = SBK_VERSION_MINOR;
48 unsigned int patch = SBK_VERSION_PATCH;
49
50 auto version_compatible() const -> bool { return major == SBK_VERSION_MAJOR && minor == SBK_VERSION_MINOR; }
51
52 template <class archive_class>
53 void serialize(archive_class& archive, const unsigned int version)
54 {
55 archive & boost::serialization::make_nvp("Major", major);
56 archive & boost::serialization::make_nvp("Minor", minor);
57 archive & boost::serialization::make_nvp("Patch", patch);
58 }
59 };
60
64 struct SB_CLASS serialized_type
65 {
66 serialized_type() = default;
67 serialized_type(const rttr::type& type) : typeString(type.get_name().data()) {}
68
69 std::string typeString;
70
71 auto get_type() const -> rttr::type { return rttr::type::get_by_name(typeString); }
72
73 template <class archive_class>
74 void serialize(archive_class& archive, const unsigned int fileVersion)
75 {
76 archive & boost::serialization::make_nvp("Type", typeString);
77 }
78 };
79
83 struct SB_CLASS serialized_object
84 {
85 serialized_object() = delete;
86 serialized_object(const std::shared_ptr<sbk::core::database_object>& object, sbk::core::object_owner* objectOwner)
87 : object(object), objectOwner(objectOwner)
88 {
89 if (object)
90 {
91 type.typeString = object->get_object_type().get_name().data();
92 id = object->get_database_id();
93 }
94 }
95
96 serialized_type type;
97 sbk_id id = 0;
98
99 std::shared_ptr<sbk::core::database_object> object;
100 sbk::core::object_owner* objectOwner = nullptr;
101
102 template <class archive_class>
103 void serialize(archive_class& archive, const unsigned int v)
104 {
105 archive & boost::serialization::make_nvp("Type", type);
106 archive & boost::serialization::make_nvp("ID", id);
107
108 if (typename archive_class::is_loading())
109 {
110 BOOST_ASSERT(objectOwner != nullptr);
111 std::weak_ptr<sbk::core::database_object> foundObject = sbk::engine::system::get()->try_find(id);
112
113 if (foundObject.expired())
114 {
115 object = objectOwner->create_database_object(type.get_type(), false);
116 object->set_flags(object_flag_loading);
117 }
118 else
119 {
120 object = foundObject.lock();
121 objectOwner->add_reference_to_object(object);
122 }
123 }
124
125 BOOST_ASSERT(object);
126 archive & boost::serialization::make_nvp("ObjectData", *object.get());
127
128 if (typename archive_class::is_loading())
129 {
130 BOOST_ASSERT(sbk::engine::system::get() != nullptr);
131 object->clear_flags(object_flag_loading);
132 sbk::engine::system::get()->add_object_to_database(object);
133 }
134 }
135 };
136
143 {
145 serialized_standalone_object(const std::shared_ptr<sbk::core::database_object>& object, sbk::core::object_owner* objectOwner)
146 : object(object, objectOwner){}
147
148 serialized_version version;
150
151 template <class archive_class>
152 void serialize(archive_class& archive, const unsigned int v)
153 {
154 archive & boost::serialization::make_nvp("Version", version);
155 BOOST_ASSERT_MSG(version.version_compatible(), "Cross version serialization not implemented yet");
156 archive & boost::serialization::make_nvp("Object", object);
157 }
158 };
159
160 struct SB_CLASS serialized_system
161 {
162 serialized_system() = delete;
163 serialized_system(const std::shared_ptr<sbk::core::database_object>& object, sbk::core::object_owner* objectOwner){}
164
165 serialized_version version;
166
167 template <class archive_class>
168 void serialize(archive_class& archive, const unsigned int v)
169 {
170 sbk::engine::system* system = sbk::engine::system::get();
171 BOOST_ASSERT(system != nullptr);
172
173 archive & boost::serialization::make_nvp("Version", version);
174 BOOST_ASSERT_MSG(version.version_compatible(), "Cross version serialization not implemented yet");
175 archive & boost::serialization::make_nvp("System", *system);
176 }
177 };
178
179 template <class object_class>
181 {
182 serialized_object_vector() = delete;
183 serialized_object_vector(sbk::core::object_owner* objectOwner) : objectOwner(objectOwner) {}
184 serialized_object_vector(const std::vector<std::shared_ptr<object_class>>& objects)
185 : objects(objects), count(objects.size()), objectOwner(nullptr) {}
186
187 sbk::core::object_owner* objectOwner = nullptr;
188 std::size_t count = 0;
189 std::vector<std::shared_ptr<object_class>> objects;
190
191 template <class archive_class>
192 void serialize(archive_class& archive, const unsigned int v)
193 {
194 archive & boost::serialization::make_nvp("Count", count);
195
196 for (std::size_t index = 0; index < count; ++index)
197 {
198 if (typename archive_class::is_loading())
199 {
200 serialized_object serializedObject({}, objectOwner);
201 archive & boost::serialization::make_nvp("Object", serializedObject);
202 }
203 else
204 {
205 std::shared_ptr<sbk::core::database_object> convertedObject =
206 std::static_pointer_cast<sbk::core::database_object, object_class>(objects[index]);
207 serialized_object serializedObject(convertedObject, objectOwner);
208 archive & boost::serialization::make_nvp("Object", serializedObject);
209 }
210 }
211 }
212 };
213
214 struct SB_CLASS serialized_sound
215 {
216 serialized_sound() = delete;
217 serialized_sound(const std::shared_ptr<sbk::engine::sound>& sound) : sound(sound) {}
218 serialized_sound(const std::shared_ptr<sbk::core::database_object>& databaseSound)
219 : sound(std::static_pointer_cast<sbk::engine::sound, sbk::core::database_object>(databaseSound)) {}
220
221 std::shared_ptr<sbk::engine::sound> sound;
222
223 template <class archive_class>
224 void serialize(archive_class& archive, const unsigned int v)
225 {
226 BOOST_ASSERT(sound);
227
228 if (typename archive_class::is_saving())
229 {
230 const sbk::engine::encoding_sound encodingSound = sound->get_encoding_sound_data();
231 const std::vector<uint8_t> buffer = read_binary_file(encodingSound.encodedSoundPath);
232 std::size_t size = buffer.size();
233
234 archive & boost::serialization::make_nvp("Size", size);
235 archive & boost::serialization::make_nvp("Data", boost::serialization::make_binary_object(buffer.data(), size));
236 }
237 else
238 {
239 std::size_t size = 0;
240 archive & boost::serialization::make_nvp("Size", size);
241
242 sbk::engine::raw_sound_ptr rawSound(std::malloc(size));
243 archive & boost::serialization::make_nvp("Data", boost::serialization::make_binary_object(rawSound.get(), size));
244
245 sound->set_raw_sound_data(rawSound, size);
246 }
247 }
248 };
249
250 template<>
252 {
253 serialized_object_vector() = delete;
254 serialized_object_vector(sbk::core::object_owner* objectOwner) : objectOwner(objectOwner) {}
255 serialized_object_vector(const std::vector<std::shared_ptr<sbk::engine::sound>>& objects)
256 : objects(objects), count(objects.size()), objectOwner(nullptr)
257 {
258 }
259
260 sbk::core::object_owner* objectOwner = nullptr;
261 std::size_t count = 0;
262 std::vector<std::shared_ptr<sbk::engine::sound>> objects;
263
264 template <class archive_class>
265 void serialize(archive_class& archive, const unsigned int v)
266 {
267 archive& boost::serialization::make_nvp("Count", count);
268
269 for (std::size_t index = 0; index < count; ++index)
270 {
271 if (typename archive_class::is_loading())
272 {
273 serialized_object serializedObject({}, objectOwner);
274 archive & boost::serialization::make_nvp("Object", serializedObject);
275
276 serialized_sound serializedSound(serializedObject.object);
277 archive & boost::serialization::make_nvp("RawSound", serializedSound);
278 }
279 else
280 {
281 serialized_object serializedObject(objects[index], objectOwner);
282 archive & boost::serialization::make_nvp("Object", serializedObject);
283
284 serialized_sound serializedSound(objects[index]);
285 archive & boost::serialization::make_nvp("RawSound", serializedSound);
286 }
287 }
288 }
289 };
290
291 struct SB_CLASS serialized_soundbank
292 {
293 serialized_soundbank() = delete;
294 serialized_soundbank(const std::shared_ptr<sbk::core::database_object>& object, sbk::core::object_owner* objectOwner)
295 : serializedSoundbank(object, objectOwner)
296 {
297 }
298
299 serialized_version version;
300 serialized_object serializedSoundbank;
301
302 template <class archive_class>
303 void serialize(archive_class& archive, const unsigned int v)
304 {
305 archive & boost::serialization::make_nvp("Version", version);
306 BOOST_ASSERT_MSG(version.version_compatible(), "Cross version serialization not implemented yet");
307
308 archive & boost::serialization::make_nvp("Soundbank", serializedSoundbank);
309 BOOST_ASSERT_MSG(serializedSoundbank.object->get_object_type().is_derived_from<sbk::engine::soundbank>(), "Must be saving a soundbank type");
310
311 sbk::engine::soundbank* soundbank = serializedSoundbank.object->try_convert_object<sbk::engine::soundbank>();
312
313 if (typename archive_class::is_loading())
314 {
315 serialized_object_vector<sbk::engine::sound> serializedSounds(soundbank);
316 serialized_object_vector<sbk::engine::node_base> serializedNodes(soundbank);
317 serialized_object_vector<sbk::engine::event> serializedEvents(soundbank);
318
319 archive& boost::serialization::make_nvp("Sounds", serializedSounds);
320 archive& boost::serialization::make_nvp("Nodes", serializedNodes);
321 archive& boost::serialization::make_nvp("Events", serializedEvents);
322
323 if (soundbank->get_master_soundbank())
324 {
325 serialized_object_vector<sbk::engine::bus> serializedBusses(soundbank);
326 serialized_object_vector<sbk::engine::int_parameter> serializedIntParameters(soundbank);
327 serialized_object_vector<sbk::engine::float_parameter> serializedFloatParameters(soundbank);
328 serialized_object_vector<sbk::engine::named_parameter> serializedNamedParameters(soundbank);
329
330 archive & boost::serialization::make_nvp("Busses", serializedBusses);
331 archive & boost::serialization::make_nvp("IntParameters", serializedIntParameters);
332 archive & boost::serialization::make_nvp("FloatParameters", serializedFloatParameters);
333 archive & boost::serialization::make_nvp("NamedParameters", serializedNamedParameters);
334 }
335 }
336 else
337 {
338 sbk::engine::soundbank_dependencies soundbankDependencies = soundbank->gather_dependencies();
339
340 serialized_object_vector<sbk::engine::sound> serializedSounds(soundbankDependencies.sounds);
341 serialized_object_vector<sbk::engine::node_base> serializedNodes(soundbankDependencies.nodes);
342 serialized_object_vector<sbk::engine::event> serializedEvents(soundbankDependencies.events);
343
344 archive & boost::serialization::make_nvp("Sounds", serializedSounds);
345 archive & boost::serialization::make_nvp("Nodes", serializedNodes);
346 archive & boost::serialization::make_nvp("Events", serializedEvents);
347
348 if (soundbank->get_master_soundbank())
349 {
350 serialized_object_vector<sbk::engine::bus> serializedBusses(soundbankDependencies.busses);
351 serialized_object_vector<sbk::engine::int_parameter> serializedIntParameters(soundbankDependencies.intParameters);
352 serialized_object_vector<sbk::engine::float_parameter> serializedFloatParameters(soundbankDependencies.floatParameters);
353 serialized_object_vector<sbk::engine::named_parameter> serializedNamedParameters(soundbankDependencies.namedParameters);
354
355 archive & boost::serialization::make_nvp("Busses", serializedBusses);
356 archive & boost::serialization::make_nvp("IntParameters", serializedIntParameters);
357 archive & boost::serialization::make_nvp("FloatParameters", serializedFloatParameters);
358 archive & boost::serialization::make_nvp("NamedParameters", serializedNamedParameters);
359 }
360 }
361 }
362 };
363
365 {
366 serialized_child_class() = default;
367 serialized_child_class(rttr::variant& variant) : child(variant), type(variant.get_type())
368 {
369 BOOST_ASSERT(variant.is_valid());
370 BOOST_ASSERT(type.is_class());
371 }
372
373 rttr::variant& child;
374 rttr::type type;
375
376 template <class archive_class>
377 void serialize(archive_class& archive, const unsigned int version)
378 {
379 for (rttr::property property : type.get_properties())
380 {
381 BOOST_ASSERT(property.is_valid());
382 BOOST_ASSERT(property.get_type().is_valid());
383
384 if (typename archive_class::is_loading())
385 {
386 rttr::variant loaded = make_default_variant(property.get_type());
387 BOOST_ASSERT(loaded.is_valid());
388 archive & boost::serialization::make_nvp(property.get_name().data(), loaded);
389 loaded.convert(property.get_type());
390 BOOST_ASSERT(loaded.get_type() == property.get_type());
391 property.set_value(child, loaded);
392 }
393 else
394 {
395 rttr::variant variantToSave = property.get_value(child);
396 archive & boost::serialization::make_nvp(property.get_name().data(), variantToSave);
397 }
398 }
399 }
400 };
401
403 {
405 serialized_sequential_container(rttr::variant& variant)
406 : originalVariant(variant), view(variant.create_sequential_view()), valueType(view.get_value_type())
407 {
408 }
409
410 rttr::variant& originalVariant;
411 rttr::variant_sequential_view view;
412 rttr::type valueType;
413
414 template <class archive_class>
415 void serialize(archive_class& archive, const unsigned int version)
416 {
417 if (typename archive_class::is_loading())
418 {
419 size_t size = 0;
420 archive & boost::serialization::make_nvp("Count", size);
421
422 view.set_size(size);
423
424 const bool needToCreate = size == 0;
425
426 for (size_t index = 0; index < size; ++index)
427 {
428 rttr::variant loadedVariant = make_default_variant(valueType);
429 BOOST_ASSERT(loadedVariant.is_valid());
430 archive & boost::serialization::make_nvp("Item", loadedVariant);
431
432 loadedVariant.convert((rttr::type)valueType);
433 if (needToCreate)
434 {
435 view.insert(view.begin() + index, loadedVariant);
436 }
437 else
438 {
439 view.set_value(index, loadedVariant);
440 }
441 }
442 }
443 else
444 {
445 size_t size = view.get_size();
446 archive & boost::serialization::make_nvp("Count", size);
447
448 for (rttr::variant item : view)
449 {
450 archive & boost::serialization::make_nvp("Item", item);
451 }
452 }
453 }
454 };
455
457 {
459 serialized_associative_container(rttr::variant& variant)
460 : originalVariant(variant),
461 view(variant.create_associative_view()),
462 keyType(view.get_key_type()),
463 valueType(view.is_key_only_type() ? view.get_key_type()
464 : view.get_value_type())
465 { }
466
467 rttr::variant& originalVariant;
468 rttr::variant_associative_view view;
469 rttr::type valueType;
470 rttr::type keyType;
471
472 template <class archive_class>
473 void serialize(archive_class& archive, const unsigned int version)
474 {
475 if (typename archive_class::is_loading())
476 {
477 size_t size = 0;
478 archive& boost::serialization::make_nvp("Count", size);
479
480 view.clear();
481
482 for (std::size_t index = 0; index < size; ++index)
483 {
484 if (view.is_key_only_type())
485 {
486 rttr::variant loadedKey = make_default_variant(keyType);
487 archive & boost::serialization::make_nvp("Key", loadedKey);
488 loadedKey.convert((rttr::type)keyType);
489 view.insert(loadedKey);
490 }
491 else
492 {
493 std::pair<rttr::variant, rttr::variant> loadedPair(make_default_variant(keyType), make_default_variant(valueType));
494 archive & boost::serialization::make_nvp("KeyValue", loadedPair);
495 loadedPair.first.convert((rttr::type)keyType);
496 loadedPair.second.convert((rttr::type)valueType);
497 view.insert(loadedPair.first, loadedPair.second);
498 }
499 }
500 }
501 else
502 {
503 size_t size = view.get_size();
504 archive & boost::serialization::make_nvp("Count", size);
505
506 for (rttr::variant item : view)
507 {
508 std::pair<rttr::variant, rttr::variant> valuePair =
509 item.convert<std::pair<rttr::variant, rttr::variant>>();
510
511 if (view.is_key_only_type())
512 {
513 rttr::variant key = valuePair.first.extract_wrapped_value();
514 archive & boost::serialization::make_nvp("Key", key);
515 }
516 else
517 {
518 archive& boost::serialization::make_nvp("KeyValue", valuePair);
519 }
520 }
521 }
522 }
523 };
524
525 template <class load_archive,
526 class save_archive,
527 std::ios_base::openmode inputMode,
528 std::ios_base::openmode outputMode>
529 class SB_CLASS boost_serializer
530 {
531 public:
532 template <class serialize_class>
533 auto save_database_object(std::shared_ptr<sbk::core::database_object>& object, const std::filesystem::path& file) -> sb_result
534 {
535 SC_CHECK_ARG(object);
536 SC_CHECK(!file.empty(), MA_INVALID_FILE);
537
538 std::ofstream outputStream(file, outputMode);
539 save_archive archive(outputStream);
540 serialize_class serialize(object, nullptr);
541
542 archive & boost::serialization::make_nvp("Data", serialize);
543 return MA_SUCCESS;
544 }
545
546 auto save_system(const std::filesystem::path& file) -> sb_result
547 {
548 SC_CHECK(!file.empty(), MA_INVALID_FILE);
549
550 std::ofstream outputStream(file, outputMode);
551 save_archive archive(outputStream);
552 serialized_system serialize({}, nullptr);
553
554 archive & boost::serialization::make_nvp("System", serialize);
555 return MA_SUCCESS;
556 }
557
558 template <class serialize_class>
559 auto load_object(sbk::core::object_owner* objectOwner, const std::filesystem::path& file) -> sb_result
560 {
561 SC_CHECK(std::filesystem::exists(file), MA_INVALID_FILE);
562
563 std::ifstream inputStream(file, inputMode);
564 load_archive archive(inputStream);
565 serialize_class object({}, objectOwner);
566
567 archive & boost::serialization::make_nvp("Data", object);
568 return MA_SUCCESS;
569 }
570 };
571
576} // namespace sbk::core::serialization
577
579
580namespace boost
581{
582 namespace serialization
583 {
584 template <class archive_class, typename T>
585 void serialize_variant(archive_class& archive, rttr::variant& variant)
586 {
587 if (typename archive_class::is_loading())
588 {
589 T loadedValue;
590 archive & boost::serialization::make_nvp("Value", loadedValue);
591 variant = loadedValue;
592 }
593 else
594 {
595 T valueToSave = variant.convert<T>();
596 archive & boost::serialization::make_nvp("Value", valueToSave);
597 }
598 }
599
600 template <class archive_class>
601 void serialize_variant_string_view(archive_class& archive, rttr::variant& variant)
602 {
603 if (typename archive_class::is_loading())
604 {
605 std::string loaded;
606 archive & boost::serialization::make_nvp("Value", loaded);
607 variant = loaded;
608 }
609 else
610 {
611 std::string_view valueToSave = variant.convert<std::string_view>();
612 std::string valueToSaveConverted(valueToSave);
613 archive & boost::serialization::make_nvp("Value", valueToSaveConverted);
614 }
615 }
616
617 template <class archive_class>
618 void serialize(archive_class& archive, rttr::variant& variant, const unsigned int version)
619 {
620 const rttr::type type = variant.get_type();
621 BOOST_ASSERT_MSG(type.is_valid(), "Type must be valid to load correctly");
622
623 if (type.is_arithmetic())
624 {
625 if (type == rttr::type::get<bool>())
626 {
627 serialize_variant<archive_class, bool>(archive, variant);
628 }
629 else if (type == rttr::type::get<int8_t>())
630 {
631 serialize_variant<archive_class, int8_t>(archive, variant);
632 }
633 else if (type == rttr::type::get<int16_t>())
634 {
635 serialize_variant<archive_class, int16_t>(archive, variant);
636 }
637 else if (type == rttr::type::get<int32_t>())
638 {
639 serialize_variant<archive_class, int32_t>(archive, variant);
640 }
641 else if (type == rttr::type::get<int64_t>())
642 {
643 serialize_variant<archive_class, int64_t>(archive, variant);
644 }
645 else if (type == rttr::type::get<uint8_t>())
646 {
647 serialize_variant<archive_class, uint8_t>(archive, variant);
648 }
649 else if (type == rttr::type::get<uint16_t>())
650 {
651 serialize_variant<archive_class, uint16_t>(archive, variant);
652 }
653 else if (type == rttr::type::get<uint32_t>())
654 {
655 serialize_variant<archive_class, uint32_t>(archive, variant);
656 }
657 else if (type == rttr::type::get<uint64_t>())
658 {
659 serialize_variant<archive_class, uint64_t>(archive, variant);
660 }
661 else if (type == rttr::type::get<float>())
662 {
663 serialize_variant<archive_class, float>(archive, variant);
664 }
665 else if (type == rttr::type::get<double>())
666 {
667 serialize_variant<archive_class, double>(archive, variant);
668 }
669 }
670 else if (type == rttr::type::get<std::string>())
671 {
672 serialize_variant<archive_class, std::string>(archive, variant);
673 }
674 else if (type == rttr::type::get<std::string_view>())
675 {
676 serialize_variant_string_view<archive_class>(archive, variant);
677 }
678 else if (type.is_wrapper())
679 {
680 variant = variant.extract_wrapped_value();
681 serialize(archive, variant, version);
682 }
683 else if (type.is_enumeration())
684 {
685 const rttr::enumeration enumeration = type.get_enumeration();
686
687 if (typename archive_class::is_loading())
688 {
689 std::string loadedStringValue;
690 archive& boost::serialization::make_nvp("Value", loadedStringValue);
691 variant = enumeration.name_to_value(loadedStringValue);
692 }
693 else
694 {
695 const rttr::string_view enumValueName = enumeration.value_to_name(variant);
696
697 if (!enumValueName.empty())
698 {
699 std::string savingString = enumValueName.data();
700 archive& boost::serialization::make_nvp("Value", savingString);
701 }
702 }
703 }
704 else if (type.is_associative_container())
705 {
706 sbk::core::serialization::serialized_associative_container serializedAssociativeContainer(variant);
707 archive & boost::serialization::make_nvp("AssociativeContainer", serializedAssociativeContainer);
708 }
709 else if (type.is_sequential_container())
710 {
711 sbk::core::serialization::serialized_sequential_container serializedSequentialContainer(variant);
712 archive & boost::serialization::make_nvp("SeqContainer", serializedSequentialContainer);
713 }
714 else if (type.is_class())
715 {
717 archive & boost::serialization::make_nvp("Child", childClass);
718 }
719 }
720
721 } // namespace serialization
722} // namespace boost
Creates, owns and tracks objects.
Definition object_owner.h:13
auto create_database_object(const rttr::type &type, bool addToDatabase=true) -> std::shared_ptr< database_object >
Definition object_owner.cpp:74
Base object that all sound Bakery objects should inherit from.
Definition object.h:23
Definition property.h:9
Definition sound.h:35
Packages events and dependent objects and sounds.
Definition soundbank.h:35
Manager of the whole Sound Bakery.
Definition system.h:44
Serializes an object type and the object's data.
Definition serializer.h:84
Header for an object that saves to a single file.
Definition serializer.h:143
Serializes an object type so upon loading, we create the correct type.
Definition serializer.h:65
Stores the version of Sound Bakery.
Definition serializer.h:45
Data for converting a sound to an encoded format.
Definition sound.h:15
Wraps all events, objects, and sounds needed to package a soundbank.
Definition soundbank.h:20