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