1 /*
2 * soundfactory.c - sound factory
3 * Copyright (C) 2010 Alexandre Martins <alemartf(at)gmail(dot)com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "soundfactory.h"
21 #include "audio.h"
22 #include "stringutil.h"
23 #include "util.h"
24 #include "logfile.h"
25 #include "resourcemanager.h"
26 #include "osspec.h"
27 #include "hashtable.h"
28 #include "nanoparser/nanoparser.h"
29
30 /* storage */
31 typedef struct factorysound_t factorysound_t;
32 struct factorysound_t {
33 sound_t *data;
34 };
35 HASHTABLE_GENERATE_CODE(factorysound_t);
36 static hashtable_factorysound_t *samples;
37 static factorysound_t* factorysound_create();
38 static void factorysound_destroy(factorysound_t *f);
39
40 /* file reader stuff (nanoparser) */
41 static void load_samples_table();
42 static int traverse(const parsetree_statement_t *stmt);
43 static int traverse_sound(const parsetree_statement_t *stmt, void *factorysound);
44
45
46
47
48 /* public functions */
49
50 /* initializes the sound factory */
soundfactory_init()51 void soundfactory_init()
52 {
53 samples = hashtable_factorysound_t_create(factorysound_destroy);
54 load_samples_table();
55 }
56
57 /* releases the sound factory */
soundfactory_release()58 void soundfactory_release()
59 {
60 samples = hashtable_factorysound_t_destroy(samples);
61 }
62
63 /* given a sound name, returns the corresponding sound effect */
soundfactory_get(const char * sound_name)64 sound_t *soundfactory_get(const char *sound_name)
65 {
66 factorysound_t *f = hashtable_factorysound_t_find(samples, sound_name);
67
68 if(f == NULL) {
69 /* if no sound is found, consider sound_name as a file path */
70 char abs_path[1024];
71 resource_filepath(abs_path, sound_name, sizeof(abs_path), RESFP_READ);
72 return sound_load(sound_name);
73 }
74 else
75 return f->data;
76 }
77
78
79
80
81 /* private functions */
82
83 /* traverses a sound configuration file */
traverse(const parsetree_statement_t * stmt)84 int traverse(const parsetree_statement_t *stmt)
85 {
86 const char *identifier;
87 const parsetree_parameter_t *param_list;
88 const parsetree_parameter_t *p1, *p2;
89 const char *sound_name = "null";
90 factorysound_t *f = NULL;
91
92 identifier = nanoparser_get_identifier(stmt);
93 param_list = nanoparser_get_parameter_list(stmt);
94
95 if(str_icmp(identifier, "sample") == 0) {
96 p1 = nanoparser_get_nth_parameter(param_list, 1);
97 p2 = nanoparser_get_nth_parameter(param_list, 2);
98
99 nanoparser_expect_string(p1, "soundfactory: must provide sample name");
100 nanoparser_expect_program(p2, "soundfactory: must provide sample attributes");
101
102 sound_name = nanoparser_get_string(p1);
103 if(NULL == hashtable_factorysound_t_find(samples, sound_name)) {
104 f = factorysound_create();
105 nanoparser_traverse_program_ex(nanoparser_get_program(p2), (void*)f, traverse_sound);
106 hashtable_factorysound_t_add(samples, sound_name, f);
107 }
108
109 logfile_message("soundfactory: loaded sample '%s'", sound_name);
110 }
111 else
112 fatal_error("soundfactory: unknown identifier '%s' at the sound definition file. Valid keywords: 'sample'");
113
114 return 0;
115 }
116
117 /* traverses a sound block */
traverse_sound(const parsetree_statement_t * stmt,void * factorysound)118 int traverse_sound(const parsetree_statement_t *stmt, void *factorysound)
119 {
120 factorysound_t *f = (factorysound_t*)factorysound;
121 const char *identifier;
122 const parsetree_parameter_t *param_list;
123 const parsetree_parameter_t *p1;
124 int n;
125
126 identifier = nanoparser_get_identifier(stmt);
127 param_list = nanoparser_get_parameter_list(stmt);
128
129 if(str_icmp(identifier, "source_file") == 0) {
130 n = nanoparser_get_number_of_parameters(param_list);
131 if(n == 1) {
132 p1 = nanoparser_get_nth_parameter(param_list, 1);
133 nanoparser_expect_string(p1, "soundfactory: must provide sound file path (source_file)");
134 f->data = sound_load(nanoparser_get_string(p1));
135 }
136 else
137 fatal_error("soundfactory: source_file accepts only one parameter.");
138 }
139 else
140 fatal_error("soundfactory: unknown identifier '%s' defined at a sound block. Valid keywords: 'source_file'", identifier);
141
142 return 0;
143 }
144
145 /* loads the samples table */
load_samples_table()146 void load_samples_table()
147 {
148 parsetree_program_t *s = NULL;
149 char abs_path[1024];
150
151 logfile_message("soundfactory: loading the samples table...");
152 resource_filepath(abs_path, "config/samples.def", sizeof(abs_path), RESFP_READ);
153
154 s = nanoparser_construct_tree(abs_path);
155 nanoparser_traverse_program(s, traverse);
156 s = nanoparser_deconstruct_tree(s);
157 }
158
159 /* creates a new factorysound object */
factorysound_create()160 factorysound_t* factorysound_create()
161 {
162 factorysound_t* f = mallocx(sizeof *f);
163 f->data = NULL;
164 return f;
165 }
166
167 /* destroys a factory sound */
factorysound_destroy(factorysound_t * f)168 void factorysound_destroy(factorysound_t *f)
169 {
170 free(f);
171 }
172
173