├── .cvsignore ├── .gitmodules ├── CHANGELOG.txt ├── COPYING ├── Makefile ├── README.md ├── extra ├── flite-1.1-noaudio.patch └── windows-dll-exports.patch ├── flite-help.pd ├── flite-meta.pd ├── flite-numbers.pd ├── flite-test.pd ├── flite-test2.pd ├── flite.c ├── pd-lib-builder ├── CHANGELOG.txt ├── Makefile.pdlibbuilder ├── README.md └── tips-tricks.md └── scripts ├── localdeps.linux.sh ├── localdeps.macos.sh └── localdeps.win.sh /.cvsignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .*~ 3 | *.o 4 | *.pd_linux 5 | aclocal.m4 6 | Makefile 7 | Makefile.in 8 | configure 9 | config.log 10 | config.status 11 | .deps 12 | install-sh 13 | mkinstalldirs 14 | missing 15 | config.guess 16 | config.sub 17 | depcomp 18 | ltmain.sh 19 | stamp-h* 20 | config.h 21 | config.h.in 22 | autom4te.cache 23 | 24 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/flite"] 2 | path = deps/flite 3 | url = https://github.com/festvox/flite 4 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Changelog for pd-flite 2 | 3 | v0.3.3, dated 16-11-2022 4 | 5 | - Remove flite sources (include them via gitmodules) 6 | - Allow building against system-installed libflite 7 | 8 | v0.3.2, dated 24-06-2022 9 | 10 | - Better thread coding 11 | 12 | v0.3.1, dated 21-06-2022 13 | 14 | - Add threaded functions for "synth" and "textfile" 15 | - Add function to open and use voice files 16 | 17 | 18 | v0.3.0, dated 12-06-2022 19 | 20 | - Add Flite sources and include them in the build. 21 | - The build includes the 5 built-in "voices" that can be used in the synthesis. 22 | - Update pd-lib-builder to 0.6.0 23 | - New method to read from files. 24 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | Preamble 12 | 13 | The licenses for most software are designed to take away your freedom 14 | to share and change it. By contrast, the GNU General Public License is 15 | intended to guarantee your freedom to share and change free 16 | software--to make sure the software is free for all its users. This General 17 | Public License applies to most of the Free Software Foundation's 18 | software and to any other program whose authors commit to using it. 19 | (Some other Free Software Foundation software is covered by the 20 | GNU Library General Public License instead.) You can apply it to your 21 | programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | this service if you wish), that you receive source code or can get it if you 27 | want it, that you can change the software or use pieces of it in new free 28 | programs; and that you know you can do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid anyone 31 | to deny you these rights or to ask you to surrender the rights. These 32 | restrictions translate to certain responsibilities for you if you distribute 33 | copies of the software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether gratis 36 | or for a fee, you must give the recipients all the rights that you have. You 37 | must make sure that they, too, receive or can get the source code. And 38 | you must show them these terms so they know their rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and 41 | (2) offer you this license which gives you legal permission to copy, 42 | distribute and/or modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain 45 | that everyone understands that there is no warranty for this free 46 | software. If the software is modified by someone else and passed on, 47 | we want its recipients to know that what they have is not the original, so 48 | that any problems introduced by others will not reflect on the original 49 | authors' reputations. 50 | 51 | Finally, any free program is threatened constantly by software patents. 52 | We wish to avoid the danger that redistributors of a free program will 53 | individually obtain patent licenses, in effect making the program 54 | proprietary. To prevent this, we have made it clear that any patent must 55 | be licensed for everyone's free use or not licensed at all. 56 | 57 | The precise terms and conditions for copying, distribution and 58 | modification follow. 59 | 60 | TERMS AND CONDITIONS FOR 61 | COPYING, DISTRIBUTION AND 62 | MODIFICATION 63 | 64 | 0. This License applies to any program or other work which contains a 65 | notice placed by the copyright holder saying it may be distributed under 66 | the terms of this General Public License. The "Program", below, refers 67 | to any such program or work, and a "work based on the Program" 68 | means either the Program or any derivative work under copyright law: 69 | that is to say, a work containing the Program or a portion of it, either 70 | verbatim or with modifications and/or translated into another language. 71 | (Hereinafter, translation is included without limitation in the term 72 | "modification".) Each licensee is addressed as "you". 73 | 74 | Activities other than copying, distribution and modification are not 75 | covered by this License; they are outside its scope. The act of running 76 | the Program is not restricted, and the output from the Program is 77 | covered only if its contents constitute a work based on the Program 78 | (independent of having been made by running the Program). Whether 79 | that is true depends on what the Program does. 80 | 81 | 1. You may copy and distribute verbatim copies of the Program's 82 | source code as you receive it, in any medium, provided that you 83 | conspicuously and appropriately publish on each copy an appropriate 84 | copyright notice and disclaimer of warranty; keep intact all the notices 85 | that refer to this License and to the absence of any warranty; and give 86 | any other recipients of the Program a copy of this License along with the 87 | Program. 88 | 89 | You may charge a fee for the physical act of transferring a copy, and 90 | you may at your option offer warranty protection in exchange for a fee. 91 | 92 | 2. You may modify your copy or copies of the Program or any portion 93 | of it, thus forming a work based on the Program, and copy and 94 | distribute such modifications or work under the terms of Section 1 95 | above, provided that you also meet all of these conditions: 96 | 97 | a) You must cause the modified files to carry prominent notices 98 | stating that you changed the files and the date of any change. 99 | 100 | b) You must cause any work that you distribute or publish, that in 101 | whole or in part contains or is derived from the Program or any 102 | part thereof, to be licensed as a whole at no charge to all third 103 | parties under the terms of this License. 104 | 105 | c) If the modified program normally reads commands interactively 106 | when run, you must cause it, when started running for such 107 | interactive use in the most ordinary way, to print or display an 108 | announcement including an appropriate copyright notice and a 109 | notice that there is no warranty (or else, saying that you provide a 110 | warranty) and that users may redistribute the program under 111 | these conditions, and telling the user how to view a copy of this 112 | License. (Exception: if the Program itself is interactive but does 113 | not normally print such an announcement, your work based on 114 | the Program is not required to print an announcement.) 115 | 116 | These requirements apply to the modified work as a whole. If 117 | identifiable sections of that work are not derived from the Program, and 118 | can be reasonably considered independent and separate works in 119 | themselves, then this License, and its terms, do not apply to those 120 | sections when you distribute them as separate works. But when you 121 | distribute the same sections as part of a whole which is a work based on 122 | the Program, the distribution of the whole must be on the terms of this 123 | License, whose permissions for other licensees extend to the entire 124 | whole, and thus to each and every part regardless of who wrote it. 125 | 126 | Thus, it is not the intent of this section to claim rights or contest your 127 | rights to work written entirely by you; rather, the intent is to exercise the 128 | right to control the distribution of derivative or collective works based 129 | on the Program. 130 | 131 | In addition, mere aggregation of another work not based on the 132 | Program with the Program (or with a work based on the Program) on a 133 | volume of a storage or distribution medium does not bring the other 134 | work under the scope of this License. 135 | 136 | 3. You may copy and distribute the Program (or a work based on it, 137 | under Section 2) in object code or executable form under the terms of 138 | Sections 1 and 2 above provided that you also do one of the following: 139 | 140 | a) Accompany it with the complete corresponding 141 | machine-readable source code, which must be distributed under 142 | the terms of Sections 1 and 2 above on a medium customarily 143 | used for software interchange; or, 144 | 145 | b) Accompany it with a written offer, valid for at least three 146 | years, to give any third party, for a charge no more than your cost 147 | of physically performing source distribution, a complete 148 | machine-readable copy of the corresponding source code, to be 149 | distributed under the terms of Sections 1 and 2 above on a 150 | medium customarily used for software interchange; or, 151 | 152 | c) Accompany it with the information you received as to the offer 153 | to distribute corresponding source code. (This alternative is 154 | allowed only for noncommercial distribution and only if you 155 | received the program in object code or executable form with 156 | such an offer, in accord with Subsection b above.) 157 | 158 | The source code for a work means the preferred form of the work for 159 | making modifications to it. For an executable work, complete source 160 | code means all the source code for all modules it contains, plus any 161 | associated interface definition files, plus the scripts used to control 162 | compilation and installation of the executable. However, as a special 163 | exception, the source code distributed need not include anything that is 164 | normally distributed (in either source or binary form) with the major 165 | components (compiler, kernel, and so on) of the operating system on 166 | which the executable runs, unless that component itself accompanies the 167 | executable. 168 | 169 | If distribution of executable or object code is made by offering access to 170 | copy from a designated place, then offering equivalent access to copy 171 | the source code from the same place counts as distribution of the source 172 | code, even though third parties are not compelled to copy the source 173 | along with the object code. 174 | 175 | 4. You may not copy, modify, sublicense, or distribute the Program 176 | except as expressly provided under this License. Any attempt otherwise 177 | to copy, modify, sublicense or distribute the Program is void, and will 178 | automatically terminate your rights under this License. However, parties 179 | who have received copies, or rights, from you under this License will not 180 | have their licenses terminated so long as such parties remain in full 181 | compliance. 182 | 183 | 5. You are not required to accept this License, since you have not 184 | signed it. However, nothing else grants you permission to modify or 185 | distribute the Program or its derivative works. These actions are 186 | prohibited by law if you do not accept this License. Therefore, by 187 | modifying or distributing the Program (or any work based on the 188 | Program), you indicate your acceptance of this License to do so, and all 189 | its terms and conditions for copying, distributing or modifying the 190 | Program or works based on it. 191 | 192 | 6. Each time you redistribute the Program (or any work based on the 193 | Program), the recipient automatically receives a license from the original 194 | licensor to copy, distribute or modify the Program subject to these terms 195 | and conditions. You may not impose any further restrictions on the 196 | recipients' exercise of the rights granted herein. You are not responsible 197 | for enforcing compliance by third parties to this License. 198 | 199 | 7. If, as a consequence of a court judgment or allegation of patent 200 | infringement or for any other reason (not limited to patent issues), 201 | conditions are imposed on you (whether by court order, agreement or 202 | otherwise) that contradict the conditions of this License, they do not 203 | excuse you from the conditions of this License. If you cannot distribute 204 | so as to satisfy simultaneously your obligations under this License and 205 | any other pertinent obligations, then as a consequence you may not 206 | distribute the Program at all. For example, if a patent license would not 207 | permit royalty-free redistribution of the Program by all those who 208 | receive copies directly or indirectly through you, then the only way you 209 | could satisfy both it and this License would be to refrain entirely from 210 | distribution of the Program. 211 | 212 | If any portion of this section is held invalid or unenforceable under any 213 | particular circumstance, the balance of the section is intended to apply 214 | and the section as a whole is intended to apply in other circumstances. 215 | 216 | It is not the purpose of this section to induce you to infringe any patents 217 | or other property right claims or to contest validity of any such claims; 218 | this section has the sole purpose of protecting the integrity of the free 219 | software distribution system, which is implemented by public license 220 | practices. Many people have made generous contributions to the wide 221 | range of software distributed through that system in reliance on 222 | consistent application of that system; it is up to the author/donor to 223 | decide if he or she is willing to distribute software through any other 224 | system and a licensee cannot impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to be 227 | a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in certain 230 | countries either by patents or by copyrighted interfaces, the original 231 | copyright holder who places the Program under this License may add an 232 | explicit geographical distribution limitation excluding those countries, so 233 | that distribution is permitted only in or among countries not thus 234 | excluded. In such case, this License incorporates the limitation as if 235 | written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new 238 | versions of the General Public License from time to time. Such new 239 | versions will be similar in spirit to the present version, but may differ in 240 | detail to address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number 247 | of this License, you may choose any version ever published by the Free 248 | Software Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we 254 | sometimes make exceptions for this. Our decision will be guided by the 255 | two goals of preserving the free status of all derivatives of our free 256 | software and of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF 261 | CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, 262 | TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT 263 | WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 264 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE 265 | PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, 266 | EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT 267 | LIMITED TO, THE IMPLIED WARRANTIES OF 268 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR 269 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND 270 | PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD 271 | THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE 272 | COST OF ALL NECESSARY SERVICING, REPAIR OR 273 | CORRECTION. 274 | 275 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW 276 | OR AGREED TO IN WRITING WILL ANY COPYRIGHT 277 | HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 278 | AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED 279 | ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING 280 | ANY GENERAL, SPECIAL, INCIDENTAL OR 281 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR 282 | INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT 283 | LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 284 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 285 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE 286 | WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 287 | OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY 288 | OF SUCH DAMAGES. 289 | 290 | END OF TERMS AND CONDITIONS 291 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile to build class 'flite' for Pure Data. 2 | # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build 3 | # settings and rules. 4 | 5 | # library name 6 | lib.name = flite 7 | 8 | cflags = 9 | 10 | BUNDLED_FLITE = ./deps/flite 11 | ifneq ($(wildcard $(BUNDLED_FLITE)/include/flite.h),) 12 | use_bundled_flite=yes 13 | endif 14 | 15 | ifeq ($(use_bundled_flite), yes) 16 | cflags += \ 17 | -I$(BUNDLED_FLITE)/include \ 18 | -I$(BUNDLED_FLITE)/lang/cmulex \ 19 | -I$(BUNDLED_FLITE)/lang/usenglish \ 20 | $(empty) 21 | else 22 | cflags += -DHAVE_FLITE_FLITE_H=1 23 | ldlibs += \ 24 | -lflite_cmulex \ 25 | -lflite_cmu_grapheme_lang \ 26 | -lflite_cmu_grapheme_lex \ 27 | -lflite_cmu_indic_lang \ 28 | -lflite_cmu_indic_lex \ 29 | -lflite_cmu_time_awb \ 30 | -lflite_cmu_us_awb \ 31 | -lflite_cmu_us_kal \ 32 | -lflite_cmu_us_kal16 \ 33 | -lflite_cmu_us_rms \ 34 | -lflite_cmu_us_slt \ 35 | -lflite_usenglish \ 36 | -lflite \ 37 | $(empty) 38 | endif 39 | 40 | 41 | ldlibs += -lm -lpthread 42 | 43 | cflags += -I . -DVERSION='"0.3.3"' 44 | 45 | # input source file (class name == source file basename) 46 | flite.class.sources = flite.c 47 | 48 | ifeq ($(use_bundled_flite), yes) 49 | flite.class.sources += \ 50 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex.c \ 51 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex_data.c \ 52 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex_entries.c \ 53 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lts_model.c \ 54 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lts_rules.c \ 55 | $(BUNDLED_FLITE)/lang/cmulex/cmu_postlex.c \ 56 | $(BUNDLED_FLITE)/lang/cmu_grapheme_lang/cmu_grapheme_lang.c \ 57 | $(BUNDLED_FLITE)/lang/cmu_grapheme_lang/cmu_grapheme_phoneset.c \ 58 | $(BUNDLED_FLITE)/lang/cmu_grapheme_lang/cmu_grapheme_phrasing_cart.c \ 59 | $(BUNDLED_FLITE)/lang/cmu_grapheme_lang/graph_gpos.c \ 60 | $(BUNDLED_FLITE)/lang/cmu_grapheme_lex/cmu_grapheme_lex.c \ 61 | $(BUNDLED_FLITE)/lang/cmu_grapheme_lex/grapheme_unitran_tables.c \ 62 | $(BUNDLED_FLITE)/lang/cmu_indic_lang/cmu_indic_lang.c \ 63 | $(BUNDLED_FLITE)/lang/cmu_indic_lang/cmu_indic_phoneset.c \ 64 | $(BUNDLED_FLITE)/lang/cmu_indic_lang/cmu_indic_phrasing_cart.c \ 65 | $(BUNDLED_FLITE)/lang/cmu_indic_lex/cmu_indic_lex.c \ 66 | $(BUNDLED_FLITE)/lang/cmu_time_awb/cmu_time_awb.c \ 67 | $(BUNDLED_FLITE)/lang/cmu_time_awb/cmu_time_awb_cart.c \ 68 | $(BUNDLED_FLITE)/lang/cmu_time_awb/cmu_time_awb_clunits.c \ 69 | $(BUNDLED_FLITE)/lang/cmu_time_awb/cmu_time_awb_lex_entry.c \ 70 | $(BUNDLED_FLITE)/lang/cmu_time_awb/cmu_time_awb_lpc.c \ 71 | $(BUNDLED_FLITE)/lang/cmu_time_awb/cmu_time_awb_mcep.c \ 72 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb.c \ 73 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_cg.c \ 74 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_cg_durmodel.c \ 75 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_cg_f0_trees.c \ 76 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_cg_phonestate.c \ 77 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_cg_single_mcep_trees.c \ 78 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_cg_single_params.c \ 79 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_spamf0_accent.c \ 80 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_spamf0_accent_params.c \ 81 | $(BUNDLED_FLITE)/lang/cmu_us_awb/cmu_us_awb_spamf0_phrase.c \ 82 | $(BUNDLED_FLITE)/lang/cmu_us_kal/cmu_us_kal.c \ 83 | $(BUNDLED_FLITE)/lang/cmu_us_kal/cmu_us_kal_diphone.c \ 84 | $(BUNDLED_FLITE)/lang/cmu_us_kal/cmu_us_kal_lpc.c \ 85 | $(BUNDLED_FLITE)/lang/cmu_us_kal/cmu_us_kal_res.c \ 86 | $(BUNDLED_FLITE)/lang/cmu_us_kal/cmu_us_kal_residx.c \ 87 | $(BUNDLED_FLITE)/lang/cmu_us_kal/cmu_us_kal_ressize.c \ 88 | $(BUNDLED_FLITE)/lang/cmu_us_kal16/cmu_us_kal16.c \ 89 | $(BUNDLED_FLITE)/lang/cmu_us_kal16/cmu_us_kal16_diphone.c \ 90 | $(BUNDLED_FLITE)/lang/cmu_us_kal16/cmu_us_kal16_lpc.c \ 91 | $(BUNDLED_FLITE)/lang/cmu_us_kal16/cmu_us_kal16_res.c \ 92 | $(BUNDLED_FLITE)/lang/cmu_us_kal16/cmu_us_kal16_residx.c \ 93 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms.c \ 94 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_cg.c \ 95 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_cg_durmodel.c \ 96 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_cg_f0_trees.c \ 97 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_cg_phonestate.c \ 98 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_cg_single_mcep_trees.c \ 99 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_cg_single_params.c \ 100 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_spamf0_accent.c \ 101 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_spamf0_accent_params.c \ 102 | $(BUNDLED_FLITE)/lang/cmu_us_rms/cmu_us_rms_spamf0_phrase.c \ 103 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt.c \ 104 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_cg.c \ 105 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_cg_durmodel.c \ 106 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_cg_f0_trees.c \ 107 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_cg_phonestate.c \ 108 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_cg_single_mcep_trees.c \ 109 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_cg_single_params.c \ 110 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_spamf0_accent.c \ 111 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_spamf0_accent_params.c \ 112 | $(BUNDLED_FLITE)/lang/cmu_us_slt/cmu_us_slt_spamf0_phrase.c \ 113 | $(BUNDLED_FLITE)/lang/usenglish/usenglish.c \ 114 | $(BUNDLED_FLITE)/lang/usenglish/us_aswd.c \ 115 | $(BUNDLED_FLITE)/lang/usenglish/us_durz_cart.c \ 116 | $(BUNDLED_FLITE)/lang/usenglish/us_dur_stats.c \ 117 | $(BUNDLED_FLITE)/lang/usenglish/us_expand.c \ 118 | $(BUNDLED_FLITE)/lang/usenglish/us_f0lr.c \ 119 | $(BUNDLED_FLITE)/lang/usenglish/us_f0_model.c \ 120 | $(BUNDLED_FLITE)/lang/usenglish/us_ffeatures.c \ 121 | $(BUNDLED_FLITE)/lang/usenglish/us_gpos.c \ 122 | $(BUNDLED_FLITE)/lang/usenglish/us_int_accent_cart.c \ 123 | $(BUNDLED_FLITE)/lang/usenglish/us_int_tone_cart.c \ 124 | $(BUNDLED_FLITE)/lang/usenglish/us_nums_cart.c \ 125 | $(BUNDLED_FLITE)/lang/usenglish/us_phoneset.c \ 126 | $(BUNDLED_FLITE)/lang/usenglish/us_phrasing_cart.c \ 127 | $(BUNDLED_FLITE)/lang/usenglish/us_pos_cart.c \ 128 | $(BUNDLED_FLITE)/lang/usenglish/us_text.c \ 129 | $(BUNDLED_FLITE)/src/audio/au_none.c \ 130 | $(BUNDLED_FLITE)/src/audio/audio.c \ 131 | $(BUNDLED_FLITE)/src/audio/au_streaming.c \ 132 | $(BUNDLED_FLITE)/src/cg/cst_cg.c \ 133 | $(BUNDLED_FLITE)/src/cg/cst_cg_dump_voice.c \ 134 | $(BUNDLED_FLITE)/src/cg/cst_cg_load_voice.c \ 135 | $(BUNDLED_FLITE)/src/cg/cst_cg_map.c \ 136 | $(BUNDLED_FLITE)/src/cg/cst_mlpg.c \ 137 | $(BUNDLED_FLITE)/src/cg/cst_mlsa.c \ 138 | $(BUNDLED_FLITE)/src/cg/cst_spamf0.c \ 139 | $(BUNDLED_FLITE)/src/cg/cst_vc.c \ 140 | $(BUNDLED_FLITE)/src/hrg/cst_ffeature.c \ 141 | $(BUNDLED_FLITE)/src/hrg/cst_item.c \ 142 | $(BUNDLED_FLITE)/src/hrg/cst_relation.c \ 143 | $(BUNDLED_FLITE)/src/hrg/cst_rel_io.c \ 144 | $(BUNDLED_FLITE)/src/hrg/cst_utterance.c \ 145 | $(BUNDLED_FLITE)/src/lexicon/cst_lexicon.c \ 146 | $(BUNDLED_FLITE)/src/lexicon/cst_lts.c \ 147 | $(BUNDLED_FLITE)/src/lexicon/cst_lts_rewrites.c \ 148 | $(BUNDLED_FLITE)/src/regex/cst_regex.c \ 149 | $(BUNDLED_FLITE)/src/regex/regexp.c \ 150 | $(BUNDLED_FLITE)/src/regex/regsub.c \ 151 | $(BUNDLED_FLITE)/src/speech/cst_lpcres.c \ 152 | $(BUNDLED_FLITE)/src/speech/cst_track.c \ 153 | $(BUNDLED_FLITE)/src/speech/cst_track_io.c \ 154 | $(BUNDLED_FLITE)/src/speech/cst_wave.c \ 155 | $(BUNDLED_FLITE)/src/speech/cst_wave_io.c \ 156 | $(BUNDLED_FLITE)/src/speech/cst_wave_utils.c \ 157 | $(BUNDLED_FLITE)/src/speech/g721.c \ 158 | $(BUNDLED_FLITE)/src/speech/g723_24.c \ 159 | $(BUNDLED_FLITE)/src/speech/g723_40.c \ 160 | $(BUNDLED_FLITE)/src/speech/g72x.c \ 161 | $(BUNDLED_FLITE)/src/speech/rateconv.c \ 162 | $(BUNDLED_FLITE)/src/stats/cst_cart.c \ 163 | $(BUNDLED_FLITE)/src/stats/cst_ss.c \ 164 | $(BUNDLED_FLITE)/src/stats/cst_viterbi.c \ 165 | $(BUNDLED_FLITE)/src/synth/cst_ffeatures.c \ 166 | $(BUNDLED_FLITE)/src/synth/cst_phoneset.c \ 167 | $(BUNDLED_FLITE)/src/synth/cst_ssml.c \ 168 | $(BUNDLED_FLITE)/src/synth/cst_synth.c \ 169 | $(BUNDLED_FLITE)/src/synth/cst_utt_utils.c \ 170 | $(BUNDLED_FLITE)/src/synth/cst_voice.c \ 171 | $(BUNDLED_FLITE)/src/synth/flite.c \ 172 | $(BUNDLED_FLITE)/src/utils/cst_alloc.c \ 173 | $(BUNDLED_FLITE)/src/utils/cst_args.c \ 174 | $(BUNDLED_FLITE)/src/utils/cst_endian.c \ 175 | $(BUNDLED_FLITE)/src/utils/cst_error.c \ 176 | $(BUNDLED_FLITE)/src/utils/cst_features.c \ 177 | $(BUNDLED_FLITE)/src/utils/cst_file_stdio.c \ 178 | $(BUNDLED_FLITE)/src/utils/cst_mmap_none.c \ 179 | $(BUNDLED_FLITE)/src/utils/cst_socket.c \ 180 | $(BUNDLED_FLITE)/src/utils/cst_string.c \ 181 | $(BUNDLED_FLITE)/src/utils/cst_tokenstream.c \ 182 | $(BUNDLED_FLITE)/src/utils/cst_url.c \ 183 | $(BUNDLED_FLITE)/src/utils/cst_val.c \ 184 | $(BUNDLED_FLITE)/src/utils/cst_val_const.c \ 185 | $(BUNDLED_FLITE)/src/utils/cst_val_user.c \ 186 | $(BUNDLED_FLITE)/src/utils/cst_wchar.c \ 187 | $(BUNDLED_FLITE)/src/wavesynth/cst_clunits.c \ 188 | $(BUNDLED_FLITE)/src/wavesynth/cst_diphone.c \ 189 | $(BUNDLED_FLITE)/src/wavesynth/cst_reflpc.c \ 190 | $(BUNDLED_FLITE)/src/wavesynth/cst_sigpr.c \ 191 | $(BUNDLED_FLITE)/src/wavesynth/cst_sts.c \ 192 | $(BUNDLED_FLITE)/src/wavesynth/cst_units.c \ 193 | $(empty) 194 | 195 | # unused sources 196 | EXCLUDEDFILES = \ 197 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex_data_raw.c \ 198 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex_entries_huff_table.c \ 199 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex_num_bytes.c \ 200 | $(BUNDLED_FLITE)/lang/cmulex/cmu_lex_phones_huff_table.c \ 201 | $(BUNDLED_FLITE)/sapi/FliteTTSEngineObj/flite_sapi_usenglish.c \ 202 | $(BUNDLED_FLITE)/src/audio/auclient.c \ 203 | $(BUNDLED_FLITE)/src/audio/auserver.c \ 204 | $(BUNDLED_FLITE)/src/audio/au_alsa.c \ 205 | $(BUNDLED_FLITE)/src/audio/au_command.c \ 206 | $(BUNDLED_FLITE)/src/audio/au_oss.c \ 207 | $(BUNDLED_FLITE)/src/audio/au_palmos.c \ 208 | $(BUNDLED_FLITE)/src/audio/au_pulseaudio.c \ 209 | $(BUNDLED_FLITE)/src/audio/au_sun.c \ 210 | $(BUNDLED_FLITE)/src/audio/au_win.c \ 211 | $(BUNDLED_FLITE)/src/audio/au_wince.c \ 212 | $(BUNDLED_FLITE)/src/utils/cst_file_palmos.c \ 213 | $(BUNDLED_FLITE)/src/utils/cst_file_wince.c \ 214 | $(BUNDLED_FLITE)/src/utils/cst_mmap_posix.c \ 215 | $(BUNDLED_FLITE)/src/utils/cst_mmap_win32.c \ 216 | $(BUNDLED_FLITE)/testsuite/asciiS2U_main.c \ 217 | $(BUNDLED_FLITE)/testsuite/asciiU2S_main.c \ 218 | $(BUNDLED_FLITE)/testsuite/bin2ascii_main.c \ 219 | $(BUNDLED_FLITE)/testsuite/by_word_main.c \ 220 | $(BUNDLED_FLITE)/testsuite/combine_waves_main.c \ 221 | $(BUNDLED_FLITE)/testsuite/compare_wave_main.c \ 222 | $(BUNDLED_FLITE)/testsuite/dcoffset_wave_main.c \ 223 | $(BUNDLED_FLITE)/testsuite/flite_test_main.c \ 224 | $(BUNDLED_FLITE)/testsuite/hrg_test_main.c \ 225 | $(BUNDLED_FLITE)/testsuite/kal_test_main.c \ 226 | $(BUNDLED_FLITE)/testsuite/lex_lookup_main.c \ 227 | $(BUNDLED_FLITE)/testsuite/lex_test_main.c \ 228 | $(BUNDLED_FLITE)/testsuite/lpc_resynth_main.c \ 229 | $(BUNDLED_FLITE)/testsuite/lpc_test2_main.c \ 230 | $(BUNDLED_FLITE)/testsuite/lpc_test_main.c \ 231 | $(BUNDLED_FLITE)/testsuite/multi_thread_main.c \ 232 | $(BUNDLED_FLITE)/testsuite/nums_test_main.c \ 233 | $(BUNDLED_FLITE)/testsuite/play_client_main.c \ 234 | $(BUNDLED_FLITE)/testsuite/play_server_main.c \ 235 | $(BUNDLED_FLITE)/testsuite/play_sync_main.c \ 236 | $(BUNDLED_FLITE)/testsuite/play_wave_main.c \ 237 | $(BUNDLED_FLITE)/testsuite/record_in_noise_main.c \ 238 | $(BUNDLED_FLITE)/testsuite/record_wave_main.c \ 239 | $(BUNDLED_FLITE)/testsuite/regex_test_main.c \ 240 | $(BUNDLED_FLITE)/testsuite/rfc_main.c \ 241 | $(BUNDLED_FLITE)/testsuite/token_test_main.c \ 242 | $(BUNDLED_FLITE)/testsuite/tris1_main.c \ 243 | $(BUNDLED_FLITE)/testsuite/utt_test_main.c \ 244 | $(BUNDLED_FLITE)/tools/find_sts_main.c \ 245 | $(BUNDLED_FLITE)/tools/flite_sort_main.c \ 246 | $(BUNDLED_FLITE)/tools/LANGNAME_lang.c \ 247 | $(BUNDLED_FLITE)/tools/LANGNAME_lex.c \ 248 | $(BUNDLED_FLITE)/tools/VOICE_cg.c \ 249 | $(BUNDLED_FLITE)/tools/VOICE_clunits.c \ 250 | $(BUNDLED_FLITE)/tools/VOICE_diphone.c \ 251 | $(BUNDLED_FLITE)/tools/VOICE_ldom.c \ 252 | $(BUNDLED_FLITE)/wince/flowm_flite.c \ 253 | $(BUNDLED_FLITE)/wince/flowm_main.c \ 254 | $(BUNDLED_FLITE)/main/compile_regexes.c \ 255 | $(BUNDLED_FLITE)/main/flitevox_info_main.c \ 256 | $(BUNDLED_FLITE)/main/flite_lang_list.c \ 257 | $(BUNDLED_FLITE)/main/flite_main.c \ 258 | $(BUNDLED_FLITE)/main/flite_time_main.c \ 259 | $(BUNDLED_FLITE)/main/t2p_main.c \ 260 | $(BUNDLED_FLITE)/main/word_times_main.c \ 261 | $(empty) 262 | endif 263 | 264 | define forWindows 265 | cflags += \ 266 | -DCST_NO_SOCKETS \ 267 | -DUNDER_WINDOWS \ 268 | $(empty) 269 | ldlibs += 270 | endef 271 | 272 | define forDarwin 273 | cflags += \ 274 | -DCST_AUDIO_NONE \ 275 | -no-cpp-precomp \ 276 | $(empty) 277 | endef 278 | 279 | # all extra files to be included in binary distribution of the library 280 | datafiles = \ 281 | flite-help.pd \ 282 | flite-numbers.pd flite-test2.pd flite-test.pd \ 283 | README.md flite-meta.pd CHANGELOG.txt \ 284 | 285 | 286 | #alldebug: CPPFLAGS+=-DFLITE_DEBUG=1 287 | 288 | 289 | # include Makefile.pdlibbuilder from submodule directory 'pd-lib-builder' 290 | PDLIBBUILDER_DIR=pd-lib-builder/ 291 | include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder 292 | 293 | localdep_windows: install 294 | scripts/localdeps.win.sh "$(installpath)/flite.$(extension)" 295 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | README for Pd external distribution 'pd-flite' 2 | 3 | Last updated for version 0.3.3 4 | 5 | # DESCRIPTION 6 | 7 | The 'pd-flite' distribution contains a single Pd external ("flite"), 8 | which provides a high-level text-to-speech interface for English based on 9 | the 'libflite' library by Alan W Black and Kevin A. Lenzo. 10 | 11 | 'libflite' lives at https://github.com/festvox/flite 12 | 13 | 14 | # linking with libflite 15 | To produce a self-contained "flite" external (with no external dependencies 16 | on libflite), you can statically link the library. 17 | 18 | ## git submodules 19 | The libflite sources are available via a git submodule in `deps/flite/`. 20 | 21 | After cloning the pd-flite repository, initialize the submodules via: 22 | 23 | git submodule update --init 24 | 25 | If the submodule is updated, re-run `git submodule update` in your local 26 | clone to get the lastest and greatest libflite. 27 | 28 | ## without git 29 | If you obtained the 'pd-flite' sources without git (e.g. by downloading a 30 | release tarball), there won't be any bundled libflite. 31 | Instead, you can manually download flite from https://github.com/festvox/flite 32 | and put it into the `deps/flite/` folder (so you have a 33 | deps/flite/include/flite.h file) 34 | 35 | ## use system libraries 36 | 37 | If you prefer to use system-provided libflite instead (e.g. provided by 38 | your favourite package manager), just make sure that deps/flite/ is empty 39 | (by not initializing the git-submodules and not downloading libflite 40 | manually). 41 | If the build process does not detect the deps/flite/include/flite.h file, 42 | it will attempt to use a system-provided libflite instead. 43 | 44 | If you happen to have a local copy of libflite in the deps/ folder, 45 | you can force building against the system libraries by adding 46 | `use_bundled_flite=no` when calling *make*. 47 | 48 | 49 | # WINDOWS BUILD 50 | 51 | With MSYS2 install the ntldd package: 52 | 53 | pacman -S mingw32/mingw-w64-i686-ntldd-git 54 | 55 | pacman -S mingw64/mingw-w64-x86_64-ntldd-git 56 | 57 | Then cd MinGW to this repo and do: 58 | 59 | make 60 | 61 | or you can also specify more options with: 62 | 63 | make PDDIR= 64 | 65 | then do this command that installs and fills the `pthread` dependencies on the output dir: 66 | 67 | make localdep_windows 68 | 69 | or with more options: 70 | 71 | make PDLIBDIR= extension= localdep_windows 72 | 73 | # ACKNOWLEDGEMENTS 74 | 75 | Pd by Miller Puckette and others. 76 | 77 | Flite run-time speech synthesis library by Alan W Black 78 | and Kevin A. Lenzo. 79 | 80 | Ideas, black magic, and other nuggets of information drawn 81 | from code by Guenter Geiger, Larry Troxler, and iohannes m zmoelnig. 82 | 83 | # KNOWN BUGS 84 | 85 | It gobbles memory, and also processor time on synthesis operations. 86 | 87 | 88 | # AUTHOR 89 | 90 | Bryan Jurish 91 | 92 | # MAINTENANCE 93 | 94 | Since v0.3.0 Lucas Cordiviola https://github.com/pd-externals/flite 95 | 96 | - Thanks to Christof Ressi for code reviews. 97 | -------------------------------------------------------------------------------- /extra/flite-1.1-noaudio.patch: -------------------------------------------------------------------------------- 1 | diff -uNr flite-1.1-release/src/audio/native_audio.h flite-1.1-release-noaudio/src/audio/native_audio.h 2 | --- flite-1.1-release/src/audio/native_audio.h Tue Dec 4 19:05:59 2001 3 | +++ flite-1.1-release-noaudio/src/audio/native_audio.h Sun Nov 3 19:12:44 2002 4 | @@ -41,6 +41,16 @@ 5 | #ifndef _NATIVE_AUDIO_H__ 6 | #define _NATIVE_AUDIO_H__ 7 | 8 | +/* -- begin HACK: turn off all audio -- */ 9 | +#undef CST_AUDIO_COMMAND 10 | +#undef CST_AUDIO_SUNOS 11 | +#undef CST_AUDIO_LINUX 12 | +#undef CST_AUDIO_ALSA 13 | +#undef CST_AUDIO_FREEBSD 14 | +#undef CST_AUDIO_WINCE 15 | +#define CST_AUDIO_NONE 16 | +/* -- end HACK -- */ 17 | + 18 | #ifdef CST_AUDIO_COMMAND 19 | 20 | #define AUDIO_OPEN_NATIVE audio_open_command 21 | -------------------------------------------------------------------------------- /extra/windows-dll-exports.patch: -------------------------------------------------------------------------------- 1 | From a8d89b884736dcf3a9b3c262da2c0e20954c46d8 Mon Sep 17 00:00:00 2001 2 | From: Lucas Cordiviola 3 | Date: Thu, 26 May 2022 18:18:05 -0300 4 | Subject: [PATCH] Windows object now works 5 | 6 | --- 7 | deps/flite/include/flite.h | 10 +--------- 8 | deps/flite/src/synth/flite.c | 13 ++++--------- 9 | 2 files changed, 5 insertions(+), 18 deletions(-) 10 | 11 | diff --git a/deps/flite/include/flite.h b/deps/flite/include/flite.h 12 | index 8814d97..3a2bd1c 100644 13 | --- a/deps/flite/include/flite.h 14 | +++ b/deps/flite/include/flite.h 15 | @@ -65,15 +65,7 @@ extern "C" { 16 | #include "cst_units.h" 17 | #include "cst_tokenstream.h" 18 | 19 | -#ifdef WIN32 20 | -/* For Visual Studio 2012 global variable definitions */ 21 | -#define GLOBALVARDEF __declspec(dllexport) 22 | -#else 23 | -#define GLOBALVARDEF 24 | -#endif 25 | - extern GLOBALVARDEF cst_val *flite_voice_list; 26 | - extern GLOBALVARDEF cst_lang flite_lang_list[20]; 27 | - extern GLOBALVARDEF int flite_lang_list_length; 28 | + 29 | 30 | /* Public functions */ 31 | int flite_init(); 32 | diff --git a/deps/flite/src/synth/flite.c b/deps/flite/src/synth/flite.c 33 | index d85fe1a..ec0e0eb 100644 34 | --- a/deps/flite/src/synth/flite.c 35 | +++ b/deps/flite/src/synth/flite.c 36 | @@ -44,12 +44,7 @@ 37 | #include "cst_clunits.h" 38 | #include "cst_cg.h" 39 | 40 | -#ifdef WIN32 41 | -/* For Visual Studio 2012 global variable definitions */ 42 | -#define GLOBALVARDEF __declspec(dllexport) 43 | -#else 44 | -#define GLOBALVARDEF 45 | -#endif 46 | + 47 | 48 | /* This is a global, which isn't ideal, this may change */ 49 | /* It is set when flite_set_voice_list() is called which happens in */ 50 | @@ -59,14 +54,14 @@ 51 | /* Note these voices remain loaded, there is currently no automatic */ 52 | /* garbage collection, that would be necessary in the long run */ 53 | /* delete_voice will work, but you'd need to know when to call it */ 54 | -GLOBALVARDEF cst_val *flite_voice_list = NULL; 55 | +cst_val *flite_voice_list = NULL; 56 | 57 | /* Another global with hold pointers to the language and lexicon */ 58 | /* initalization functions, we limiting to 20 but it could be bigger */ 59 | /* if we really did support over 20 different languages */ 60 | #define FLITE_MAX_LANGS 20 61 | -GLOBALVARDEF cst_lang flite_lang_list[FLITE_MAX_LANGS]; 62 | -GLOBALVARDEF int flite_lang_list_length = 0; 63 | +cst_lang flite_lang_list[FLITE_MAX_LANGS]; 64 | +int flite_lang_list_length = 0; 65 | 66 | int flite_init() 67 | { 68 | -- 69 | 2.36.0.windows.1 70 | 71 | -------------------------------------------------------------------------------- /flite-help.pd: -------------------------------------------------------------------------------- 1 | #N canvas 297 24 793 679 10; 2 | #X text 25 4 flite : text-to-speech synthesis with libflite; 3 | #N canvas 0 0 450 300 (subpatch) 0; 4 | #X array words2 1.60234e+07 float 0; 5 | #X coords 0 1 1.60234e+07 -1 100 70 1; 6 | #X restore 648 276 graph; 7 | #X obj 29 640 print flite-synth-done; 8 | #X text 51 35 ARRAYNAME - initial array name; 9 | #X text 352 16 1 - control messages; 10 | #X text 30 22 ARGUMENTS:; 11 | #X text 336 2 INLETS:; 12 | #X text 329 29 OUTLETS:; 13 | #X msg 26 77 set words1; 14 | #X msg 33 95 set words2; 15 | #X msg 66 144 synth; 16 | #X text 106 147 "synth" message synthesizes current text-buffer; 17 | #X text 159 122 "text" message sets input text-buffer; 18 | #X text 104 83 "set" message selects the output array; 19 | #X text 246 267 "list" messages set text and synthesize; 20 | #X obj 516 253 dac~; 21 | #X msg 601 85 \; pd dsp 1; 22 | #X msg 667 85 \; pd dsp 0; 23 | #X text 495 135 For playback \, you can use 'tabplay~':; 24 | #X msg 517 165 set words1; 25 | #X msg 527 185 set words2; 26 | #X msg 635 189 bang; 27 | #X msg 686 190 stop; 28 | #X msg 635 167 start; 29 | #X text 411 563 ACKNOWLEDGEMENTS:; 30 | #X text 429 578 Flite runtime speech synthesis library by Alan W Black 31 | and Kevin A. Lenzo.; 32 | #X msg 94 271 list bang bahda boobop; 33 | #N canvas 260 141 629 360 META 0; 34 | #X text 12 125 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan 35 | Wilkes for Pd version 0.42.; 36 | #X text 12 25 LICENSE GPL v2; 37 | #X text 12 45 DESCRIPTION text-to-speech synthesis with libflite; 38 | #X text 12 5 KEYWORDS control array; 39 | #X text 12 85 OUTLET_0 bang; 40 | #X text 12 105 AUTHOR Bryan Jurish ; 41 | #X text 12 65 INLET_0 set text synth list thrd_synth voice_file thrd_voice_file 42 | textfile thrd_textfile, f 89; 43 | #X restore 727 636 pd META; 44 | #X msg 60 122 text test 123; 45 | #X text 412 607 Bryan Jurish ; 46 | #X msg 110 301 awb; 47 | #X msg 143 301 kal; 48 | #X msg 178 300 kal16; 49 | #X msg 220 300 rms; 50 | #X msg 253 301 slt; 51 | #X msg 111 345 voice \$1; 52 | #X obj 110 326 symbol; 53 | #X obj 185 448 openpanel; 54 | #X obj 164 448 bng 15 250 50 0 empty empty empty 17 7 0 10 #fcfcfc 55 | #000000 #000000; 56 | #X msg 184 538 textfile \$1; 57 | #N canvas 26 26 633 528 longtext 0; 58 | #X obj 241 -91 inlet; 59 | #X obj 239 355 outlet; 60 | #X msg 241 -68 test 123 test 123 test 123 test 123 test 123 test 123 61 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 62 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 63 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 64 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 65 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 66 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 67 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 68 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 69 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 70 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 71 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 72 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 73 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 74 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 75 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 76 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 77 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 78 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 79 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 80 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 81 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 82 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 83 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 84 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 85 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 86 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 87 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 88 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 89 | test 123 test 123 test 123 test 123 test 123 test 123 test 123 test 90 | 123 test 123 test 123 test 123 test 123 test 123 test 123 test 123 91 | test 123 test 123 test 123 test 123 test 123 test 123 test 123; 92 | #X connect 0 0 2 0; 93 | #X connect 2 0 1 0; 94 | #X restore 99 171 pd longtext; 95 | #X obj 82 171 bng 15 250 50 0 empty empty empty 17 7 0 10 #fcfcfc #000000 96 | #000000; 97 | #X msg 90 242 thrd_synth; 98 | #X msg 210 583 thrd_textfile \$1; 99 | #X obj 184 493 route 0 1; 100 | #X obj 184 516 symbol; 101 | #X obj 210 563 symbol; 102 | #X obj 281 471 tgl 15 0 empty empty empty 17 7 0 10 #fcfcfc #000000 103 | #000000 0 1; 104 | #X text 160 242 "threaded" synthesis of the current text buffer; 105 | #X text 322 579 threaded version, f 9; 106 | #X text 298 471 threaded, f 10; 107 | #X obj 184 473 list prepend 0; 108 | #X text 502 356 Warnings: better not use graphical arrays for threaded 109 | synthesis. Also be careful to not synthesize to an array which is currently 110 | playing., f 46; 111 | #X obj 82 212 list trim; 112 | #X msg 123 393 voice_file \$1; 113 | #X msg 139 369 symbol cmu_us_ljm.flitevox; 114 | #X msg 253 448 ./README.md; 115 | #X obj 83 192 list prepend text; 116 | #X obj 516 297 array define words1; 117 | #X obj 28 615 flite words1; 118 | #X obj 517 230 tabplay~ words1; 119 | #X text 174 344 "voice" messages sets one of the built-in voices; 120 | #X text 227 391 load a .flitevox voice file (english), f 38; 121 | #N canvas 26 26 450 300 get-voices 0; 122 | #X obj 116 192 pdcontrol; 123 | #X msg 117 165 browse http://cmuflite.org/packed/flite-2.0/voices/ 124 | ; 125 | #X obj 171 105 bng 15 250 50 0 empty empty empty 17 7 0 10 #fcfcfc 126 | #000000 #000000; 127 | #X text 103 104 get voices; 128 | #X connect 1 0 0 0; 129 | #X connect 2 0 1 0; 130 | #X coords 0 -1 1 1 90 25 2 100 100; 131 | #X restore 369 408 pd get-voices; 132 | #N canvas 488 193 533 410 typical 0; 133 | #X listbox 132 44 42 0 0 0 - - - 0; 134 | #X obj 148 86 t b l, f 14; 135 | #X msg 148 154 thrd_synth; 136 | #X obj 147 360 dac~; 137 | #X obj 229 113 list prepend text; 138 | #X obj 229 136 list trim; 139 | #X obj 148 229 t b b; 140 | #X obj 148 328 tabplay~ \$0-foo; 141 | #X obj 148 206 flite \$0-foo; 142 | #X obj 387 8 array define \$0-foo; 143 | #X text 33 37 type here and press enter, f 15; 144 | #X obj 175 254 \$0; 145 | #X msg 175 282 \; \$1-foo normalize 0.7 \;; 146 | #X text 33 68 (commas are not allowed in the list box), f 13; 147 | #X connect 0 0 1 0; 148 | #X connect 1 0 2 0; 149 | #X connect 1 1 4 0; 150 | #X connect 2 0 8 0; 151 | #X connect 4 0 5 0; 152 | #X connect 5 0 8 0; 153 | #X connect 6 0 7 0; 154 | #X connect 6 1 11 0; 155 | #X connect 7 0 3 0; 156 | #X connect 7 0 3 1; 157 | #X connect 8 0 6 0; 158 | #X connect 11 0 12 0; 159 | #X restore 566 454 pd typical; 160 | #X text 541 436 open this sub patch; 161 | #X text 345 43 1 - bang on completed synthesis; 162 | #X text 264 538 "textfile" message reads a text file and synthesize 163 | it; 164 | #X msg 137 415 thrd_voice_file \$1; 165 | #X text 262 410 threaded version, f 9; 166 | #X text 412 630 v0.3.3 updated by Lucas Cordiviola https://github.com/pd-externals/flite 167 | ; 168 | #X connect 8 0 59 0; 169 | #X connect 9 0 59 0; 170 | #X connect 10 0 59 0; 171 | #X connect 19 0 60 0; 172 | #X connect 20 0 60 0; 173 | #X connect 21 0 60 0; 174 | #X connect 22 0 60 0; 175 | #X connect 23 0 21 0; 176 | #X connect 26 0 59 0; 177 | #X connect 28 0 59 0; 178 | #X connect 30 0 36 0; 179 | #X connect 31 0 36 0; 180 | #X connect 32 0 36 0; 181 | #X connect 33 0 36 0; 182 | #X connect 34 0 36 0; 183 | #X connect 35 0 59 0; 184 | #X connect 36 0 35 0; 185 | #X connect 37 0 51 0; 186 | #X connect 38 0 37 0; 187 | #X connect 39 0 59 0; 188 | #X connect 40 0 57 0; 189 | #X connect 41 0 40 0; 190 | #X connect 42 0 59 0; 191 | #X connect 43 0 59 0; 192 | #X connect 44 0 45 0; 193 | #X connect 44 1 46 0; 194 | #X connect 45 0 39 0; 195 | #X connect 46 0 43 0; 196 | #X connect 47 0 51 1; 197 | #X connect 51 0 44 0; 198 | #X connect 53 0 59 0; 199 | #X connect 54 0 59 0; 200 | #X connect 55 0 68 0; 201 | #X connect 56 0 51 0; 202 | #X connect 57 0 53 0; 203 | #X connect 59 0 2 0; 204 | #X connect 60 0 15 0; 205 | #X connect 60 0 15 1; 206 | #X connect 68 0 59 0; 207 | -------------------------------------------------------------------------------- /flite-meta.pd: -------------------------------------------------------------------------------- 1 | #N canvas 169 49 432 242 10; 2 | #N canvas 25 49 420 300 META 1; 3 | #X text 10 10 VERSION 0.3.3; 4 | #X text 10 30 AUTHOR Bryan Jurish ; 5 | #X text 10 50 NAME flite; 6 | #X text 10 70 LICENSE GPL-2; 7 | #X text 9 91 DESCRIPTION Speech synthesis for Pd; 8 | #X restore 20 20 pd META; 9 | -------------------------------------------------------------------------------- /flite-numbers.pd: -------------------------------------------------------------------------------- 1 | #N canvas 47 239 465 419 10; 2 | #X obj 69 219 random; 3 | #X floatatom 105 199 10 0 0; 4 | #X msg 105 176 65535; 5 | #X obj 105 153 loadbang; 6 | #X msg 14 13 start; 7 | #X msg 57 13 stop; 8 | #X msg 172 19 \; pd dsp 1; 9 | #X msg 238 19 \; pd dsp 0; 10 | #X msg 85 245 text \$1; 11 | #X obj 319 14 table \$0-numtab; 12 | #X obj 85 324 tabplay~ \$0-numtab; 13 | #X obj 85 277 flite \$0-numtab; 14 | #X obj 14 58 s \$0-start; 15 | #X obj 57 35 s \$0-stop; 16 | #X obj 39 124 r \$0-start; 17 | #X obj 39 148 t b b; 18 | #X msg 39 245 synth; 19 | #X obj 73 359 dac~; 20 | #X obj 206 371 s \$0-start; 21 | #X obj 206 347 spigot; 22 | #X msg 276 305 1; 23 | #X msg 243 305 0; 24 | #X obj 276 281 r \$0-start; 25 | #X obj 243 261 r \$0-stop; 26 | #X msg 210 295 0 1; 27 | #X connect 0 0 8 0; 28 | #X connect 1 0 0 1; 29 | #X connect 2 0 1 0; 30 | #X connect 3 0 2 0; 31 | #X connect 4 0 12 0; 32 | #X connect 5 0 13 0; 33 | #X connect 8 0 11 0; 34 | #X connect 10 0 17 0; 35 | #X connect 10 0 17 1; 36 | #X connect 10 1 19 0; 37 | #X connect 11 0 10 0; 38 | #X connect 14 0 15 0; 39 | #X connect 15 0 16 0; 40 | #X connect 15 1 0 0; 41 | #X connect 16 0 11 0; 42 | #X connect 19 0 18 0; 43 | #X connect 20 0 19 1; 44 | #X connect 21 0 19 1; 45 | #X connect 22 0 20 0; 46 | #X connect 23 0 21 0; 47 | #X connect 23 0 24 0; 48 | #X connect 24 0 10 0; 49 | -------------------------------------------------------------------------------- /flite-test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 164 1 726 560 10; 2 | #X msg 36 43 set ary2; 3 | #X msg 13 22 set ary1; 4 | #N canvas 0 0 450 300 graph1 0; 5 | #X array ary1 42489 float 0; 6 | #X coords 0 1 42488 -1 200 140 1; 7 | #X restore 41 223 graph; 8 | #N canvas 0 0 450 300 graph2 0; 9 | #X array ary2 10 float 0; 10 | #X coords 0 1 9 -1 200 140 1; 11 | #X restore 277 221 graph; 12 | #X obj 122 164 flite ary1; 13 | #X msg 121 16 text moo the cow; 14 | #X msg 133 38 text 42 marmosets; 15 | #X msg 149 83 synth; 16 | #X obj 390 418 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144 17 | -1 -1 11000 1; 18 | #X obj 388 442 dbtorms; 19 | #X obj 356 497 dac~; 20 | #X obj 365 472 *~ 0; 21 | #X msg 208 406 bang; 22 | #X msg 264 405 0 1; 23 | #X msg 264 384 stop; 24 | #X msg 208 384 start; 25 | #X obj 12 79 s aryset; 26 | #X obj 249 438 tabplay~ ary1; 27 | #X obj 302 405 r aryset; 28 | #X msg 46 390 set ary1; 29 | #X msg 111 389 set ary2; 30 | #X msg 472 452 \; pd dsp 1; 31 | #X msg 473 486 \; pd dsp 0; 32 | #X msg 145 61 text text; 33 | #X obj 108 471 spigot; 34 | #X obj 145 449 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 35 | 1; 36 | #X text 87 450 Loop; 37 | #X msg 285 15 list moo the cow; 38 | #X msg 287 40 list 42 marmosets; 39 | #X msg 289 66 list list; 40 | #X msg 291 91 list bang; 41 | #X obj 122 187 print flite-synth-done; 42 | #X connect 0 0 4 0; 43 | #X connect 0 0 16 0; 44 | #X connect 1 0 4 0; 45 | #X connect 1 0 16 0; 46 | #X connect 4 0 31 0; 47 | #X connect 5 0 4 0; 48 | #X connect 6 0 4 0; 49 | #X connect 7 0 4 0; 50 | #X connect 8 0 9 0; 51 | #X connect 9 0 11 1; 52 | #X connect 11 0 10 0; 53 | #X connect 11 0 10 1; 54 | #X connect 12 0 17 0; 55 | #X connect 13 0 17 0; 56 | #X connect 13 0 25 0; 57 | #X connect 14 0 13 0; 58 | #X connect 15 0 12 0; 59 | #X connect 17 0 11 0; 60 | #X connect 17 1 24 0; 61 | #X connect 18 0 17 0; 62 | #X connect 19 0 17 0; 63 | #X connect 20 0 17 0; 64 | #X connect 23 0 4 0; 65 | #X connect 24 0 17 0; 66 | #X connect 25 0 24 1; 67 | #X connect 27 0 4 0; 68 | #X connect 28 0 4 0; 69 | #X connect 29 0 4 0; 70 | #X connect 30 0 4 0; 71 | -------------------------------------------------------------------------------- /flite-test2.pd: -------------------------------------------------------------------------------- 1 | #N canvas 489 199 450 300 10; 2 | #X obj 72 150 flite testary; 3 | #X obj 312 53 table testary; 4 | #X msg 54 13 moo; 5 | #X msg 91 14 is; 6 | #X msg 127 13 a; 7 | #X msg 175 13 cow; 8 | #X msg 175 62 marmoset; 9 | #X msg 176 38 bovine; 10 | #X obj 72 174 tabplay~ testary; 11 | #X obj 181 199 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 12 | -1; 13 | #X obj 110 222 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144 14 | -1 -1 8100 1; 15 | #X obj 107 245 dbtorms; 16 | #X obj 63 247 dac~; 17 | #X obj 72 222 *~ 0; 18 | #X msg 72 109 text \$1 \, synth; 19 | #X obj 72 87 pack s; 20 | #X connect 0 0 8 0; 21 | #X connect 2 0 15 0; 22 | #X connect 3 0 15 0; 23 | #X connect 4 0 15 0; 24 | #X connect 5 0 15 0; 25 | #X connect 6 0 15 0; 26 | #X connect 7 0 15 0; 27 | #X connect 8 0 13 0; 28 | #X connect 8 1 9 0; 29 | #X connect 10 0 11 0; 30 | #X connect 11 0 13 1; 31 | #X connect 13 0 12 0; 32 | #X connect 13 0 12 1; 33 | #X connect 14 0 0 0; 34 | #X connect 15 0 14 0; 35 | -------------------------------------------------------------------------------- /flite.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C -*- */ 2 | /*=============================================================================*\ 3 | * File: flite.c 4 | * Author: Bryan Jurish 5 | * Description: speech synthesis for PD 6 | * 7 | * PD interface to 'flite' C libraries. 8 | * 9 | * v0.3.1 updated by Lucas Cordiviola 10 | * 11 | *=============================================================================*/ 12 | 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | /* black magic for Microsoft's compiler */ 24 | #ifdef _MSC_VER 25 | #pragma warning( disable : 4244 ) 26 | #pragma warning( disable : 4305 ) 27 | #endif 28 | 29 | #ifdef __GNUC__ 30 | # define MOO_UNUSED __attribute__((unused)) 31 | #else 32 | # define MOO_UNUSED 33 | #endif 34 | 35 | 36 | #define debug(fmt, args...) fprintf(stderr, fmt, ##args); 37 | 38 | #include 39 | #if HAVE_FLITE_FLITE_H 40 | # include 41 | # include 42 | #else 43 | # include 44 | # include 45 | #endif 46 | 47 | 48 | /*-------------------------------------------------------------------- 49 | * DEBUG 50 | *--------------------------------------------------------------------*/ 51 | //#define FLITE_DEBUG 1 52 | //#undef FLITE_DEBUG 53 | 54 | 55 | /*-------------------------------------------------------------------- 56 | * Globals 57 | *--------------------------------------------------------------------*/ 58 | 59 | cst_voice *register_cmu_us_awb(); 60 | cst_voice *register_cmu_us_kal(); 61 | cst_voice *register_cmu_us_kal16(); 62 | cst_voice *register_cmu_us_rms(); 63 | cst_voice *register_cmu_us_slt(); 64 | 65 | void usenglish_init(cst_voice *v); 66 | cst_lexicon *cmulex_init(void); 67 | 68 | 69 | 70 | /*===================================================================== 71 | * Structures and Types 72 | *=====================================================================*/ 73 | 74 | static const char *flite_description = 75 | "flite: Text-to-Speech external v" VERSION " \n"; 76 | 77 | static const char *thread_waiting = "flite: Wait for the running thread to finish"; 78 | 79 | 80 | //static char *flite_acknowledge = "flite: based on code by "; 81 | //static char *flite_version = "flite: PD external v%s by Bryan Jurish"; 82 | // "flite: Text-to-Speech external v" VERSION " by Bryan Jurish\n" 83 | 84 | 85 | 86 | 87 | /*--------------------------------------------------------------------- 88 | * flite 89 | *---------------------------------------------------------------------*/ 90 | static t_class *flite_class; 91 | 92 | typedef enum _thrd_request 93 | { 94 | IDLE = 0, 95 | TEXTFILE = 1, 96 | SYNTH = 2, 97 | VOXFILE = 3, 98 | QUIT = 4, 99 | } t_thrd_request; 100 | 101 | typedef enum _thrd_tick 102 | { 103 | FINISHSYNTH = 0, 104 | ARRAYERR = 1, 105 | BUFFERERR = 2, 106 | FAIL = 3, 107 | VOXFILEDONE = 4, 108 | INPROGRESS = 5, 109 | } t_thrd_tick; 110 | 111 | 112 | typedef struct _flite 113 | { 114 | t_object x_obj; /* black magic (probably inheritance-related) */ 115 | t_canvas *x_canvas; 116 | t_symbol *x_arrayname; /* arrayname (from '_tabwrite' code in $PD_SRC/d_array.c) */ 117 | char *x_textbuf; /* text buffer (hack) */ 118 | char x_reqfile[MAXPDSTRING]; 119 | char x_inprogress; 120 | t_outlet *x_bangout; 121 | t_clock *x_clock; 122 | t_thrd_request x_requestcode; 123 | t_thrd_tick x_tick_ctl; 124 | pthread_mutex_t x_mutex; 125 | pthread_cond_t x_requestcondition; 126 | pthread_t x_tid; 127 | int x_argc; 128 | t_atom *x_argv; 129 | cst_voice *x_voice; 130 | cst_wave *x_wave; 131 | int x_vecsize; 132 | t_garray *x_a; 133 | t_word *x_vec; 134 | } t_flite; 135 | 136 | 137 | static void flite_set(t_flite *x, t_symbol *ary); 138 | static int flite_filer(t_flite *x, t_symbol *name); 139 | static void flite_voice(t_flite *x, t_symbol *vox); 140 | static void flite_voice_file(t_flite *x, t_symbol *filename); 141 | static void flite_thrd_voice_file(t_flite *x, t_symbol *filename); 142 | static void flite_threaded_voice_file(t_flite *x); 143 | static void flite_do_voice_file(t_flite *x); 144 | static void flite_do_textbuffer(t_flite *x); 145 | static void flite_text(t_flite *x, MOO_UNUSED t_symbol *s, int argc, t_atom *argv); 146 | static void flite_textfile(t_flite *x, t_symbol *filename); 147 | static void flite_thrd_textfile(t_flite *x, t_symbol *filename); 148 | static void flite_read_textfile(t_flite *x); 149 | static void flite_list(t_flite *x, t_symbol *s, int argc, t_atom *argv); 150 | static void flite_synth(t_flite *x); 151 | static void flite_thread_synth(t_flite *x); 152 | static void flite_thrd_synth(t_flite *x); 153 | static void flite_clock_tick(t_flite *x); 154 | static void flite_thread(t_flite *x); 155 | 156 | 157 | /*-------------------------------------------------------------------- 158 | * flite_set : set arrayname 159 | *--------------------------------------------------------------------*/ 160 | static void flite_set(t_flite *x, t_symbol *ary) { 161 | 162 | if (x->x_inprogress) { 163 | pd_error(x,"%s", thread_waiting); 164 | return; 165 | } 166 | #ifdef FLITE_DEBUG 167 | debug("flite_set: called with arg='%s'\n", ary->s_name); 168 | #endif 169 | x->x_arrayname = ary; 170 | return; 171 | } 172 | 173 | /*-------------------------------------------------------------------- 174 | * flite_filer : get the full path of the file if it exists 175 | * and place it's full path on the struct. 176 | *--------------------------------------------------------------------*/ 177 | static int flite_filer(t_flite *x, t_symbol *name) { 178 | 179 | char completefilename[MAXPDSTRING]; 180 | 181 | const char* filename = name->s_name; 182 | char realdir[MAXPDSTRING], *realname = NULL; 183 | int fd; 184 | fd = canvas_open(x->x_canvas, filename, "", realdir, &realname, MAXPDSTRING, 0); 185 | if(fd < 0){ 186 | pd_error(x, "flite: can't find file: %s", filename); 187 | x->x_inprogress = 0; 188 | return 0; 189 | } 190 | 191 | strcpy(completefilename, realdir); 192 | strcat(completefilename, "/"); 193 | strcat(completefilename, realname); 194 | strcpy(x->x_reqfile, completefilename); 195 | return 1; 196 | } 197 | 198 | /*-------------------------------------------------------------------- 199 | * flite_voice : set one of the built-in voices for the synthesizer. 200 | *--------------------------------------------------------------------*/ 201 | static void flite_voice(t_flite *x, t_symbol *vox) { 202 | 203 | if (x->x_inprogress) { 204 | pd_error(x,"%s", thread_waiting); 205 | return; 206 | } 207 | 208 | #ifdef FLITE_DEBUG 209 | debug("flite_voice: called with arg='%s'\n", vox->s_name); 210 | #endif 211 | 212 | const char *voxstring = vox->s_name; 213 | 214 | if (!strcmp(voxstring, "awb")) { 215 | x->x_voice = register_cmu_us_awb(); 216 | } 217 | else if (!strcmp(voxstring, "kal")) { 218 | x->x_voice = register_cmu_us_kal(); 219 | } 220 | else if (!strcmp(voxstring, "kal16")) { 221 | x->x_voice = register_cmu_us_kal16(); 222 | } 223 | else if (!strcmp(voxstring, "rms")) { 224 | x->x_voice = register_cmu_us_rms(); 225 | } 226 | else if (!strcmp(voxstring, "slt")) { 227 | x->x_voice = register_cmu_us_slt(); 228 | } else { 229 | pd_error(x,"flite: unknown voice '%s'. Possible voices are: 'awb', 'kal', 'kal16', 'rms' or 'slt'.", voxstring ); 230 | return; 231 | } 232 | return; 233 | } 234 | 235 | /*-------------------------------------------------------------------- 236 | * flite_voice_file : check for the voice file and open it. 237 | *--------------------------------------------------------------------*/ 238 | static void flite_voice_file(t_flite *x, t_symbol *filename) { 239 | 240 | if (x->x_inprogress) { 241 | pd_error(x,"%s", thread_waiting); 242 | return; 243 | } 244 | 245 | if(!flite_filer(x, filename)) { 246 | return; 247 | } 248 | flite_do_voice_file(x); 249 | x->x_tick_ctl = VOXFILEDONE; 250 | flite_clock_tick(x); 251 | return; 252 | } 253 | 254 | /*-------------------------------------------------------------------- 255 | * flite_voice_file : check for the voice file and signal the thread to open it. 256 | *--------------------------------------------------------------------*/ 257 | static void flite_thrd_voice_file(t_flite *x, t_symbol *filename) { 258 | 259 | if (x->x_inprogress) { 260 | pd_error(x,"%s", thread_waiting); 261 | return; 262 | } 263 | 264 | if(!flite_filer(x, filename)) { 265 | return; 266 | } 267 | x->x_inprogress = 1; 268 | pthread_mutex_lock(&x->x_mutex); 269 | x->x_requestcode = VOXFILE; 270 | pthread_mutex_unlock(&x->x_mutex); 271 | pthread_cond_signal(&x->x_requestcondition); 272 | return; 273 | } 274 | 275 | /*-------------------------------------------------------------------- 276 | * flite_threaded_voice_file : thread opens the voice file. 277 | *--------------------------------------------------------------------*/ 278 | static void flite_threaded_voice_file(t_flite *x) { 279 | 280 | flite_do_voice_file(x); 281 | pthread_mutex_lock(&x->x_mutex); 282 | if (x->x_requestcode != QUIT) 283 | { 284 | sys_lock(); 285 | x->x_tick_ctl = VOXFILEDONE; 286 | clock_delay(x->x_clock, 0); 287 | sys_unlock(); 288 | } 289 | pthread_mutex_unlock(&x->x_mutex); 290 | return; 291 | } 292 | 293 | /*-------------------------------------------------------------------- 294 | * flite_do_voice_file : open the voice file for the synthesizer. 295 | *--------------------------------------------------------------------*/ 296 | static void flite_do_voice_file(t_flite *x) { 297 | 298 | #ifdef FLITE_DEBUG 299 | debug("flite_thrd_voice_file: called with arg='%s'\n", x->x_reqfile); 300 | #endif 301 | flite_add_lang("eng",usenglish_init,cmulex_init); 302 | flite_add_lang("usenglish",usenglish_init,cmulex_init); 303 | x->x_voice = flite_voice_load(x->x_reqfile); 304 | 305 | } 306 | 307 | /*-------------------------------------------------------------------- 308 | * flite_do_textbuffer : text-buffer 309 | *--------------------------------------------------------------------*/ 310 | static void flite_do_textbuffer(t_flite *x) { 311 | 312 | char *buf; 313 | int length; 314 | if (x->x_inprogress) { 315 | pd_error(x,"%s", thread_waiting); 316 | return; 317 | } 318 | t_binbuf*bbuf = binbuf_new(); 319 | binbuf_add(bbuf, x->x_argc, x->x_argv); 320 | binbuf_gettext(bbuf, &buf, &length); 321 | binbuf_free(bbuf); 322 | x->x_textbuf = (char *) calloc(length+1, sizeof(char)); 323 | memcpy(x->x_textbuf, buf, length); 324 | freebytes(buf, length+1); 325 | 326 | #ifdef FLITE_DEBUG 327 | debug("flite_debug: got text='%s'\n", x->x_textbuf); 328 | #endif 329 | return; 330 | 331 | } 332 | 333 | /*-------------------------------------------------------------------- 334 | * flite_text : set the text-buffer 335 | *--------------------------------------------------------------------*/ 336 | static void flite_text(t_flite *x, MOO_UNUSED t_symbol *s, int argc, t_atom *argv) { 337 | 338 | if (x->x_inprogress) { 339 | pd_error(x,"%s", thread_waiting); 340 | return; 341 | } 342 | x->x_argc = argc; 343 | x->x_argv = argv; 344 | flite_do_textbuffer(x); 345 | return; 346 | } 347 | 348 | /*-------------------------------------------------------------------- 349 | * flite_textfile : if the file exists read it into the text-buffer and 350 | * synthesize it. 351 | *--------------------------------------------------------------------*/ 352 | static void flite_textfile(t_flite *x, t_symbol *filename) { 353 | 354 | if (x->x_inprogress) { 355 | pd_error(x,"%s", thread_waiting); 356 | return; 357 | } 358 | if(!flite_filer(x, filename)) { 359 | return; 360 | } 361 | flite_read_textfile(x); 362 | flite_synth(x); 363 | return; 364 | } 365 | 366 | /*-------------------------------------------------------------------- 367 | * flite_thrd_textfile : if the file exists call the thread to read it 368 | * into the text-buffer and synthesize it. 369 | *--------------------------------------------------------------------*/ 370 | static void flite_thrd_textfile(t_flite *x, t_symbol *filename) { 371 | 372 | if (x->x_inprogress) { 373 | pd_error(x,"%s", thread_waiting); 374 | return; 375 | } 376 | 377 | if(!flite_filer(x, filename)) { 378 | return; 379 | } 380 | 381 | // -- sanity checks 382 | if (!(x->x_a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { 383 | pd_error(x,"flite: no such array '%s'", x->x_arrayname->s_name); 384 | return; 385 | } 386 | 387 | x->x_inprogress = 1; 388 | pthread_mutex_lock(&x->x_mutex); 389 | x->x_requestcode = TEXTFILE; 390 | pthread_mutex_unlock(&x->x_mutex); 391 | pthread_cond_signal(&x->x_requestcondition); 392 | return; 393 | } 394 | 395 | /*-------------------------------------------------------------------- 396 | * flite_read_textfile : read the text file into the text-buffer 397 | *--------------------------------------------------------------------*/ 398 | static void flite_read_textfile(t_flite *x) { 399 | 400 | FILE *fp; 401 | fp = fopen(x->x_reqfile, "r"); 402 | fseek(fp, 0, SEEK_END); 403 | int len; 404 | len = ftell(fp); 405 | fseek(fp, 0, SEEK_SET); 406 | x->x_textbuf = (char *) calloc(len+1, sizeof(char)); 407 | fread(x->x_textbuf, 1, len, fp); 408 | fclose(fp); 409 | return; 410 | } 411 | 412 | /*-------------------------------------------------------------------- 413 | * flite_list : parse & synthesize text in one swell foop 414 | *--------------------------------------------------------------------*/ 415 | static void flite_list(t_flite *x, t_symbol *s, int argc, t_atom *argv) { 416 | 417 | if (x->x_inprogress) { 418 | pd_error(x,"%s", thread_waiting); 419 | return; 420 | } 421 | flite_text(x,s,argc,argv); 422 | flite_synth(x); 423 | return; 424 | } 425 | 426 | 427 | 428 | /*-------------------------------------------------------------------- 429 | * flite_synth : synthesize current text-buffer 430 | *--------------------------------------------------------------------*/ 431 | static void flite_synth(t_flite *x) { 432 | 433 | if (x->x_inprogress) { 434 | pd_error(x,"%s", thread_waiting); 435 | return; 436 | } 437 | 438 | #ifdef FLITE_DEBUG 439 | debug("flite: got message 'synth'\n"); 440 | #endif 441 | 442 | // -- sanity checks 443 | if (!(x->x_a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { 444 | x->x_tick_ctl = ARRAYERR; 445 | flite_clock_tick(x); 446 | return; 447 | } 448 | if (!x->x_textbuf) { 449 | x->x_tick_ctl = BUFFERERR; 450 | flite_clock_tick(x); 451 | return; 452 | } 453 | 454 | #ifdef FLITE_DEBUG 455 | debug("flite: flite_text_to_wave()\n"); 456 | #endif 457 | x->x_wave = flite_text_to_wave(x->x_textbuf, x->x_voice); 458 | 459 | if (!x->x_wave) { 460 | x->x_tick_ctl = FAIL; 461 | flite_clock_tick(x); 462 | return; 463 | } 464 | 465 | // -- resample 466 | #ifdef FLITE_DEBUG 467 | debug("flite: cst_wave_resample()\n"); 468 | #endif 469 | 470 | cst_wave_resample(x->x_wave, sys_getsr()); 471 | x->x_tick_ctl = FINISHSYNTH; 472 | flite_clock_tick(x); 473 | return; 474 | } 475 | 476 | /*-------------------------------------------------------------------- 477 | * flite_thread_synth : thread synthesizes the current text-buffer. 478 | *--------------------------------------------------------------------*/ 479 | static void flite_thread_synth(t_flite *x) { 480 | 481 | 482 | #ifdef FLITE_DEBUG 483 | debug("flite: got message 'synth'\n"); 484 | #endif 485 | 486 | if (!x->x_textbuf) 487 | { 488 | pthread_mutex_lock(&x->x_mutex); 489 | if (x->x_requestcode != QUIT) 490 | { 491 | sys_lock(); 492 | x->x_tick_ctl = BUFFERERR; 493 | clock_delay(x->x_clock, 0); 494 | sys_unlock(); 495 | pthread_mutex_unlock(&x->x_mutex); 496 | return; 497 | } 498 | } 499 | 500 | #ifdef FLITE_DEBUG 501 | debug("flite: flite_text_to_wave()\n"); 502 | #endif 503 | x->x_wave = flite_text_to_wave(x->x_textbuf, x->x_voice); 504 | 505 | if (!x->x_wave) 506 | { 507 | pthread_mutex_lock(&x->x_mutex); 508 | if (x->x_requestcode != QUIT) 509 | { 510 | sys_lock(); 511 | x->x_tick_ctl = FAIL; 512 | clock_delay(x->x_clock, 0); 513 | sys_unlock(); 514 | pthread_mutex_unlock(&x->x_mutex); 515 | return; 516 | } 517 | } 518 | 519 | // -- resample 520 | #ifdef FLITE_DEBUG 521 | debug("flite: cst_wave_resample()\n"); 522 | #endif 523 | cst_wave_resample(x->x_wave, sys_getsr()); 524 | 525 | pthread_mutex_lock(&x->x_mutex); 526 | if (x->x_requestcode != QUIT) 527 | { 528 | sys_lock(); 529 | x->x_tick_ctl = FINISHSYNTH; 530 | clock_delay(x->x_clock, 0); 531 | sys_unlock(); 532 | } 533 | pthread_mutex_unlock(&x->x_mutex); 534 | return; 535 | } 536 | 537 | /*-------------------------------------------------------------------- 538 | * flite_thrd_synth : call the thread to synthesize the text-buffer. 539 | *--------------------------------------------------------------------*/ 540 | static void flite_thrd_synth(t_flite *x) { 541 | 542 | if (x->x_inprogress) { 543 | pd_error(x,"%s", thread_waiting); 544 | return; 545 | } 546 | // -- sanity checks 547 | if (!(x->x_a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { 548 | pd_error(x,"flite: no such array '%s'", x->x_arrayname->s_name); 549 | return; 550 | } 551 | x->x_inprogress = 1; 552 | pthread_mutex_lock(&x->x_mutex); 553 | x->x_requestcode = SYNTH; 554 | pthread_mutex_unlock(&x->x_mutex); 555 | pthread_cond_signal(&x->x_requestcondition); 556 | return; 557 | } 558 | 559 | /*-------------------------------------------------------------------- 560 | * flite_clock_tick : clock 561 | *--------------------------------------------------------------------*/ 562 | 563 | static void flite_clock_tick(t_flite *x) 564 | { 565 | 566 | if (x->x_tick_ctl == FINISHSYNTH) { 567 | 568 | int i; 569 | 570 | // -- resize & write to our array 571 | #ifdef FLITE_DEBUG 572 | debug("flite: garray_resize(%d)\n", x->x_wave->num_samples); 573 | #endif 574 | 575 | garray_resize_long(x->x_a, (long) x->x_wave->num_samples); 576 | if (!garray_getfloatwords(x->x_a, &x->x_vecsize, &x->x_vec)) { 577 | pd_error(x,"flite: bad template for write to array '%s'", x->x_arrayname->s_name); 578 | x->x_inprogress = 0; 579 | return; 580 | } 581 | 582 | #ifdef FLITE_DEBUG 583 | debug("flite: ->write to garray loop<-\n"); 584 | #endif 585 | for (i = 0; i < x->x_wave->num_samples; i++) { 586 | x->x_vec->w_float = x->x_wave->samples[i]/32767.0; 587 | x->x_vec++; 588 | } 589 | // -- cleanup 590 | delete_wave(x->x_wave); 591 | // -- redraw 592 | garray_redraw(x->x_a); 593 | 594 | outlet_bang(x->x_bangout); 595 | 596 | } else if (x->x_tick_ctl == ARRAYERR) { 597 | pd_error(x,"flite: no such array '%s'", x->x_arrayname->s_name); 598 | } else if (x->x_tick_ctl == BUFFERERR) { 599 | pd_error(x,"flite: attempt to synthesize empty text-buffer!"); 600 | } else if (x->x_tick_ctl == FAIL) { 601 | pd_error(x,"flite: synthesis failed for text '%s'", x->x_textbuf); 602 | } else if (x->x_tick_ctl == INPROGRESS) { 603 | pd_error(x,"%s", thread_waiting); 604 | } else if (x->x_tick_ctl == VOXFILEDONE) { 605 | logpost(x,2,"Flite: successfully loaded '%s'", x->x_reqfile); 606 | } 607 | x->x_inprogress = 0; 608 | return; 609 | } 610 | 611 | 612 | /*-------------------------------------------------------------------- 613 | * flite_thread : thread 614 | *--------------------------------------------------------------------*/ 615 | static void flite_thread(t_flite *x) { 616 | 617 | while (1) { 618 | pthread_mutex_lock(&x->x_mutex); 619 | while (x->x_requestcode == IDLE) { 620 | #ifdef FLITE_DEBUG 621 | debug("pthread_cond_wait(\n"); 622 | #endif 623 | pthread_cond_wait(&x->x_requestcondition, &x->x_mutex); 624 | } 625 | if (x->x_requestcode == SYNTH) 626 | { 627 | pthread_mutex_unlock(&x->x_mutex); 628 | #ifdef FLITE_DEBUG 629 | debug("thread synth\n"); 630 | #endif 631 | flite_thread_synth(x); 632 | pthread_mutex_lock(&x->x_mutex); 633 | if (x->x_requestcode == SYNTH) 634 | x->x_requestcode = IDLE; 635 | pthread_mutex_unlock(&x->x_mutex); 636 | } 637 | else if (x->x_requestcode == TEXTFILE) 638 | { 639 | pthread_mutex_unlock(&x->x_mutex); 640 | flite_read_textfile(x); 641 | flite_thread_synth(x); 642 | pthread_mutex_lock(&x->x_mutex); 643 | if (x->x_requestcode == TEXTFILE) 644 | x->x_requestcode = IDLE; 645 | pthread_mutex_unlock(&x->x_mutex); 646 | } 647 | else if (x->x_requestcode == VOXFILE) 648 | { 649 | pthread_mutex_unlock(&x->x_mutex); 650 | flite_threaded_voice_file(x); 651 | pthread_mutex_lock(&x->x_mutex); 652 | if (x->x_requestcode == VOXFILE) 653 | x->x_requestcode = IDLE; 654 | pthread_mutex_unlock(&x->x_mutex); 655 | } 656 | else if (x->x_requestcode == QUIT) 657 | { 658 | pthread_mutex_unlock(&x->x_mutex); 659 | break; 660 | } 661 | } 662 | #ifdef FLITE_DEBUG 663 | debug("thread quit\n"); 664 | #endif 665 | return; 666 | } 667 | static void*flite_do_thread(void *z) 668 | { 669 | t_flite *x = (t_flite*)z; 670 | flite_thread(x); 671 | return 0; 672 | } 673 | 674 | /*-------------------------------------------------------------------- 675 | * constructor 676 | *--------------------------------------------------------------------*/ 677 | static void *flite_new(t_symbol *ary) 678 | { 679 | t_flite *x; 680 | 681 | x = (t_flite *)pd_new(flite_class); 682 | 683 | x->x_clock = clock_new(x, (t_method)flite_clock_tick); 684 | 685 | // set initial arrayname 686 | x->x_arrayname = ary; 687 | 688 | // init x_textbuf 689 | x->x_textbuf = NULL; 690 | 691 | // create bang-on-done outlet 692 | x->x_bangout = outlet_new(&x->x_obj, &s_bang); 693 | 694 | // default voice 695 | x->x_voice = register_cmu_us_kal16(); 696 | 697 | x->x_canvas = canvas_getcurrent(); 698 | x->x_inprogress = 0; 699 | x->x_requestcode = IDLE; 700 | pthread_mutex_init(&x->x_mutex, 0); 701 | pthread_cond_init(&x->x_requestcondition, 0); 702 | pthread_create(&x->x_tid, 0, flite_do_thread, x); 703 | 704 | return (void *)x; 705 | } 706 | 707 | /*-------------------------------------------------------------------- 708 | * destructor 709 | *--------------------------------------------------------------------*/ 710 | static void flite_free(t_flite *x) { 711 | 712 | #ifdef FLITE_DEBUG 713 | debug("free\n"); 714 | #endif 715 | pthread_mutex_lock(&x->x_mutex); 716 | x->x_requestcode = QUIT; 717 | pthread_mutex_unlock(&x->x_mutex); 718 | pthread_cond_signal(&x->x_requestcondition); 719 | pthread_join(x->x_tid, NULL); 720 | pthread_cond_destroy(&x->x_requestcondition); 721 | pthread_mutex_destroy(&x->x_mutex); 722 | free(x->x_textbuf); 723 | clock_free(x->x_clock); 724 | } 725 | 726 | /*-------------------------------------------------------------------- 727 | * setup 728 | *--------------------------------------------------------------------*/ 729 | #if defined(_WIN32) 730 | __declspec(dllexport) 731 | #else 732 | __attribute__((visibility("default"))) 733 | #endif 734 | void flite_setup(void) { 735 | post(""); 736 | post(flite_description); 737 | post(""); 738 | 739 | // --- setup synth 740 | flite_init(); 741 | 742 | 743 | // --- register class 744 | flite_class = class_new(gensym("flite"), 745 | (t_newmethod)flite_new, // newmethod 746 | (t_method)flite_free, // freemethod 747 | sizeof(t_flite), // size 748 | CLASS_DEFAULT, // flags 749 | A_DEFSYM, // arg1: table-name 750 | 0); 751 | 752 | // --- class methods 753 | class_addlist(flite_class, flite_list); 754 | class_addmethod(flite_class, (t_method)flite_set, gensym("set"), A_DEFSYM, 0); 755 | class_addmethod(flite_class, (t_method)flite_text, gensym("text"), A_GIMME, 0); 756 | class_addmethod(flite_class, (t_method)flite_synth, gensym("synth"), 0); 757 | class_addmethod(flite_class, (t_method)flite_voice, gensym("voice"), A_DEFSYM, 0); 758 | class_addmethod(flite_class, (t_method)flite_voice_file, gensym("voice_file"), A_DEFSYM, 0); 759 | class_addmethod(flite_class, (t_method)flite_thrd_voice_file, gensym("thrd_voice_file"), A_DEFSYM, 0); 760 | class_addmethod(flite_class, (t_method)flite_textfile, gensym("textfile"), A_DEFSYM, 0); 761 | class_addmethod(flite_class, (t_method)flite_thrd_synth, gensym("thrd_synth"), 0); 762 | class_addmethod(flite_class, (t_method)flite_thrd_textfile, gensym("thrd_textfile"), A_DEFSYM, 0); 763 | 764 | // --- help patch 765 | //class_sethelpsymbol(flite_class, gensym("flite-help.pd")); /* breaks pd-extended help lookup */ 766 | } 767 | -------------------------------------------------------------------------------- /pd-lib-builder/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Changelog for Makefile.pdlibbuilder. 2 | 3 | v0.6.0, dated 2019-12-21 4 | - detect target platform (OS and architecture) rather than build platform (#55) 5 | - introduce optional user variable 'PLATFORM' for cross compilation 6 | - no longer build OSX/MacOS fat binaries by default (#21, #50) 7 | - do build fat binaries when 'extension=d_fat' is specified for OSX/MacOS 8 | - fix bug where minimum OSX/MacOS version wasn't defined, and set it to 10.6 9 | 10 | v0.5.1, dated 2018-03-15 11 | Fixes and improvements for Windows builds: 12 | - properly evaluate variables 'PDDIR' and 'PDBINDIR' to find pd.dll 13 | - define default path of 32 bit Pd on 64 bit Windows 14 | - link C++ externals with standard C libs on Windows, they don't load otherwise 15 | - strip installed Windows binaries by default 16 | (issues #34, #39, #41, #42 respectively) 17 | Warning for all platforms: variable 'PD_PATH' is no longer supported, use the 18 | equivalent 'PDDIR'. 19 | 20 | v0.5.0, dated 2018-01-23 21 | Implement target architecture detection for Windows builds, 22 | and set appropriate options for 32 and 64 bit (used to be for 32 bit only). 23 | (feature, issue #37 #38, merge commit 215bf3e) 24 | 25 | v0.4.4, dated 2016-11-22 26 | Use variable 'system' when evaluating 'for{Linux,Darwin,Windows}' 27 | (bugfix, issue #31, commit 2c14110) 28 | 29 | v0.4.3, dated 2016-11-02 30 | Replace flags '-fpic' by 'fPIC'. 31 | (bugfix, issue #29, commit 426b38b) 32 | 33 | v0.4.2, dated 2016-10-30 34 | Fix issue where incorrect message about m_pd.h is given. 35 | (bugfix, commit 2e13d8f) 36 | 37 | v0.4.1, dated 2016-10-27 38 | Respect cflag for minimum OSX version when defined by lib makefile. 39 | (bugfix, pull request #22, commit 48c4127) 40 | 41 | v0.4.0, dated 2016-10-14 42 | Introduced path variables PDDIR, PDINCLUDEDIR, PDBINDIR, PDLIBDIR which can 43 | also be defined in environment. 44 | (feature, issue #27, commit b0dab72) 45 | 46 | v0.3.1, dated 2016-10-13 47 | Fix bug where pd.dll wouldn't be found. 48 | (bugfix, commit a0c87be) 49 | 50 | v0.3.0, dated 2016-10-09 51 | Variable 'PD_PATH' introduced for pd-extended / pd-l2ork compatibility. 52 | (feature, issue #26, commit 41e9743) 53 | 54 | v0.2.8, dated 2016-10-09 55 | Allow installed files to contain weird characters (notably '$'). 56 | (bugfix, pull request #20, commit 5b920b1) 57 | 58 | v0.2.7, dated 2016-10-04 59 | Remove all default pd search paths except vanilla's. 60 | (discussion, issue #25, commit a6a89dc) 61 | 62 | v0.2.6, dated 2016-09-20 63 | Redefined dependency checking so it won't stall rebuilds on OSX. 64 | (bugfix, issue #16, commit 9fd1795) 65 | 66 | v0.2.5, dated 2016-06-26 67 | Fixed dependency checking for object files in other directories. 68 | (bugfix, commit f06e550) 69 | 70 | v0.2.4, dated 2016-06-25 71 | Fixed regression bug that disabled all dependency checking. 72 | (bugfix, commit 1d7bb5e) 73 | 74 | v0.2.3, dated 2016-03-29 75 | Disabled dependency checking for OSX <= 10.5 because it stalled rebuilds. 76 | (bugfix, issue #16, commit eb614fd) 77 | 78 | v0.2.2, dated 2016-03-28 79 | Removed target 'pre' because it forced rebuild of everything in 'all'. 80 | (bugfix, issue #17, commit c989c8e) 81 | 82 | v0.2.1, dated 2015-12-27 83 | Implement / respect 'CPPFLAGS','CFLAGS'and 'LDFLAGS'. 84 | (bugfix, issue #5, commit 98f3582) 85 | 86 | v0.2.0, dated 2015-12-19 87 | Added per-platform multiline defines 'forLinux', 'forDarwin', 'forWindows'. 88 | (feature, pull request #9, commit 3946ea5) 89 | 90 | v0.1.0, dated 2015-12-08 91 | Added targets 'pre' and 'post' to automatically run before and after 'all'. 92 | (feature, pull request #4, commit a5678ac) 93 | 94 | v0.0.2, dated 2015-12-06 95 | Improved methods for searching pd paths. 96 | (bugfix, commit ed37e6b) 97 | 98 | v0.0.1, dated 2015-10-31 99 | Fixed expansion of variable 'lib.version'. 100 | (bugfix, issue #1, commit 974b617) 101 | 102 | v0.0.0, dated 2015-06-24 103 | Initial version. 104 | (commit 16517a2) 105 | -------------------------------------------------------------------------------- /pd-lib-builder/Makefile.pdlibbuilder: -------------------------------------------------------------------------------- 1 | # Makefile.pdlibbuilder dated 2019-12-21 2 | version = 0.6.0 3 | 4 | # Helper makefile for Pure Data external libraries. 5 | # Written by Katja Vetter March-June 2015 for the public domain. No warranties. 6 | # Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's 7 | # ShakeNMake. 8 | # 9 | # Grab the newest version of Makefile.pdlibbuilder from 10 | # https://github.com/pure-data/pd-lib-builder/ 11 | # 12 | # GNU make version >= 3.81 required. 13 | # 14 | # 15 | #=== characteristics =========================================================== 16 | # 17 | # 18 | # - defines build settings based on autodetected OS and architecture 19 | # - defines rules to build Pd class- or lib executables from C or C++ sources 20 | # - defines rules for libdir installation 21 | # - defines convenience targets for developer and user 22 | # - evaluates implicit dependencies for non-clean builds 23 | # 24 | # 25 | #=== basic usage =============================================================== 26 | # 27 | # 28 | # In your Makefile, define your Pd lib name and class files, and include 29 | # Makefile.pdlibbuilder at the end of the Makefile. Like so: 30 | # 31 | # ________________________________________________________________________ 32 | # 33 | # # Makefile for mylib 34 | # 35 | # lib.name = mylib 36 | # 37 | # class.sources = myclass1.c myclass2.c 38 | # 39 | # datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt 40 | # 41 | # include Makefile.pdlibbuilder 42 | # ________________________________________________________________________ 43 | # 44 | # 45 | # For files in class.sources it is assumed that class basename == source file 46 | # basename. The default target builds all classes as individual executables 47 | # with Pd's default extension for the platform. For anything more than the 48 | # most basic usage, continue reading. 49 | # 50 | # 51 | #=== list of Makefile.pdlibbuilder API variables =============================== 52 | # 53 | # 54 | # Variables available for definition in your library Makefile: 55 | # 56 | # - lib.name 57 | # - lib.setup.sources 58 | # - class.sources 59 | # - common.sources 60 | # - shared.sources 61 | # - .class.sources 62 | # - .class.ldflags 63 | # - .class.ldlibs 64 | # - cflags 65 | # - ldflags 66 | # - ldlibs 67 | # - datafiles 68 | # - datadirs 69 | # - makefiles 70 | # - makefiledirs 71 | # - externalsdir 72 | # 73 | # Optional multiline defines evaluated per operating system: 74 | # 75 | # - forLinux 76 | # - forDarwin 77 | # - forWindows 78 | # 79 | # Variables available for your makefile or make command line: 80 | # 81 | # - make-lib-executable 82 | # - suppress-wunused 83 | # 84 | # Path variables for make command line or environment: 85 | # 86 | # - PDDIR 87 | # - PDINCLUDEDIR 88 | # - PDBINDIR 89 | # - PDLIBDIR 90 | # 91 | # Standard make variables for make command line or environment: 92 | # 93 | # - CPPFLAGS 94 | # - CFLAGS 95 | # - LDFLAGS 96 | # - CC 97 | # - CXX 98 | # - INSTALL 99 | # - STRIP 100 | # - DESTDIR 101 | # 102 | # Optional user variables for make command line or environment: 103 | # 104 | # - PLATFORM 105 | # 106 | # Deprecated path variables: 107 | # 108 | # - pdincludepath 109 | # - pdbinpath 110 | # - objectsdir 111 | # 112 | # 113 | #=== descriptions of Makefile.pdlibbuilder API variables ======================= 114 | # 115 | # 116 | # lib.name: 117 | # Name of the library directory as it will be installed / distributed. Also the 118 | # name of the lib executable in the case where all classes are linked into 119 | # a single binary. 120 | # 121 | # lib.setup.sources: 122 | # Source file(s) (C or C++) which must be compiled only when linking all classes 123 | # into a single lib binary. 124 | # 125 | # class.sources: 126 | # All sources files (C or C++) for which the condition holds that 127 | # class name == source file basename. 128 | # 129 | # .class.sources: 130 | # Source file(s) (C or C++) specific to class . Use this for 131 | # multiple-source classes or when class name != source file basename. 132 | # 133 | # common.sources: 134 | # Source file(s) which must be statically linked to each class in the library. 135 | # 136 | # shared.sources: 137 | # Source file(s) (C or C++) to build a shared dynamic link lib, to be linked 138 | # with all class executables. 139 | # 140 | # cflags, ldflags, ldlibs: 141 | # Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic 142 | # link libs) for the whole library. These flags are added to platform-specific 143 | # flags defined by Makefile.pdlibbuilder. 144 | # 145 | # .class.ldflags and .class.ldlibs: 146 | # Define ldflags resp. ldlibs specific to class . These flags are 147 | # added to platform-specific flags defined by Makefile.pdlibbuilder, and flags 148 | # defined in your Makefile for the whole library. Note: cflags can not be 149 | # defined per class in the current implementation. 150 | # 151 | # datafiles and datadirs: 152 | # All extra files you want to include in binary distributions of the 153 | # library: abstractions and help patches, example patches, meta patch, readme 154 | # and license texts, manuals, sound files, etcetera. Use 'datafiles' for all 155 | # files that should go into your lib rootdir and 'datadirs' for complete 156 | # directories you want to copy from source to distribution. 157 | # 158 | # forLinux, forDarwin, forWindows: 159 | # Shorthand for 'variable definitions for Linux only' etc. Use like: 160 | # define forLinux 161 | # cflags += -DLINUX 162 | # class.sources += linuxthing.c 163 | # endef 164 | # 165 | # makefiles and makefiledirs: 166 | # Extra makefiles or directories with makefiles that should be made in sub-make 167 | # processes. 168 | # 169 | # make-lib-executable: 170 | # When this variable is defined 'yes' in your makefile or as command argument, 171 | # Makefile.pdlibbuilder will try to build all classes into a single library 172 | # executable (but it will force exit if lib.setup.sources is undefined). 173 | # If your makefile defines 'make-lib-executable=yes' as the library default, 174 | # this can still be overridden with 'make-lib-executable=no' as command argument 175 | # to build individual class executables (the Makefile.pdlibbuilder default.) 176 | # 177 | # suppress-wunused: 178 | # When this variable is defined ('yes' or any other value), -Wunused-variable, 179 | # -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed, 180 | # but the other warnings from -Wall are retained. 181 | # 182 | # PDDIR: 183 | # Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and 184 | # PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. 185 | # 186 | # PDINCLUDEDIR: 187 | # Directory where Pd API m_pd.h should be found, and other Pd header files. 188 | # Overrides the default search path. 189 | # 190 | # PDBINDIR: 191 | # Directory where pd.dll should be found for linking (Windows only). Overrides 192 | # the default search path. 193 | # 194 | # PDLIBDIR: 195 | # Root directory for installation of Pd library directories. Overrides the 196 | # default install location. 197 | # 198 | # DESTDIR: 199 | # Prepended path component for staged install. 200 | # 201 | # PLATFORM: 202 | # Target platform for cross compilation in the form of GNU triplet: 203 | # cpu-vendor-os. Example: x86_64-w64-mingw32. This specifies the tool chain that 204 | # pdlibbuilder will use, if installed and locatable. System and architecture 205 | # will then be autodefined accordingly. In most cases no other variables need to 206 | # be overridden. 207 | # 208 | # CPPFLAGS: 209 | # Preprocessor flags which are not strictly required for building. 210 | # 211 | # CFLAGS: 212 | # Compiler flags which are not strictly required for building. Compiler flags 213 | # defined by Makefile.pdlibbuilder for warning, optimization and architecture 214 | # specification are overriden by CFLAGS. 215 | # 216 | # LDFLAGS: 217 | # Linker flags which are not strictly required for building. Linker flags 218 | # defined by Makefile.pdlibbuilder for architecture specification are overriden 219 | # by LDFLAGS. 220 | # 221 | # CC and CXX: 222 | # C and C++ compiler programs as defined in your build environment. 223 | # 224 | # INSTALL 225 | # Definition of install program. 226 | # 227 | # STRIP 228 | # Name of strip program. Default 'strip' can be overridden in cross compilation 229 | # environments. 230 | # 231 | # objectsdir: 232 | # Root directory for installation of Pd library directories, like PDLIBDIR but 233 | # not overridable by environment. Supported for compatibility with pd-extended 234 | # central makefile, but deprecated otherwise. 235 | # 236 | # pdincludepath, pdbinpath: 237 | # As PDINCLUDEDIR and PDBINDIR but not overridable by environment. Deprecated 238 | # as user variables. 239 | # 240 | # 241 | #=== paths ===================================================================== 242 | # 243 | # 244 | # Source files in directories other than current working directory must be 245 | # prefixed with their relative path. Do not rely on VPATH or vpath. 246 | # Object (.o) files are built in the directory of their source files. 247 | # Executables are built in current working directory. 248 | # 249 | # Default search path for m_pd.h and other API header files is platform 250 | # dependent, and overridable by PDINCLUDEDIR: 251 | # 252 | # Linux: /usr/include/pd 253 | # 254 | # OSX: /Applications/Pd*.app/Contents/Resources/src 255 | # 256 | # Windows: %PROGRAMFILES%/Pd/src 257 | # %PROGRAMFILES(X86)%/Pd/src (32 bit builds on 64 bit Windows) 258 | # 259 | # Default search path for binary pd.dll (Windows), overridable by PDBINDIR 260 | # 261 | # %PROGRAMFILES%/Pd/bin 262 | # %PROGRAMFILES(X86)%/Pd/bin (32 bit builds on 64 bit Windows) 263 | # 264 | # Default location to install pd libraries is platform dependent, and 265 | # overridable by PDLIBDIR: 266 | # 267 | # Linux: /usr/local/lib/pd-externals 268 | # OSX: ~/Library/Pd 269 | # Windows: %APPDATA%/Pd 270 | # 271 | # https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files 272 | # The rationale for not installing to ~/pd-externals by default on Linux 273 | # is that some people share the home dir between 32 and 64 bit installations. 274 | # 275 | # 276 | #=== targets =================================================================== 277 | # 278 | # 279 | # all: build $(executables) plus optional post target 280 | # post: target to build after $(executables) 281 | # alldebug: build all with -g option turned on for debug symbols 282 | # : force clean build of an individual class 283 | # .pre: make preprocessor output file in current working directory 284 | # .lst: make asm/source output file in current working directory 285 | # 286 | # install: install executables and data files 287 | # clean: remove build products from source tree 288 | # 289 | # help: print help text 290 | # vars: print makefile variables 291 | # allvars: print all variables 292 | # depend: print generated prerequisites 293 | # dumpmachine: print compiler output of option '-dumpmachine' 294 | # coffee: dummy target 295 | # 296 | # Variable $(executables) expands to class executables plus optional shared lib, 297 | # or alternatively to single lib executable when make-lib-executable=true. 298 | # Targets pre and post can be defined by library makefile. Make sure to include 299 | # Makefile.pdlibbuilder first so default target all will not be redefined. 300 | # 301 | # 302 | #=== Pd-extended libdir concept ================================================ 303 | # 304 | # 305 | # For libdir layout as conceived by Hans-Christoph Steiner, see: 306 | # 307 | # https://puredata.info/docs/developer/Libdir 308 | # 309 | # Files README.txt, LICENSE.txt and -meta.pd are part of the libdir 310 | # convention. Help patches for each class and abstraction are supposed to be 311 | # available. Makefile.pdlibbuilder does not force the presence of these files 312 | # however. It does not automatically include such files in libdir installations. 313 | # Data files you want to include in distributions must be defined explicitly in 314 | # your Makefile. 315 | # 316 | # 317 | #=== Makefile.pdlibbuilder syntax conventions ================================== 318 | # 319 | # 320 | # Makefile.pdlibbuilder variable names are lower case. Default make variables, 321 | # environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR) 322 | # are upper case. Use target 'allvars' to print all variables and their values. 323 | # 324 | # 'Fields' in data variables are separated by dots, like in 'foo.class.sources'. 325 | # Words in variables expressing a function or command are separated by dashes, 326 | # like in 'make-lib-executable'. 327 | # 328 | # 329 | #=== useful make options ======================================================= 330 | # 331 | # 332 | # Use 'make -d ' to print debug details of the make process. 333 | # Use 'make -p ' to print make's database. 334 | # 335 | # 336 | #=== TODO ====================================================================== 337 | # 338 | # 339 | # - decide whether to use -static-libgcc or shared dll in MinGW 340 | # - cygwin support 341 | # - android support 342 | # - figure out how to handle '$' in filenames 343 | # - add makefile template targets dpkg-source dist libdir distclean tags? 344 | # 345 | # 346 | #=== end of documentation sections ============================================= 347 | # 348 | # 349 | ################################################################################ 350 | ################################################################################ 351 | ################################################################################ 352 | 353 | 354 | # GNU make version 3.81 (2006) or higher is required because of the following: 355 | # - function 'info' 356 | # - variable '.DEFAULT_GOAL' 357 | 358 | # force exit when make version is < 3.81 359 | ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81) 360 | $(error GNU make version 3.81 or higher is required) 361 | endif 362 | 363 | # Relative path to externals root dir in multi-lib source tree like 364 | # pd-extended SVN. Default is parent of current working directory. May be 365 | # defined differently in including makefile. 366 | externalsdir ?= .. 367 | 368 | # variable you can use to check if Makefile.pdlibbuilder is already included 369 | Makefile.pdlibbuilder = true 370 | 371 | 372 | ################################################################################ 373 | ### variables: library name and version ######################################## 374 | ################################################################################ 375 | 376 | 377 | # strip possibles spaces from lib.name, they mess up calculated file names 378 | lib.name := $(strip $(lib.name)) 379 | 380 | # if meta file exists, check library version 381 | metafile := $(wildcard $(lib.name)-meta.pd) 382 | 383 | ifdef metafile 384 | lib.version := $(shell sed -n \ 385 | 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \ 386 | $(metafile)) 387 | endif 388 | 389 | 390 | ################################################################################ 391 | ### variables: files ########################################################### 392 | ################################################################################ 393 | 394 | 395 | #=== sources =================================================================== 396 | 397 | 398 | # (re)define .class.sources using file names in class.sources 399 | 400 | define add-class-source 401 | $(notdir $(basename $v)).class.sources += $v 402 | endef 403 | 404 | $(foreach v, $(class.sources), $(eval $(add-class-source))) 405 | 406 | # derive class names from .class.sources variables 407 | sourcevariables := $(filter %.class.sources, $(.VARIABLES)) 408 | classes := $(basename $(basename $(sourcevariables))) 409 | 410 | # accumulate all source files specified in makefile 411 | classes.sources := $(sort $(foreach v, $(sourcevariables), $($v))) 412 | all.sources := $(classes.sources) $(lib.setup.sources) \ 413 | $(shared.sources) $(common.sources) 414 | 415 | 416 | #=== object files ============================================================== 417 | 418 | 419 | # construct object filenames from all C and C++ source file names 420 | classes.objects := $(addsuffix .o, $(basename $(classes.sources))) 421 | common.objects := $(addsuffix .o, $(basename $(common.sources))) 422 | shared.objects := $(addsuffix .o, $(basename $(shared.sources))) 423 | lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources))) 424 | all.objects = $(classes.objects) $(common.objects) $(shared.objects) \ 425 | $(lib.setup.objects) 426 | 427 | 428 | #=== executables =============================================================== 429 | 430 | 431 | # use recursive variables here because executable extension is not yet known 432 | 433 | # construct class executable names from class names 434 | classes.executables = $(addsuffix .$(extension), $(classes)) 435 | 436 | # construct shared lib executable name if shared sources are defined 437 | ifdef shared.sources 438 | shared.lib = lib$(lib.name).$(shared.extension) 439 | else 440 | shared.lib = 441 | endif 442 | 443 | 444 | ################################################################################ 445 | ### target platform detection ################################################## 446 | ################################################################################ 447 | 448 | 449 | #=== target platform =========================================================== 450 | 451 | 452 | # PLATFORM: optional user variable to define target platform for cross 453 | # compilation. Redefine build tools accordingly. PLATFORM should match 454 | # the exact target prefix of tools present in $PATH, like x86_64-w64-mingw32, 455 | # x86_64-apple-darwin12 etc. Tool definitions are exported to ensure submakes 456 | # will get the same. 457 | 458 | ifneq ($(PLATFORM),) 459 | ifneq ($(findstring darwin, $(PLATFORM)),) 460 | export CC = $(PLATFORM)-cc 461 | export CXX = $(PLATFORM)-c++ 462 | export CPP = $(PLATFORM)-cc 463 | else 464 | export CC = $(PLATFORM)-gcc 465 | export CXX = $(PLATFORM)-g++ 466 | export CPP = $(PLATFORM)-cpp 467 | endif 468 | STRIP = $(PLATFORM)-strip 469 | endif 470 | 471 | # Let (native or cross-) compiler report target triplet and isolate individual 472 | # words therein to facilitate later processing. 473 | target.triplet := $(subst -, ,$(shell $(CC) -dumpmachine)) 474 | 475 | 476 | #=== operating system ========================================================== 477 | 478 | 479 | # The following systems are defined: Linux, Darwin, Windows. GNU and 480 | # GNU/kFreeBSD are treated as Linux to get the same options. 481 | 482 | ifneq ($(filter linux gnu% kfreebsd, $(target.triplet)),) 483 | system = Linux 484 | endif 485 | 486 | ifneq ($(filter darwin%, $(target.triplet)),) 487 | system = Darwin 488 | endif 489 | 490 | ifneq ($(filter mingw% cygwin%, $(target.triplet)),) 491 | system = Windows 492 | endif 493 | 494 | # evaluate possible system-specific multiline defines from library makefile 495 | $(eval $(for$(system))) 496 | 497 | 498 | # TODO: Cygwin, Android 499 | 500 | 501 | #=== architecture ============================================================== 502 | 503 | 504 | # The following CPU names can be processed by pdlibbuilder: 505 | # i*86 Intel 32 bit 506 | # x86_64 Intel 64 bit 507 | # arm ARM 32 bit 508 | # aarch64 ARM 64 bit 509 | 510 | target.arch := $(firstword $(target.triplet)) 511 | 512 | 513 | ################################################################################ 514 | ### variables per platform ##################################################### 515 | ################################################################################ 516 | 517 | 518 | #=== flags per architecture ==================================================== 519 | 520 | 521 | # Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, 522 | # arch.c.flags are overriden below. To see gcc's default architecture flags: 523 | # $ gcc -Q --help=target 524 | 525 | # ARMv6: Raspberry Pi 1st gen, not detectable from target.arch 526 | ifeq ($(shell uname), armv6l) 527 | arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard 528 | 529 | # ARMv7: Beagle, Udoo, RPi2 etc. 530 | else ifeq ($(target.arch), arm) 531 | arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard 532 | 533 | # ARMv8 64 bit, not tested yet 534 | else ifeq ($(target.arch), aarch64) 535 | arch.c.flags = -mcpu=cortex-a53 536 | 537 | # Intel 32 bit, build with SSE and SSE2 instructions 538 | else ifneq ($(filter i%86, $(target.arch)),) 539 | arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2 540 | 541 | # Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions 542 | else ifeq ($(target.arch), x86_64) 543 | arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 544 | 545 | # if none of the above architectures detected 546 | else 547 | arch.c.flags = 548 | endif 549 | 550 | 551 | #=== flags and paths for Linux ================================================= 552 | 553 | 554 | ifeq ($(system), Linux) 555 | prefix = /usr/local 556 | libdir := $(prefix)/lib 557 | pkglibdir = $(libdir)/pd-externals 558 | pdincludepath := $(wildcard /usr/include/pd) 559 | extension = pd_linux 560 | cpp.flags := -DUNIX 561 | c.flags := -fPIC 562 | c.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags 563 | c.ldlibs := -lc -lm 564 | cxx.flags := -fPIC -fcheck-new 565 | cxx.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags 566 | cxx.ldlibs := -lc -lm -lstdc++ 567 | shared.extension = so 568 | shared.ldflags := -rdynamic -fPIC -shared -Wl,-soname,$(shared.lib) 569 | endif 570 | 571 | 572 | #=== flags and paths for Darwin ================================================ 573 | 574 | 575 | # LLVM-clang doesn't support -fcheck-new, therefore this flag is only used when 576 | # compiling with g++. 577 | 578 | ifeq ($(system), Darwin) 579 | pkglibdir = $(HOME)/Library/Pd 580 | pdincludepath := $(firstword $(wildcard \ 581 | /Applications/Pd*.app/Contents/Resources/src)) 582 | extension = pd_darwin 583 | cpp.flags := -DUNIX -DMACOSX -I /sw/include 584 | c.flags := 585 | c.ldflags := -undefined suppress -flat_namespace -bundle 586 | c.ldlibs := -lc 587 | cxx.ldflags := -undefined suppress -flat_namespace -bundle 588 | cxx.ldlibs := -lc 589 | shared.extension = dylib 590 | shared.ldflags = -dynamiclib -undefined dynamic_lookup \ 591 | -install_name @loader_path/$(shared.lib) \ 592 | -compatibility_version 1 -current_version 1.0 593 | ifneq ($(filter %g++, $(CXX)),) 594 | cxx.flags := -fcheck-new 595 | endif 596 | ifeq ($(extension), d_fat) 597 | arch := i386 x86_64 598 | else 599 | arch := $(target.arch) 600 | endif 601 | ifneq ($(filter -mmacosx-version-min=%, $(cflags)),) 602 | version.flag := $(filter -mmacosx-version-min=%, $(cflags)) 603 | else 604 | version.flag = -mmacosx-version-min=10.6 605 | endif 606 | arch.c.flags := $(addprefix -arch , $(arch)) $(version.flag) 607 | arch.ld.flags := $(arch.c.flags) 608 | endif 609 | 610 | 611 | #=== flags and paths for Windows =============================================== 612 | 613 | 614 | # Standard paths on Windows contain spaces, and GNU make functions treat such 615 | # paths as lists, with unintended effects. Therefore we must use shell function 616 | # ls instead of make's wildcard when probing for a path, and use double quotes 617 | # when specifying a path in a command argument. 618 | 619 | # Default paths in Mingw / Mingw-w64 environments. 'PROGRAMFILES' is standard 620 | # location for builds with native architecture, 'ProgramFiles(x86)' for i686 621 | # builds on x86_64 Windows (detection method by Lucas Cordiviola). Curly braces 622 | # required because of parentheses in variable name. 623 | ifeq ($(system), Windows) 624 | pkglibdir := $(APPDATA)/Pd 625 | ifeq ($(target.arch), i686) 626 | programfiles := ${ProgramFiles(x86)} 627 | else 628 | programfiles := $(PROGRAMFILES) 629 | endif 630 | pdbinpath := $(programfiles)/Pd/bin 631 | pdincludepath := $(programfiles)/Pd/src 632 | endif 633 | 634 | # Store default path to pd.dll in PDBINDIR if the latter is not user-defined. 635 | # For include path this is done in the platform-independent paths section below, 636 | # but for PDBINDIR it is done here so ld flags can be evaluated as immediate 637 | # variables. 638 | ifeq ($(system), Windows) 639 | ifdef PDDIR 640 | PDBINDIR := $(PDDIR)/bin 641 | endif 642 | PDBINDIR ?= $(pdbinpath) 643 | endif 644 | 645 | # TODO: decide whether -mms-bitfields should be specified. 646 | ifeq ($(system), Windows) 647 | cpp.flags := -DMSW -DNT 648 | ifeq ($(target.arch), i686) 649 | arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse 650 | else ifeq ($(target.arch), x86_64) 651 | cpp.flags := -DMSW -DNT -DPD_LONGINTTYPE=__int64 652 | arch.c.flags := -march=core2 -msse -msse2 -msse3 -mfpmath=sse 653 | else 654 | arch.c.flags = 655 | endif 656 | extension = dll 657 | c.flags := 658 | c.ldflags := -static-libgcc -shared \ 659 | -Wl,--enable-auto-import "$(PDBINDIR)/pd.dll" 660 | c.ldlibs := 661 | cxx.flags := -fcheck-new 662 | cxx.ldflags := -static-libgcc -static-libstdc++ -shared \ 663 | -Wl,--enable-auto-import "$(PDBINDIR)/pd.dll" 664 | cxx.ldlibs := 665 | shared.extension = dll 666 | shared.ldflags := -static-libgcc -shared "$(PDBINDIR)/pd.dll" 667 | stripflags = --strip-all 668 | endif 669 | 670 | 671 | #=== paths ===================================================================== 672 | 673 | 674 | # Platform-dependent default paths are specified above, but overridable. 675 | # Path variables in upper case can be defined as make command argument or in the 676 | # environment. Variable 'objectsdir' is supported for compatibility with 677 | # the build system that pd-l2ork has inherited from pd-extended. 678 | 679 | PDINCLUDEDIR ?= $(pdincludepath) 680 | PDLIBDIR ?= $(firstword $(objectsdir) $(pkglibdir)) 681 | 682 | ifdef PDDIR 683 | PDINCLUDEDIR := $(wildcard $(PDDIR)/src) 684 | endif 685 | 686 | # base path where all components of the lib will be installed by default 687 | installpath := $(DESTDIR)$(PDLIBDIR)/$(lib.name) 688 | 689 | # check if include path contains spaces (as is often the case on Windows) 690 | # if so, store the path so we can later do checks with it 691 | pdincludepathwithspaces := $(if $(word 2, $(PDINCLUDEDIR)), $(PDINCLUDEDIR)) 692 | 693 | 694 | #=== accumulated build flags =================================================== 695 | 696 | 697 | # From GNU make docs: 'Users expect to be able to specify CFLAGS freely 698 | # themselves.' So we use CFLAGS to define options which are not strictly 699 | # required for compilation: optimizations, architecture specifications, and 700 | # warnings. CFLAGS can be safely overriden using a make command argument. 701 | # Variables cflags, ldflags and ldlibs may be defined in including makefile. 702 | 703 | optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer 704 | warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing 705 | 706 | # suppress -Wunused-variable & Co if you don't want to clutter a build log 707 | ifdef suppress-wunused 708 | warn.flags += $(addprefix -Wno-unused-, function parameter value variable) 709 | endif 710 | 711 | CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags) 712 | 713 | # preprocessor flags 714 | cpp.flags := -DPD -I "$(PDINCLUDEDIR)" $(cpp.flags) $(CPPFLAGS) 715 | 716 | # flags for dependency checking (cflags from makefile may define -I options) 717 | depcheck.flags := $(cpp.flags) $(cflags) 718 | 719 | # architecture specifications for linker are overridable by LDFLAGS 720 | LDFLAGS := $(arch.ld.flags) 721 | 722 | # now add the same ld flags to shared dynamic lib 723 | shared.ldflags := $(shared.ldflags) $(LDFLAGS) 724 | 725 | # accumulated flags for C compiler / linker 726 | c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS) 727 | c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS) 728 | c.ldlibs := $(c.ldlibs) $(ldlibs) 729 | 730 | # accumulated flags for C++ compiler / linker 731 | cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS) 732 | cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS) 733 | cxx.ldlibs := $(cxx.ldlibs) $(ldlibs) 734 | 735 | 736 | ################################################################################ 737 | ### variables: tools ########################################################### 738 | ################################################################################ 739 | 740 | 741 | # aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument 742 | compile-c := $(CC) 743 | compile-cxx := $(CXX) 744 | 745 | 746 | ################################################################################ 747 | ### checks ##################################################################### 748 | ################################################################################ 749 | 750 | 751 | # At this point most variables are defined. Now do some checks and info's 752 | # before rules begin. 753 | 754 | # print Makefile.pdlibbuilder version before possible termination 755 | $(info ++++ info: using Makefile.pdlibbuilder version $(version)) 756 | 757 | # Terminate if target triplet remained empty, to avoid all sorts of confusing 758 | # scenarios and spurious bugs. 759 | ifeq ($(target.triplet),) 760 | $(error Command "$(CC) -dumpmachine" did not return a target triplet, \ 761 | needed for a build. \ 762 | Is compiler "$(CC)" installed in your PATH? ($(PATH)). \ 763 | Does compiler "$(CC)" support option "-dumpmachine"?) 764 | endif 765 | 766 | # 'forward declaration' of default target, needed to do checks 767 | all: 768 | 769 | # To avoid unpredictable results, make sure the default target is not redefined 770 | # by including makefile. 771 | ifneq ($(.DEFAULT_GOAL), all) 772 | $(error Default target must be 'all'.) 773 | endif 774 | 775 | # find out which target(s) will be made 776 | ifdef MAKECMDGOALS 777 | goals := $(MAKECMDGOALS) 778 | else 779 | goals := all 780 | endif 781 | 782 | # store path to Pd API m_pd.h if it is found 783 | ifdef PDINCLUDEDIR 784 | mpdh := $(shell ls "$(PDINCLUDEDIR)/m_pd.h") 785 | endif 786 | 787 | # store path to pd.dll; if not found, ls will give a useful error 788 | ifeq ($(system), Windows) 789 | pddll := $(shell ls "$(PDBINDIR)/pd.dll") 790 | endif 791 | 792 | # when making target all, check if m_pd.h is found and print info about it 793 | ifeq ($(goals), all) 794 | $(if $(mpdh), \ 795 | $(info ++++ info: using Pd API $(mpdh)), \ 796 | $(warning Where is Pd API m_pd.h? Do 'make help' for info.)) 797 | endif 798 | 799 | # print target info 800 | $(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name))) 801 | 802 | # when installing, print installpath info 803 | $(if $(filter install install-lib, $(goals)), $(info ++++ info: \ 804 | installpath is '$(installpath)')) 805 | 806 | 807 | #=== define executables ======================================================== 808 | 809 | 810 | # By default we build class executables, and optionally a shared dynamic link 811 | # lib. When make-lib-executable=yes we build all classes into a single lib 812 | # executable, on the condition that variable lib.setup.sources is defined. 813 | 814 | ifeq ($(make-lib-executable),yes) 815 | $(if $(lib.setup.sources), ,\ 816 | $(error Can not build library blob because lib.setup.sources is undefined)) 817 | executables := $(lib.name).$(extension) 818 | else 819 | executables := $(classes.executables) $(shared.lib) 820 | endif 821 | 822 | 823 | ################################################################################ 824 | ### rules: special targets ##################################################### 825 | ################################################################################ 826 | 827 | 828 | # Disable built-in rules. If some target can't be built with the specified 829 | # rules, it should not be built at all. 830 | MAKEFLAGS += --no-builtin-rules 831 | 832 | .PRECIOUS: 833 | .SUFFIXES: 834 | .PHONY: all post build-lib \ 835 | $(classes) $(makefiledirs) $(makefiles) \ 836 | install install-executables install-datafiles install-datadirs \ 837 | force clean vars allvars depend help 838 | 839 | 840 | ################################################################################ 841 | ### rules: build targets ####################################################### 842 | ################################################################################ 843 | 844 | 845 | # Target all forces the build of targets [$(executables) post] in 846 | # deterministic order. Target $(executables) builds class executables plus 847 | # optional shared lib or alternatively a single lib executable when 848 | # make-lib-executable=true. Target post is optionally defined by 849 | # library makefile. 850 | 851 | all: post 852 | post: $(executables) 853 | 854 | all: 855 | $(info ++++info: target all in lib $(lib.name) completed) 856 | 857 | # build all with -g option turned on for debug symbols 858 | alldebug: c.flags += -g 859 | alldebug: cxx.flags += -g 860 | alldebug: all 861 | 862 | 863 | #=== class executable ========================================================== 864 | 865 | 866 | # recipe for linking objects in class executable 867 | # argument $1 = compiler type (c or cxx) 868 | # argument $2 = class basename 869 | define link-class 870 | $(compile-$1) \ 871 | $($1.ldflags) $($2.class.ldflags) \ 872 | -o $2.$(extension) \ 873 | $(addsuffix .o, $(basename $($2.class.sources))) \ 874 | $(addsuffix .o, $(basename $(common.sources))) \ 875 | $($1.ldlibs) $($2.class.ldlibs) $(shared.lib) 876 | endef 877 | 878 | # general rule for linking object files in class executable 879 | %.$(extension): $(shared.lib) 880 | $(info ++++ info: linking objects in $@ for lib $(lib.name)) 881 | $(if $(filter %.cc %.cpp, $($*.class.sources)), \ 882 | $(call link-class,cxx,$*), \ 883 | $(call link-class,c,$*)) 884 | 885 | 886 | #=== library blob ============================================================== 887 | 888 | 889 | # build all classes into single executable 890 | build-lib: $(lib.name).$(extension) 891 | $(info ++++ info: library blob $(lib.name).$(extension) completed) 892 | 893 | # recipe for linking objects in lib executable 894 | # argument $1 = compiler type (c or cxx) 895 | define link-lib 896 | $(compile-$1) \ 897 | $($1.ldflags) $(lib.ldflags) \ 898 | -o $(lib.name).$(extension) $(all.objects) \ 899 | $($1.ldlibs) $(lib.ldlibs) 900 | endef 901 | 902 | # rule for linking objects in lib executable 903 | # declared conditionally to avoid name clashes 904 | ifeq ($(make-lib-executable),yes) 905 | $(lib.name).$(extension): $(all.objects) 906 | $(if $(filter %.cc %.cpp, $(all.sources)), \ 907 | $(call link-lib,cxx), \ 908 | $(call link-lib,c)) 909 | endif 910 | 911 | 912 | #=== shared dynamic lib ======================================================== 913 | 914 | 915 | # recipe for linking objects in shared executable 916 | # argument $1 = compiler type (c or cxx) 917 | define link-shared 918 | $(compile-$1) \ 919 | $(shared.ldflags) \ 920 | -o lib$(lib.name).$(shared.extension) $(shared.objects) \ 921 | $($1.ldlibs) $(shared.ldlibs) 922 | endef 923 | 924 | # rule for linking objects in shared executable 925 | # build recipe is in macro 'link-shared' 926 | lib$(lib.name).$(shared.extension): $(shared.objects) 927 | $(info ++++ info: linking objects in shared lib $@) 928 | $(if $(filter %.cc %.cpp, $(shared.sources)), \ 929 | $(call link-shared,cxx), \ 930 | $(call link-shared,c)) 931 | 932 | 933 | #=== object files ============================================================== 934 | 935 | 936 | # recipe to make .o file from source 937 | # argument $1 is compiler type (c or cxx) 938 | define make-object-file 939 | $(info ++++ info: making $@ in lib $(lib.name)) 940 | $(compile-$1) \ 941 | $($1.flags) \ 942 | -o $@ -c $< 943 | endef 944 | 945 | # Three rules to create .o files. These are double colon 'terminal' rules, 946 | # meaning they are the last in a rules chain. 947 | 948 | %.o:: %.c 949 | $(call make-object-file,c) 950 | 951 | %.o:: %.cc 952 | $(call make-object-file,cxx) 953 | 954 | %.o:: %.cpp 955 | $(call make-object-file,cxx) 956 | 957 | 958 | #=== explicit prerequisites for class executables ============================== 959 | 960 | 961 | # For class executables, prerequisite rules are declared in run time. Target 962 | # 'depend' prints these rules for debugging purposes. 963 | 964 | # declare explicit prerequisites rule like 'class: class.extension' 965 | # argument $v is class basename 966 | define declare-class-target 967 | $v: $v.$(extension) 968 | endef 969 | 970 | # declare explicit prerequisites rule like 'class.extension: object1.o object2.o' 971 | # argument $v is class basename 972 | define declare-class-executable-target 973 | $v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \ 974 | $(addsuffix .o, $(basename $(common.sources))) 975 | endef 976 | 977 | # evaluate explicit prerequisite rules for all classes 978 | $(foreach v, $(classes), $(eval $(declare-class-target))) 979 | $(foreach v, $(classes), $(eval $(declare-class-executable-target))) 980 | 981 | 982 | #=== implicit prerequisites for class executables ============================== 983 | 984 | 985 | # Evaluating implicit prerequisites (header files) with help from the 986 | # preprocessor is 'expensive' so this is done conditionally and selectively. 987 | # Note that it is also possible to trigger a build via install targets, in 988 | # which case implicit prerequisites are not checked. 989 | 990 | # When the Pd include path contains spaces it will mess up the implicit 991 | # prerequisites rules. 992 | disable-dependency-tracking := $(strip $(pdincludepathwithspaces)) 993 | 994 | ifndef disable-dependency-tracking 995 | must-build-everything := $(filter all, $(goals)) 996 | must-build-class := $(filter $(classes), $(goals)) 997 | must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources)) 998 | endif 999 | 1000 | # declare implicit prerequisites rule like 'object.o: header1.h header2.h ...' 1001 | # argument $1 is input source file(s) 1002 | # dir is explicitly added because option -MM strips it by default 1003 | define declare-object-target 1004 | $(dir $1)$(filter %.o: %.h, $(shell $(CPP) $(depcheck.flags) -MM $1)) $(MAKEFILE_LIST) 1005 | endef 1006 | 1007 | # evaluate implicit prerequisite rules when rebuilding everything 1008 | ifdef must-build-everything 1009 | $(if $(wildcard $(all.objects)), \ 1010 | $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \ 1011 | $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v)))) 1012 | endif 1013 | 1014 | # evaluate implicit prerequisite rules when selectively building classes 1015 | ifdef must-build-class 1016 | $(foreach v, $(must-build-sources), \ 1017 | $(eval $(call declare-object-target, $v))) 1018 | $(foreach v, $(shared.sources), \ 1019 | $(eval $(call declare-object-target, $v))) 1020 | endif 1021 | 1022 | 1023 | ################################################################################ 1024 | ### rules: preprocessor and assembly files ##################################### 1025 | ################################################################################ 1026 | 1027 | 1028 | # Preprocessor and assembly output files for bug tracing etc. They are not part 1029 | # of the build processes for executables. By default these files are created in 1030 | # the current working directory. Dependency tracking is not performed, the build 1031 | # is forced instead to make sure it's up to date. 1032 | 1033 | force: 1034 | 1035 | 1036 | #=== preprocessor file ========================================================= 1037 | 1038 | 1039 | # make preprocessor output file with extension .pre 1040 | # argument $1 = compiler type (c or cxx) 1041 | define make-preprocessor-file 1042 | $(info ++++ info: making preprocessor output file $(notdir $*.pre) \ 1043 | in current working directory) 1044 | $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre) 1045 | endef 1046 | 1047 | %.pre:: %.c force 1048 | $(call make-preprocessor-file,c) 1049 | 1050 | %.pre:: %.cc force 1051 | $(call make-preprocessor-file,cxx) 1052 | 1053 | %.pre:: %.cpp force 1054 | $(call make-preprocessor-file,cxx) 1055 | 1056 | 1057 | #=== assembly file ============================================================= 1058 | 1059 | 1060 | # make C / assembly interleaved output file with extension .lst 1061 | # argument $1 = compiler type (c or cxx) 1062 | define make-assembly-file 1063 | $(info ++++ info: making assembly output file $(notdir $*.lst) \ 1064 | in current working directory) 1065 | $(compile-$1) \ 1066 | -c -Wa,-a,-ad -fverbose-asm \ 1067 | $($1.flags) \ 1068 | $< > $(notdir $*.lst) 1069 | endef 1070 | 1071 | %.lst:: %.c force 1072 | $(call make-assembly-file,c) 1073 | 1074 | %.lst:: %.cc force 1075 | $(call make-assembly-file,cxx) 1076 | 1077 | %.lst:: %.cpp force 1078 | $(call make-assembly-file,cxx) 1079 | 1080 | 1081 | ################################################################################ 1082 | ### rules: installation targets ################################################ 1083 | ################################################################################ 1084 | 1085 | 1086 | #=== strip ===================================================================== 1087 | 1088 | 1089 | # Stripping of installed binaries will only be done when variable 'stripflags' 1090 | # is defined non-empty. No default definition is provided except for Windows 1091 | # where the unstripped binaries are large, especially in the case of Mingw-w64. 1092 | 1093 | # Note: while stripping all symbols ('-s' or '--strip-all') is possible for 1094 | # Linux and Windows, in the case of OSX only non-global symbols can be stripped 1095 | # (option '-x' or '--discard-all'). 1096 | 1097 | # Make definition of strip command overridable so it can be defined in an 1098 | # environment for cross-compilation. 1099 | STRIP ?= strip 1100 | 1101 | # Commands in 'strip-executables' will be executed conditionally in the rule for 1102 | # target 'install-executables'. 1103 | strip-executables = cd "$(installpath)" && \ 1104 | $(foreach v, $(executables), $(STRIP) $(stripflags) '$v';) 1105 | 1106 | 1107 | #=== install =================================================================== 1108 | 1109 | 1110 | # Install targets depend on successful exit status of target all because nothing 1111 | # must be installed in case of a build error. 1112 | 1113 | # -p = preserve time stamps 1114 | # -m = set permission mode (as in chmod) 1115 | # -d = create all components of specified directories 1116 | INSTALL = install 1117 | INSTALL_PROGRAM := $(INSTALL) -p -m 644 1118 | INSTALL_DATA := $(INSTALL) -p -m 644 1119 | INSTALL_DIR := $(INSTALL) -m 755 -d 1120 | 1121 | # strip spaces from file names 1122 | executables := $(strip $(executables)) 1123 | datafiles := $(strip $(datafiles)) 1124 | datadirs := $(strip $(datadirs)) 1125 | 1126 | # Do not make any install sub-target with empty variable definition because the 1127 | # install program would exit with an error. 1128 | install: $(if $(executables), install-executables) 1129 | install: $(if $(datafiles), install-datafiles) 1130 | install: $(if $(datadirs), install-datadirs) 1131 | 1132 | install-executables: all 1133 | $(INSTALL_DIR) -v "$(installpath)" 1134 | $(foreach v, $(executables), \ 1135 | $(INSTALL_PROGRAM) '$v' "$(installpath)";) 1136 | $(info ++++ info: executables of lib $(lib.name) installed \ 1137 | from $(CURDIR) to $(installpath)) 1138 | $(if $(stripflags), $(strip-executables),) 1139 | 1140 | install-datafiles: all 1141 | $(INSTALL_DIR) -v "$(installpath)" 1142 | $(foreach v, $(datafiles), \ 1143 | $(INSTALL_DATA) '$(v)' "$(installpath)";) 1144 | $(info ++++ info: data files of lib $(lib.name) installed \ 1145 | from $(CURDIR) to $(installpath)) 1146 | 1147 | install-datadirs: all 1148 | $(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";) 1149 | $(foreach v, $(datadirs), \ 1150 | $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";) 1151 | $(info ++++ info: data directories of lib $(lib.name) installed \ 1152 | from $(CURDIR) to $(installpath)) 1153 | 1154 | 1155 | ################################################################################ 1156 | ### rules: distribution targets ################################################ 1157 | ################################################################################ 1158 | 1159 | 1160 | # TODO 1161 | # These targets are implemented in Makefile Template, but I have to figure out 1162 | # how to do it under the not-so-strict conditions of Makefile.pdlibbuilder. 1163 | 1164 | # make source package 1165 | dist: 1166 | @echo "target dist not yet implemented" 1167 | 1168 | # make Debian source package 1169 | dpkg-source: 1170 | @echo "target dpkg-source not yet implemented" 1171 | 1172 | $(ORIGDIR): 1173 | 1174 | $(DISTDIR): 1175 | 1176 | 1177 | ################################################################################ 1178 | ### rules: clean targets ####################################################### 1179 | ################################################################################ 1180 | 1181 | 1182 | # delete build products from build tree 1183 | clean: 1184 | rm -f $(all.objects) 1185 | rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib) 1186 | rm -f *.pre *.lst 1187 | 1188 | # remove distribution directories and tarballs from build tree 1189 | distclean: clean 1190 | @echo "target distclean not yet implemented" 1191 | 1192 | 1193 | ################################################################################ 1194 | ### rules: submake targets ##################################################### 1195 | ################################################################################ 1196 | 1197 | 1198 | # Iterate over sub-makefiles or makefiles in other directories. 1199 | 1200 | # When 'continue-make=yes' is set, sub-makes will report 'true' to the parent 1201 | # process regardless of their real exit status. This prevents the parent make 1202 | # from being aborted by a sub-make error. Useful when you want to quickly find 1203 | # out which sub-makes from a large set will succeed. 1204 | ifeq ($(continue-make),yes) 1205 | continue = || true 1206 | endif 1207 | 1208 | # These targets will trigger sub-make processes for entries in 'makefiledirs' 1209 | # and 'makefiles'. 1210 | all alldebug install clean distclean dist dkpg-source: \ 1211 | $(makefiledirs) $(makefiles) 1212 | 1213 | # this expands to identical rules for each entry in 'makefiledirs' 1214 | $(makefiledirs): 1215 | $(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue) 1216 | 1217 | # this expands to identical rules for each entry in 'makefiles' 1218 | $(makefiles): 1219 | $(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue) 1220 | 1221 | 1222 | ################################################################################ 1223 | ### rules: convenience targets ################################################# 1224 | ################################################################################ 1225 | 1226 | 1227 | #=== show variables ============================================================ 1228 | 1229 | 1230 | # Several 'function' macro's cause errors when expanded within a rule or without 1231 | # proper arguments. Variables which are set with the define directive are only 1232 | # shown by name for that reason. 1233 | functions = \ 1234 | add-class-source \ 1235 | declare-class-target \ 1236 | declare-class-executable-target \ 1237 | declare-object-target \ 1238 | link-class \ 1239 | link-lib \ 1240 | link-shared \ 1241 | make-object-file \ 1242 | make-preprocessor-file \ 1243 | make-assembly-file 1244 | 1245 | 1246 | # show variables from makefiles 1247 | vars: 1248 | $(info ++++ info: showing makefile variables:) 1249 | $(foreach v,\ 1250 | $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\ 1251 | $(if $(filter file, $(origin $v)),\ 1252 | $(info variable $v = $($v)))) 1253 | $(foreach v, $(functions), $(info 'function' name: $v)) 1254 | @echo 1255 | 1256 | # show all variables 1257 | allvars: 1258 | $(info ++++ info: showing default, automatic and makefile variables:) 1259 | $(foreach v, \ 1260 | $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \ 1261 | $(info variable ($(origin $v)) $v = $($v))) 1262 | $(foreach v, $(functions), $(info 'function' name: $v)) 1263 | @echo 1264 | 1265 | 1266 | #=== show dependencies ========================================================= 1267 | 1268 | 1269 | # show generated prerequisites rules 1270 | depend: 1271 | $(info ++++ info: generated prerequisite rules) 1272 | $(foreach v, $(classes), $(info $(declare-class-target))) 1273 | $(foreach v, $(classes), $(info $(declare-class-executable-target))) 1274 | $(foreach v, $(all.sources), $(info $(call declare-object-target, $v))) 1275 | @echo 1276 | 1277 | 1278 | #=== show help text ============================================================ 1279 | 1280 | 1281 | # brief info about targets and paths 1282 | 1283 | ifdef mpdh 1284 | mpdhinfo := $(mpdh) 1285 | else 1286 | mpdhinfo := m_pd.h was not found. Is Pd installed? 1287 | endif 1288 | 1289 | help: 1290 | @echo 1291 | @echo " Main targets:" 1292 | @echo " all: build executables (default target)" 1293 | @echo " install: install all components of the library" 1294 | @echo " vars: print makefile variables for troubleshooting" 1295 | @echo " allvars: print all variables for troubleshooting" 1296 | @echo " help: print this help text" 1297 | @echo 1298 | @echo " Pd API m_pd.h:" 1299 | @echo " $(mpdhinfo)" 1300 | @echo " You may specify your preferred Pd include directory as argument" 1301 | @echo " to the make command, like 'PDINCLUDEDIR=path/to/pd/src'." 1302 | @echo 1303 | @echo " Path for installation of your libdir(s):" 1304 | @echo " $(PDLIBDIR)" 1305 | @echo " Alternatively you may specify your path for installation as argument" 1306 | @echo " to the make command, like 'PDLIBDIR=path/to/pd-externals'." 1307 | @echo 1308 | @echo " Default paths are listed in the doc sections in Makefile.pdlibbuilder." 1309 | @echo 1310 | 1311 | 1312 | #=== platform test ============================================================= 1313 | 1314 | 1315 | # This target can be used to test if the compiler for specified PLATFORM is 1316 | # correctly defined and available. 1317 | 1318 | dumpmachine: 1319 | @$(CC) -dumpmachine 1320 | 1321 | 1322 | #=== dummy target ============================================================== 1323 | 1324 | 1325 | coffee: 1326 | @echo "Makefile.pdlibbuilder: Can not make coffee. Sorry." 1327 | 1328 | 1329 | ################################################################################ 1330 | ### end of rules sections ###################################################### 1331 | ################################################################################ 1332 | 1333 | 1334 | # for syntax highlighting in vim and github 1335 | # vim: set filetype=make: 1336 | 1337 | -------------------------------------------------------------------------------- /pd-lib-builder/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Makefile.pdlibbuilder ### 4 | 5 | Helper makefile for Pure Data external libraries. Written by Katja Vetter 6 | March-June 2015 for the public domain and since then developed as a Pd 7 | community project. No warranties. Inspired by Hans Christoph Steiner's Makefile 8 | Template and Stephan Beal's ShakeNMake. 9 | 10 | GNU make version >= 3.81 required. 11 | 12 | 13 | ### characteristics ### 14 | 15 | 16 | * defines build settings based on autodetected target platform 17 | * defines rules to build Pd class- or lib executables from C or C++ sources 18 | * defines rules for libdir installation 19 | * defines convenience targets for developer and user 20 | * evaluates implicit dependencies for non-clean builds 21 | 22 | 23 | ### basic usage ### 24 | 25 | 26 | In your Makefile, define your Pd lib name and class files, and include 27 | Makefile.pdlibbuilder at the end of the Makefile. Like so: 28 | 29 | 30 | # Makefile for mylib 31 | 32 | lib.name = mylib 33 | 34 | class.sources = myclass1.c myclass2.c 35 | 36 | datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt 37 | 38 | include Makefile.pdlibbuilder 39 | 40 | 41 | For files in class.sources it is assumed that class name == source file 42 | basename. The default target builds all classes as individual executables 43 | with Pd's default extension for the platform. For anything more than the 44 | most basic usage, read the documentation sections in Makefile.pdlibbuilder. 45 | 46 | 47 | ### paths ### 48 | 49 | 50 | Makefile.pdlibbuilder >= v0.4.0 supports pd path variables which can be 51 | defined not only as make command argument but also in the environment, to 52 | override platform-dependent defaults: 53 | 54 | PDDIR: 55 | Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and 56 | PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. 57 | 58 | PDINCLUDEDIR: 59 | Directory where Pd API m_pd.h should be found, and other Pd header files. 60 | Overrides the default search path. 61 | 62 | PDBINDIR: 63 | Directory where pd.dll should be found for linking (Windows only). Overrides 64 | the default search path. 65 | 66 | PDLIBDIR: 67 | Root directory for installation of Pd library directories. Overrides the 68 | default install location. 69 | 70 | 71 | ### documentation ### 72 | 73 | 74 | This README.md provides only basic information. A large comment section inside 75 | Makefile.pdlibbuilder lists and explains the available user variables, default 76 | paths, and targets. The internal documentation reflects the exact functionality 77 | of the particular version. For suggestions about project maintenance and 78 | advanced compilation see tips-tricks.md. 79 | 80 | 81 | ### versioning ### 82 | 83 | 84 | The project is versioned in MAJOR.MINOR.BUGFIX format (see http://semver.org), 85 | and maintained at https://github.com/pure-data/pd-lib-builder. Pd lib developers 86 | are invited to regulary check for updates, and to contribute and discuss 87 | improvements here. If you really need to distribute a personalized version with 88 | your library, rename Makefile.pdlibbuilder to avoid confusion. 89 | 90 | 91 | ### examples ### 92 | 93 | The list of projects using pd-lib-builder can be helpful if you are looking for 94 | examples, from the simplest use case to more complex implementations. 95 | 96 | - helloworld: traditional illustration of simplest use case 97 | - pd-windowing: straightforward real world use case of a small library 98 | - pd-nilwind / pd-cyclone: more elaborate source tree 99 | - zexy: migrated from autotools to pd-lib-builder 100 | 101 | 102 | ### projects using pd-lib-builder ### 103 | 104 | non-exhaustive list 105 | 106 | https://github.com/pure-data/helloworld 107 | 108 | https://github.com/electrickery/pd-nilwind 109 | 110 | https://github.com/electrickery/pd-maxlib 111 | 112 | https://github.com/electrickery/pd-sigpack 113 | 114 | https://github.com/electrickery/pd-tof 115 | 116 | https://github.com/electrickery/pd-windowing 117 | 118 | https://github.com/electrickery/pd-smlib 119 | 120 | https://github.com/porres/pd-cyclone 121 | 122 | https://github.com/porres/pd-else 123 | 124 | https://github.com/porres/pd-psycho 125 | 126 | https://git.iem.at/pd/comport 127 | 128 | https://git.iem.at/pd/hexloader 129 | 130 | https://git.iem.at/pd/iemgui 131 | 132 | https://git.iem.at/pd/iemguts 133 | 134 | https://git.iem.at/pd/iemlib 135 | 136 | https://git.iem.at/pd/iemnet 137 | 138 | https://git.iem.at/pd/iem_ambi 139 | 140 | https://git.iem.at/pd/iem_tab 141 | 142 | https://git.iem.at/pd/iem_adaptfilt 143 | 144 | https://git.iem.at/pd/iem_roomsim 145 | 146 | https://git.iem.at/pd/iem_spec2 147 | 148 | https://git.iem.at/pd/mediasettings 149 | 150 | https://git.iem.at/pd/zexy 151 | 152 | https://git.iem.at/pd-gui/punish 153 | 154 | https://github.com/residuum/PuRestJson 155 | 156 | https://github.com/libpd/abl_link 157 | 158 | https://github.com/wbrent/timbreID 159 | 160 | https://github.com/MetaluNet/moonlib 161 | 162 | 163 | -------------------------------------------------------------------------------- /pd-lib-builder/tips-tricks.md: -------------------------------------------------------------------------------- 1 | pd-lib-builder cheatsheet 2 | ========================= 3 | 4 | # Creating special builds 5 | 6 | ## cross-compiling on linux x86_64 for other platforms 7 | 8 | Using pd-lib-builder >=0.6.0 we can define variable `PLATFORM` to specify a 9 | target triplet for cross-compilation. Example to build W32 binaries (assuming 10 | package `mingw-w64` is installed and a W32 package for Pd is unzipped into a 11 | path `${PDWIN32}`: 12 | 13 | make PLATFORM=x86_64-w64-mingw32 PDDIR="${PDWIN32}" 14 | 15 | #### older pd-lib-builder versions 16 | 17 | Using pd-lib-builder < 0.6.0, in the absence of variable `PLATFORM`, you would 18 | instead override variables `system`, `target.arch`, `CC` and / or `CXX`, 19 | `STRIP`. Example: 20 | 21 | make system=Windows target.arch=i686 CC=i686-w64-mingw32-gcc STRIP=i686-w64-mingw32-strip PDDIR="${PDWIN32}" 22 | 23 | #### toolchains 24 | 25 | Cross toolchains for relevant platforms in Debian Buster (install g++ 26 | with dependencies for a given platform to get the whole tool chain): 27 | 28 | - `arm-linux-gnueabihf` 29 | - `aarch64-linux-gnu` 30 | - `i686-linux-gnu` 31 | - `i686-w64-mingw32` and `x86_64-w64-mingw32` (install `mingw-w64`) 32 | 33 | OSX/MacOS cross tool chains are not distributed by Debian. Use project 34 | `osxcross` from Thomas Poechtraeger to create the tools. 35 | 36 | ## building double-precision externals 37 | 38 | At the time of writing (2018-02) there is no official Pd that supports 39 | double-precision numbers yet. 40 | However, if you do get hold of an experimental double-precision Pd, you can 41 | easily build your externals for 64-bit numbers: 42 | 43 | make CPPFLAGS="-DPD_FLOATSIZE=64" 44 | 45 | ## building externals for W64 (64-bit Windows) 46 | 47 | At the time of writing (2018-02) there is no official Pd that supports 48 | W64 yet. 49 | However, if you do get hold of an experimental W64 Pd, you can 50 | easily build your externals for this environment with 51 | 52 | make CPPFLAGS="-DPD_LONGINTTYPE=__int64" CC=x86_64-w64-mingw32-gcc 53 | 54 | 55 | To build a double-precision external for W64, use something like: 56 | 57 | make CPPFLAGS="-DPD_LONGINTTYPE=__int64 -DPD_FLOATSIZE=64" CC=x86_64-w64-mingw32-gcc 58 | 59 | 60 | ## TODO universal binaries on OSX 61 | 62 | 63 | # Project management 64 | 65 | In general it is advised to put the `Makefile.pdlibbuilder` into a separate 66 | subdirectory (e.g. `pd-lib-builder/`). 67 | This makes it much easier to update the `Makefile.pdlibbuilder` later 68 | 69 | You *should* also use a variable to the actual path of the Makefile.pdlibbuilder 70 | (even if you keep it in the root-directory), as this allows easy experimenting 71 | with newer (or older) (or site-specific) versions of the pd-lib-builder 72 | Makefile. 73 | 74 | ~~~make 75 | PDLIBBUILDER_DIR=pd-lib-builder/ 76 | include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder 77 | ~~~ 78 | 79 | ## Keeping pd-lib-builder up-to-date 80 | 81 | ### `git subtree` 82 | 83 | With git-subtrees, you make the pd-lib-builder repository (or any other 84 | repository for that matter) part of your own repository - with full history and 85 | everything - put nicely into a distinct subdirectory. 86 | 87 | Support for *manipulating* subtrees has been added with Git-v1.7.11 (May 2012). 88 | The nice thing however is, that from "outside" the subtree is part of your 89 | repository like any other directory. E.g. older versions of Git can clone your 90 | repository with the full subtree (and all it's history) just fine. 91 | You can also use git-archive to make a complete snapshot of your repository 92 | (including the subtree) - nice, if you e.g. want self-contained downloads of 93 | your project from git hosting platforms (like Github, Gitlab, Bitbucket,...) 94 | 95 | In short, `git subtree` is the better `git submodule`. 96 | 97 | So here's how to do it: 98 | 99 | #### Initial setup/check-out 100 | This will create a `pd-lib-builder/` directory containing the full history of 101 | the pd-lib-builder repository up to its release `v0.5.0` 102 | 103 | ~~~sh 104 | git subtree add --prefix=pd-lib-builder/ https://github.com/pure-data/pd-lib-builder v0.5.0 105 | ~~~ 106 | 107 | This will automatically merge the `pd-lib-builder/` history into your current 108 | branch, so everything is ready to go. 109 | 110 | #### Cloning your repository with the subtree 111 | Nothing special, really. 112 | Just clone your repository as always: 113 | 114 | ~~~sh 115 | git clone https://git.example.org/pd/superbonk~.git 116 | ~~~ 117 | 118 | #### Updating the subtree 119 | Time passes and sooner or later you will find, that there is a shiny new 120 | pd-lib-builder with plenty of bugfixes and new features. 121 | To update your local copy to pd-lib-builder's current `master`, simply run: 122 | 123 | ~~~sh 124 | git subtree pull --prefix pd-lib-builder/ https://github.com/pure-data/pd-lib-builder master 125 | ~~~ 126 | 127 | #### Pulling the updated subtree into existing clones 128 | Again, nothing special. 129 | Just pull as always: 130 | 131 | ~~~sh 132 | git pull 133 | ~~~ 134 | 135 | 136 | #### Further reading 137 | More on the power of `git subtree` can be found online 138 | - https://medium.com/@v/git-subtrees-a-tutorial-6ff568381844 139 | - https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree 140 | - ... 141 | 142 | ### ~~`git submodule`~~ [DISCOURAGED] 143 | 144 | 145 | #### Initial setup/check-out 146 | To add a new submodule to your repository, just run `git submodule add` and 147 | commit the changes: 148 | 149 | ~~~sh 150 | git submodule add https://github.com/pure-data/pd-lib-builder 151 | git commit .gitmodules pd-lib-builder/ -m "Added pd-lib-builder as git-submodule" 152 | ~~~ 153 | 154 | #### Cloning your repository with the submodule 155 | 156 | When doing a fresh clone of your repository, pass the `--recursive` option to 157 | automatically fetch all submodules: 158 | 159 | ~~~sh 160 | git clone --recursive https://git.example.org/pd/superbonk~.git 161 | ~~~ 162 | 163 | If you've cloned non-recursively, you can initialize and update the submodules 164 | manually: 165 | 166 | ~~~sh 167 | git submodule init 168 | git submodule update 169 | ~~~ 170 | 171 | #### Updating the submodule 172 | Submodules are usually fixed to a given commit in their repository. 173 | To update the `pd-lib-builder` submodule to the current `master` do something 174 | like: 175 | 176 | ~~~sh 177 | cd pd-lib-builder 178 | git checkout master 179 | git pull 180 | cd .. 181 | git status pd-lib-builder 182 | git commit pd-lib-builder -m "Updated pd-lib-builder to current master" 183 | ~~~ 184 | 185 | #### Pulling the updated submodule into existing clones 186 | After you have pushed the submodule updates in your repository, other clones of 187 | the repository can be updated as follows: 188 | 189 | ~~~sh 190 | git pull 191 | ~~~ 192 | 193 | The above will make your repository aware, that the submodule is out-of-sync. 194 | 195 | ~~~sh 196 | $ LANG=C git status pd-lib-builder 197 | On branch master 198 | Your branch is up to date with 'origin/master'. 199 | 200 | Changes not staged for commit: 201 | (use "git add ..." to update what will be committed) 202 | (use "git checkout -- ..." to discard changes in working directory) 203 | 204 | modified: pd-lib-builder (new commits) 205 | $ 206 | ~~~ 207 | 208 | In order to sync the submodule to the correct commit, run the following: 209 | 210 | ~~~sh 211 | git submodule update 212 | ~~~ 213 | 214 | #### Drawbacks 215 | `git submodule` has a number of drawbacks: 216 | - it requires special commands to synchronize the submodules, in addition to 217 | synching your repository. 218 | - you must make sure to use an URL for the submodule that is accessible to your 219 | potential users. e.g. using `git@github.com:pure-data/pd-lib-builder` is bad, 220 | because it requires everybody who wants to checkout your sources to have a 221 | github-account - even if they could checkout *your* repository anonymously. 222 | - submodules will be excluded from `git archive`. This means, that if you use a 223 | mainstream git provider (like Github, GitLab, Bitbucket,...) and make releases 224 | by creating a `git tag`, the automatically generated zipfiles with the sources 225 | will lack the submodule - and your users will not be able to compile your 226 | source code. 227 | 228 | In general, I would suggest to **avoid** `git submodule`, and instead use the 229 | better `git subtree` (above). 230 | 231 | -------------------------------------------------------------------------------- /scripts/localdeps.linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # creates local copies of all dependencies (dynamic libraries) 4 | # and sets RUNPATH to $ORIGIN on each so they will find 5 | # each other. 6 | # 7 | # usage: $0 8 | 9 | 10 | 11 | verbose=0 12 | include_paths= 13 | exclude_paths= 14 | 15 | 16 | 17 | #default exclude/include paths 18 | exclude_paths="*/libc.so.*:*/libarmmem.*.so.*:*/libdl.so.*:*/libglib-.*.so.*:*/libgomp.so.*:*/libgthread.*.so.*:*/libm.so.*:*/libpthread.*.so.*:*/libpthread.so.*:*/libstdc++.so.*:*/libgcc_s.so.*:*/libpcre.so.*:*/libz.so.*" 19 | include_paths="/*" 20 | 21 | # UTILITIES 22 | if [ -e "${0%/*}/localdeps.utilities.source" ]; then 23 | . "${0%/*}/localdeps.utilities.source" 24 | else 25 | # the following section (from @BEGIN_UTILITIES@ to @END_UTILITIES@) 26 | # was copied from 'localdeps.utilities.source'. 27 | # changes you make to this section will be lost. 28 | #@BEGIN_UTILITIES@ 29 | verbose=${verbose:-0} 30 | 31 | error() { 32 | echo "$@" 1>&2 33 | } 34 | 35 | substitute() { 36 | # substitutes literal strings 37 | # usage: echo foo | substitute foo bar g 38 | sed "s/$(echo $1 | sed 's:[]\[^$.*/&]:\\&:g')/$(echo $2 | sed 's:[]\[^$.*/&]:\\&:g')/$3" 39 | } 40 | 41 | check_binaries() { 42 | local cmd 43 | for cmd in "$@"; do 44 | if ! which "${cmd}" > /dev/null; then 45 | error "Could not find '${cmd}'. Is it installed?" 46 | exit 127 47 | fi 48 | done 49 | } 50 | 51 | 52 | normalize_path() { 53 | # normalize a path specification, e.g. on Windows turn C:\Foo\Bar\ into /c/foo/bar/" 54 | # on most system this doesn't do anything, but override it to your needs... 55 | # e.g. on Windows use: ${CYGPATH} "$1" | tr "[A-Z]" "[a-z]" 56 | echo "$1" 57 | } 58 | 59 | list_dirs() { 60 | # 61 | local IN="$@" 62 | local iter 63 | while [ "$IN" ] ;do 64 | iter=${IN%%:*} 65 | echo "${iter}" 66 | [ "$IN" = "$iter" ] && IN='' || IN="${IN#*:}" 67 | done 68 | } 69 | 70 | check_in_path() { 71 | local needle=$1 72 | local p 73 | local patterns 74 | shift 75 | patterns="$@" 76 | while [ "${patterns}" ]; do 77 | p=${patterns%%:*} 78 | [ "$patterns" = "$p" ] && patterns='' || patterns="${patterns#*:}" 79 | 80 | case "${needle}" in 81 | ${p}) 82 | echo "${needle}" 83 | break 84 | ;; 85 | esac 86 | done | grep . >/dev/null 87 | } 88 | 89 | check_includedep() { 90 | local path=$(normalize_path "$1") 91 | local p 92 | local result=0 93 | # exclude non-existing files 94 | if [ ! -e "${path}" ]; then 95 | return 0 96 | fi 97 | 98 | # skip paths that match one of the patterns in ${exclude_paths} 99 | if check_in_path "${path}" "${exclude_paths}"; then 100 | return 1 101 | fi 102 | # only include paths that match one of the patterns in ${include_paths} 103 | if check_in_path "${path}" "${include_paths}"; then 104 | echo "${path}" 105 | return 0 106 | fi 107 | # skip the rest 108 | return 1 109 | } 110 | 111 | usage() { 112 | cat >/dev/stderr <] [-X ] [ ...] 114 | recursively includes all dependencies of the given binaries 115 | 116 | -I : adds one include path entry 117 | -X : adds one exclude path entry 118 | -v: raise verbosity 119 | -q: lower verbosity 120 | 121 | EOF 122 | 123 | case "$0" in 124 | *win*) 125 | cat >/dev/stderr </dev/stderr < ' \ 220 | | while read _ _ libpath _; do 221 | inc=$(check_includedep "${libpath}") 222 | if [ "x${inc}" != "x" ]; then 223 | echo "${inc}" 224 | fi 225 | done 226 | } 227 | 228 | install_deps () { 229 | # make a local copy of all linked libraries of given binary 230 | # and set RUNPATH to $ORIGIN (exclude "standard" libraries) 231 | # arg1: binary to check 232 | local outdir 233 | outdir="$(dirname "$1")/${arch}" 234 | local outfile 235 | if [ ! -d "${outdir}" ]; then 236 | outdir=. 237 | fi 238 | list_deps "$1" | while read libpath; do 239 | libname=$(basename "${libpath}") 240 | if [ ! -e "${libpath}" ]; then 241 | error "DEP: ${INSTALLDEPS_INDENT} WARNING: could not make copy of '${libpath}'. Not found" 242 | continue 243 | fi 244 | outfile="${outdir}/$(basename ${libpath})" 245 | if [ -e "${outfile}" ]; then 246 | error "DEP: ${INSTALLDEPS_INDENT} ${libpath} SKIPPED" 247 | else 248 | error "DEP: ${INSTALLDEPS_INDENT} ${libpath} -> ${outdir}/" 249 | cp "${libpath}" "${outfile}" 250 | patchelf --set-rpath \$ORIGIN "${outfile}" 251 | fi 252 | done 253 | patchelf --set-rpath \$ORIGIN/${arch} "${1}" 254 | } 255 | 256 | 257 | 258 | # Check dependencies 259 | check_binaries grep ldd patchelf 260 | 261 | for f in "$@"; do 262 | # Check if we can read from given file 263 | if ! ldd "${f}" > /dev/null 2>&1; then 264 | error "Skipping '${f}'. Is it a binary file?" 265 | continue 266 | fi 267 | depdir="$(dirname ${f})/${arch}" 268 | mkdir -p "${depdir}" 269 | install_deps "${f}" 270 | done 271 | -------------------------------------------------------------------------------- /scripts/localdeps.macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## puts dependencies besides the binary 4 | # LATER: put dependencies into a separate folder 5 | 6 | ## usage: $0 [...] 7 | 8 | #default exclude/include paths 9 | exclude_paths="/usr/lib/*:/System/Library/Frameworks/*" 10 | include_paths="/*" 11 | recursion=false 12 | 13 | # UTILITIES 14 | if [ -e "${0%/*}/localdeps.utilities.source" ]; then 15 | . "${0%/*}/localdeps.utilities.source" 16 | else 17 | # the following section (from @BEGIN_UTILITIES@ to @END_UTILITIES@) 18 | # was copied from 'localdeps.utilities.source'. 19 | # changes you make to this section will be lost. 20 | #@BEGIN_UTILITIES@ 21 | verbose=${verbose:-0} 22 | 23 | error() { 24 | echo "$@" 1>&2 25 | } 26 | 27 | substitute() { 28 | # substitutes literal strings 29 | # usage: echo foo | substitute foo bar g 30 | sed "s/$(echo $1 | sed 's:[]\[^$.*/&]:\\&:g')/$(echo $2 | sed 's:[]\[^$.*/&]:\\&:g')/$3" 31 | } 32 | 33 | check_binaries() { 34 | local cmd 35 | for cmd in "$@"; do 36 | if ! which "${cmd}" > /dev/null; then 37 | error "Could not find '${cmd}'. Is it installed?" 38 | exit 127 39 | fi 40 | done 41 | } 42 | 43 | 44 | normalize_path() { 45 | # normalize a path specification, e.g. on Windows turn C:\Foo\Bar\ into /c/foo/bar/" 46 | # on most system this doesn't do anything, but override it to your needs... 47 | # e.g. on Windows use: ${CYGPATH} "$1" | tr "[A-Z]" "[a-z]" 48 | echo "$1" 49 | } 50 | 51 | list_dirs() { 52 | # 53 | local IN="$@" 54 | local iter 55 | while [ "$IN" ] ;do 56 | iter=${IN%%:*} 57 | echo "${iter}" 58 | [ "$IN" = "$iter" ] && IN='' || IN="${IN#*:}" 59 | done 60 | } 61 | 62 | check_in_path() { 63 | local needle=$1 64 | local p 65 | local patterns 66 | shift 67 | patterns="$@" 68 | while [ "${patterns}" ]; do 69 | p=${patterns%%:*} 70 | [ "$patterns" = "$p" ] && patterns='' || patterns="${patterns#*:}" 71 | 72 | case "${needle}" in 73 | ${p}) 74 | echo "${needle}" 75 | break 76 | ;; 77 | esac 78 | done | grep . >/dev/null 79 | } 80 | 81 | check_includedep() { 82 | local path=$(normalize_path "$1") 83 | local p 84 | local result=0 85 | # exclude non-existing files 86 | if [ ! -e "${path}" ]; then 87 | return 0 88 | fi 89 | 90 | # skip paths that match one of the patterns in ${exclude_paths} 91 | if check_in_path "${path}" "${exclude_paths}"; then 92 | return 1 93 | fi 94 | # only include paths that match one of the patterns in ${include_paths} 95 | if check_in_path "${path}" "${include_paths}"; then 96 | echo "${path}" 97 | return 0 98 | fi 99 | # skip the rest 100 | return 1 101 | } 102 | 103 | usage() { 104 | cat >/dev/stderr <] [-X ] [ ...] 106 | recursively includes all dependencies of the given binaries 107 | 108 | -I : adds one include path entry 109 | -X : adds one exclude path entry 110 | -v: raise verbosity 111 | -q: lower verbosity 112 | 113 | EOF 114 | 115 | case "$0" in 116 | *win*) 117 | cat >/dev/stderr </dev/stderr < ${outdir}" 275 | cp "${dep}" "${outdir}" 276 | chmod u+w "${outdir}/${depfile}" 277 | 278 | # make sure the dependency announces itself with the local path 279 | install_name_tool -id "${loaderpath}" "${outdir}/${depfile}" 280 | # recursively call ourselves, to resolve higher-order dependencies 281 | INSTALLDEPS_INDENT="${INSTALLDEPS_INDENT} " $0 -r "${outdir}/${depfile}" 282 | fi 283 | done 284 | } 285 | 286 | if [ "x${OTOOL}" = "x" ]; then 287 | check_binaries otool 288 | OTOOL="otool -L" 289 | fi 290 | 291 | for f in "$@"; do 292 | if [ -e "${f}" ]; then 293 | error 294 | install_deps "${f}" 295 | fi 296 | done 297 | 298 | # Code signing 299 | # On Monterey, binaries are automatically codesigned. Modifying them with this script renders the signature 300 | # invalid. When Pd loads an external with an invalid signature, it exits immediately. Thus, we need to make sure 301 | # that we codesign them again _after_ the localdeps process 302 | 303 | # This needs to be the absolutely last step. We don't do it while we're still inside a recursion. 304 | if ! $recursion; then 305 | echo -n "Code signing in progress... " 306 | outdir="$(dirname "$1")/${arch}" 307 | codesign --remove-signature "${ARGS[@]}" ${outdir}/*.dylib 308 | codesign -s - "${ARGS[@]}" ${outdir}/*.dylib 309 | echo "Done" 310 | fi 311 | -------------------------------------------------------------------------------- /scripts/localdeps.win.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## puts dependencies besides the binary 4 | # LATER: put dependencies into a separate folder 5 | 6 | ## usage: $0 [...] 7 | 8 | 9 | ########################################### 10 | # WARNING 11 | # 12 | # this uses an ugly hack to allow side-by-side installation of 32bit and 64bit 13 | # dependencies: 14 | # embedded dependencies are renamed from "libfoo.dll" to "libfoo.w32" resp. 15 | # "libfoo.w64", and the files are modified (using 'sed') to reflect this 16 | # renaming. 17 | # this is somewhat brittle and likely to break! 18 | 19 | #default exclude/include paths 20 | exclude_paths="" 21 | include_paths="*mingw*:*/msys/*" 22 | 23 | # UTILITIES 24 | if [ -e "${0%/*}/localdeps.utilities.source" ]; then 25 | . "${0%/*}/localdeps.utilities.source" 26 | else 27 | # the following section (from @BEGIN_UTILITIES@ to @END_UTILITIES@) 28 | # was copied from 'localdeps.utilities.source'. 29 | # changes you make to this section will be lost. 30 | #@BEGIN_UTILITIES@ 31 | verbose=${verbose:-0} 32 | 33 | error() { 34 | echo "$@" 1>&2 35 | } 36 | 37 | substitute() { 38 | # substitutes literal strings 39 | # usage: echo foo | substitute foo bar g 40 | sed "s/$(echo $1 | sed 's:[]\[^$.*/&]:\\&:g')/$(echo $2 | sed 's:[]\[^$.*/&]:\\&:g')/$3" 41 | } 42 | 43 | check_binaries() { 44 | local cmd 45 | for cmd in "$@"; do 46 | if ! which "${cmd}" > /dev/null; then 47 | error "Could not find '${cmd}'. Is it installed?" 48 | exit 127 49 | fi 50 | done 51 | } 52 | 53 | 54 | normalize_path() { 55 | # normalize a path specification, e.g. on Windows turn C:\Foo\Bar\ into /c/foo/bar/" 56 | # on most system this doesn't do anything, but override it to your needs... 57 | # e.g. on Windows use: ${CYGPATH} "$1" | tr "[A-Z]" "[a-z]" 58 | echo "$1" 59 | } 60 | 61 | list_dirs() { 62 | # 63 | local IN="$@" 64 | local iter 65 | while [ "$IN" ] ;do 66 | iter=${IN%%:*} 67 | echo "${iter}" 68 | [ "$IN" = "$iter" ] && IN='' || IN="${IN#*:}" 69 | done 70 | } 71 | 72 | check_in_path() { 73 | local needle=$1 74 | local p 75 | local patterns 76 | shift 77 | patterns="$@" 78 | while [ "${patterns}" ]; do 79 | p=${patterns%%:*} 80 | [ "$patterns" = "$p" ] && patterns='' || patterns="${patterns#*:}" 81 | 82 | case "${needle}" in 83 | ${p}) 84 | echo "${needle}" 85 | break 86 | ;; 87 | esac 88 | done | grep . >/dev/null 89 | } 90 | 91 | check_includedep() { 92 | local path=$(normalize_path "$1") 93 | local p 94 | local result=0 95 | # exclude non-existing files 96 | if [ ! -e "${path}" ]; then 97 | return 0 98 | fi 99 | 100 | # skip paths that match one of the patterns in ${exclude_paths} 101 | if check_in_path "${path}" "${exclude_paths}"; then 102 | return 1 103 | fi 104 | # only include paths that match one of the patterns in ${include_paths} 105 | if check_in_path "${path}" "${include_paths}"; then 106 | echo "${path}" 107 | return 0 108 | fi 109 | # skip the rest 110 | return 1 111 | } 112 | 113 | usage() { 114 | cat >/dev/stderr <] [-X ] [ ...] 116 | recursively includes all dependencies of the given binaries 117 | 118 | -I : adds one include path entry 119 | -X : adds one exclude path entry 120 | -v: raise verbosity 121 | -q: lower verbosity 122 | 123 | EOF 124 | 125 | case "$0" in 126 | *win*) 127 | cat >/dev/stderr </dev/stderr </dev/null) 205 | if [ -z "${CYGPATH}" ]; then 206 | CYGPATH=echo 207 | fi 208 | 209 | normalize_path() { 210 | # convert to unix-format (C:\foo\bar\ --> /c/foo/bar/) 211 | # and lower-case everything (because on microsoft-fs, paths are case-insensitive) 212 | ${CYGPATH} "$1" | tr "[A-Z]" "[a-z]" 213 | } 214 | 215 | list_deps() { 216 | local path 217 | local path0 218 | local inc 219 | "${NTLDD}" "$1" \ 220 | | grep ' => ' \ 221 | | sed -e 's|\\|/|g' -e 's|.* => ||' -e 's| (0.*||' \ 222 | | while read path; do 223 | path0=$(echo $path |sed -e 's|/|\\|g') 224 | inc=$(check_includedep "${path0}") 225 | if [ "x${inc}" != "x" ]; then 226 | echo "${path}" 227 | fi 228 | done 229 | } 230 | 231 | file2arch() { 232 | if file "$1" | grep -w "PE32+" >/dev/null; then 233 | echo "w64" 234 | return 235 | fi 236 | if file "$1" | grep -w "PE32" >/dev/null; then 237 | echo "w32" 238 | return 239 | fi 240 | } 241 | 242 | install_deps () { 243 | local outdir="$2" 244 | local idepfile 245 | local odepfile 246 | local archext 247 | local dep 248 | error "DEP: ${INSTALLDEPS_INDENT}'$1' '$2'" 249 | 250 | if [ "x${outdir}" = "x" ]; then 251 | outdir=${1%/*} 252 | fi 253 | if [ ! -d "${outdir}" ]; then 254 | outdir=. 255 | fi 256 | 257 | list_deps "$1" | while read dep; do 258 | idepfile=$(basename "${dep}") 259 | odepfile=${idepfile} 260 | archext=$(file2arch "${dep}") 261 | if [ "x${archext}" != "x" ]; then 262 | odepfile=$(echo ${idepfile} | sed -e "s|\.dll|.${archext}|") 263 | fi 264 | if [ "x${idepfile}" = "x${odepfile}" ]; then 265 | archext="" 266 | fi 267 | if [ -e "${outdir}/${odepfile}" ]; then 268 | error "DEP: ${INSTALLDEPS_INDENT} ${dep} SKIPPED" 269 | else 270 | error "DEP: ${INSTALLDEPS_INDENT} ${dep} -> ${outdir}/${odepfile}" 271 | cp "${dep}" "${outdir}/${odepfile}" 272 | chmod a-x "${outdir}/${odepfile}" 273 | fi 274 | 275 | if [ "x${archext}" != "x" ]; then 276 | sed -b \ 277 | -e "s|${idepfile}|${odepfile}|g" \ 278 | -i \ 279 | "${outdir}/${odepfile}" "${dep}" "$1" 280 | fi 281 | #recursively resolve dependencies 282 | INSTALLDEPS_INDENT="${INSTALLDEPS_INDENT} " install_deps "${outdir}/${odepfile}" 283 | done 284 | } 285 | 286 | if [ "x${NTLDD}" = "x" ]; then 287 | check_binaries ntldd 288 | NTLDD="ntldd" 289 | fi 290 | 291 | for f in "$@"; do 292 | if [ -e "${f}" ]; then 293 | error 294 | install_deps "${f}" 295 | fi 296 | done --------------------------------------------------------------------------------