├── .gitignore ├── CREDITS.md ├── DEAR-MICROSOFT.md ├── LICENSE ├── Makefile ├── README.md ├── asio.h ├── asio32.h ├── asio64.h ├── classid.c ├── classid.h ├── config.h ├── jackasio.c ├── jackasio.h ├── main.c ├── register.c ├── setwin10.reg ├── tuneables.h ├── win32ify.sed ├── win64ify.sed └── wineasio.dll.spec /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile* 2 | *.o 3 | *.so 4 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | # Credits and Copyrights 2 | 3 | ## 2018 4 | * Michael "mcnster" Nelson 5 | 6 | ## 2013 7 | * Joakim Hernberg 8 | 9 | ## 2010 10 | * Nedko Arnaudov 11 | * Torben Hohn 12 | * Peter L Jones 13 | 14 | ## 2008 15 | * William Steidtmann 16 | 17 | ## 2007 18 | * Stephane Letz 19 | * Johnny Petrantoni 20 | * Ralf Beck 21 | 22 | ## 2006 23 | * Robert Reif 24 | 25 | ## 2003 26 | * John K. Hohn 27 | 28 | --- 29 | 30 | ## 1675 31 | > **_If I have seen further it is by standing on the shoulders of Giants._** 32 | * Isaac Newton 33 | -------------------------------------------------------------------------------- /DEAR-MICROSOFT.md: -------------------------------------------------------------------------------- 1 | Dear Microsoft, 2 | 3 | We like this site (Github) because its clean, has no bots or advertising, and doesn't spam our emails. Would you kindly follow suit? We're giving you the benefit of the doubt here. Maybe you _have_ changed your evil ways. We'll see. But blow it, and we'll be gone in a New York nanosecond. Fair warning. 4 | 5 | Sincerely, 6 | 7 | 8 | The WineASIO Developers 9 | 10 | P.S. And please, please, please, don't rename us "Microsoft GitHub". We all know by now. 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ### Generated by Winemaker 2 | 3 | PREFIX = /usr 4 | SRCDIR = . 5 | SUBDIRS = 6 | DLLS = wineasio.dll 7 | EXES = 8 | 9 | 10 | 11 | ### Common settings 12 | # Removed NATIVE_INT64 definition 13 | # 14 | CEXTRA = -g -O2 -D__WINESRC__ -D_REENTRANT -fPIC -Wall -pipe -fno-strict-aliasing -Wdeclaration-after-statement -Wwrite-strings -Wpointer-arith 15 | CXXEXTRA = -D__WINESRC__ -D_REENTRANT -fPIC -Wall -pipe -fno-strict-aliasing -Wdeclaration-after-statement -Wwrite-strings -Wpointer-arith 16 | RCEXTRA = 17 | INCLUDE_PATH = -I. -I/usr/include -I$(PREFIX)/include -I$(PREFIX)/include/wine -I$(PREFIX)/include/wine/windows 18 | DLL_PATH = 19 | LIBRARY_PATH = 20 | LIBRARIES = -ljack 21 | 22 | 23 | ### wineasio.dll sources and settings 24 | 25 | wineasio_dll_MODULE = wineasio.dll 26 | wineasio_dll_C_SRCS = jackasio.c \ 27 | main.c \ 28 | register.c \ 29 | classid.c 30 | wineasio_dll_CXX_SRCS = 31 | wineasio_dll_RC_SRCS = 32 | wineasio_dll_LDFLAGS = -shared \ 33 | $(wineasio_dll_MODULE:%=%.spec) \ 34 | -mnocygwin \ 35 | -L/usr/lib64/wine \ 36 | -L/usr/lib64 37 | wineasio_dll_DLL_PATH = 38 | wineasio_dll_DLLS = odbc32 \ 39 | ole32 \ 40 | winmm 41 | wineasio_dll_LIBRARY_PATH= 42 | wineasio_dll_LIBRARIES= uuid 43 | 44 | wineasio_dll_OBJS = $(wineasio_dll_C_SRCS:.c=.o) \ 45 | $(wineasio_dll_CXX_SRCS:.cpp=.o) \ 46 | $(wineasio_dll_RC_SRCS:.rc=.res) 47 | 48 | 49 | 50 | ### Global source lists 51 | 52 | C_SRCS = $(wineasio_dll_C_SRCS) 53 | CXX_SRCS = $(wineasio_dll_CXX_SRCS) 54 | RC_SRCS = $(wineasio_dll_RC_SRCS) 55 | 56 | 57 | ### Tools 58 | 59 | CC = gcc 60 | CXX = g++ 61 | WINECC = winegcc 62 | RC = wrc 63 | 64 | 65 | ### Generic targets 66 | 67 | all: asio.h $(SUBDIRS) $(DLLS:%=%.so) $(EXES:%=%.so) 68 | 69 | ### Build rules 70 | 71 | .PHONY: all clean dummy 72 | 73 | $(SUBDIRS): dummy 74 | @cd $@ && $(MAKE) 75 | 76 | # Implicit rules 77 | 78 | .SUFFIXES: .cpp .rc .res 79 | DEFINCL = $(INCLUDE_PATH) $(DEFINES) $(OPTIONS) 80 | 81 | .c.o: 82 | $(CC) -c $(DEFINCL) $(CFLAGS) $(CEXTRA) -o $@ $< 83 | 84 | .cpp.o: 85 | $(CXX) -c $(CXXFLAGS) $(CXXEXTRA) $(DEFINCL) -o $@ $< 86 | 87 | .cxx.o: 88 | $(CXX) -c $(CXXFLAGS) $(CXXEXTRA) $(DEFINCL) -o $@ $< 89 | 90 | .rc.res: 91 | $(RC) $(RCFLAGS) $(RCEXTRA) $(DEFINCL) -fo$@ $< 92 | 93 | # Rules for cleaning 94 | 95 | CLEAN_FILES = y.tab.c y.tab.h lex.yy.c core *.orig *.rej \ 96 | \\\#*\\\# *~ *% .\\\#* 97 | 98 | clean:: $(SUBDIRS:%=%/__clean__) $(EXTRASUBDIRS:%=%/__clean__) 99 | $(RM) $(CLEAN_FILES) $(RC_SRCS:.rc=.res) $(C_SRCS:.c=.o) $(CXX_SRCS:.cpp=.o) 100 | $(RM) $(DLLS:%=%.so) $(EXES:%=%.so) $(EXES:%.exe=%) 101 | 102 | $(SUBDIRS:%=%/__clean__): dummy 103 | cd `dirname $@` && $(MAKE) clean 104 | 105 | $(EXTRASUBDIRS:%=%/__clean__): dummy 106 | -cd `dirname $@` && $(RM) $(CLEAN_FILES) 107 | 108 | distclean:: clean 109 | $(RM) asio.h 110 | 111 | ### Target specific build rules 112 | DEFLIB = $(LIBRARY_PATH) $(LIBRARIES) $(DLL_PATH) 113 | 114 | $(wineasio_dll_MODULE).so: $(wineasio_dll_OBJS) 115 | $(WINECC) $(wineasio_dll_LDFLAGS) -o $@ $(wineasio_dll_OBJS) $(wineasio_dll_LIBRARY_PATH) $(DEFLIB) $(wineasio_dll_DLLS:%=-l%) $(wineasio_dll_LIBRARIES:%=-l%) 116 | 117 | install: 118 | if [ -d $(PREFIX)/lib64/wine ]; then cp wineasio.dll.so $(DESTDIR)$(PREFIX)/lib64/wine; else cp wineasio.dll.so $(DESTDIR)$(PREFIX)/lib/wine; fi 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README.md 2 | 3 | Lossless/skipless FL Studio audio piped through JACK on Linux with Wine. Other Windoze audio programs that make use of ASIO should work as well. 4 | 5 | 6 | ## Installation for FL Studio 20 7 | 8 | ### Install Wine, JACK, and qjackctl 9 | 10 | (Per your Linux distribution.) 11 | 12 | ### Install the WineASIO driver 13 | 14 | ```shell 15 | $ git clone https://github.com/wineasio/wineasio 16 | $ cd wineasio 17 | $ make 18 | # make install 19 | $ export WINEARCH=win64 20 | $ wine64 regsvr32 wineasio.dll 21 | ``` 22 | 23 | `make install` assumes [Arch Linux](https://www.archlinux.org). Adjust the `Makefile` to specify the directory of your system-wide Wine libraries if necessary. 24 | 25 | ### Configure Wine to emulate Windows 10 26 | 27 | ```shell 28 | $ wine64 regedit setwin10.reg 29 | ``` 30 | 31 | ### Install FL Studio 32 | 33 | ```shell 34 | $ wine64 ~/path/to/flstudio-20-win-installer.exe 35 | ``` 36 | 37 | You can download a free demo of FL Studio at [https://www.image-line.com](https://www.image-line.com). All components are enabled except Save. 38 | 39 | ### PAM tweaks for real-time/low-latency 40 | 41 | * Create an `audio` group (if it does not already exist): 42 | ```shell 43 | # groupadd audio 44 | ``` 45 | * Add yourself to the `audio` group: 46 | ```shell 47 | # usermod -a -G audio yourUserID 48 | ``` 49 | * Add to `/etc/security/limits.conf`: 50 | ``` 51 | @audio - rtprio 99 52 | @audio - memlock unlimited 53 | ``` 54 | * Logout and login again. 55 | 56 | 57 | ## Running FL Studio 58 | 59 | ### Start Jack with qjackctl 60 | 61 | ```shell 62 | $ qjackctl 63 | ``` 64 | 65 | * Set the `samplerate` to `44,100` Hz. 66 | * Set the `frames/period` to `2,048` and `periods/buffer` to `4` to begin with, and adjust up or down as required. 67 | * Start the JACK server with qjackctl. Check for errors in the Messages/Status window. Be sure JACK is running in real-time mode. 68 | 69 | ### Start FL Studio 70 | 71 | ```shell 72 | $ wine64 ~/.wine/drive_c/Program\ Files/Image-Line/FL\ Studio\ 20/FL64.exe 2>&1 | tee /dev/null 73 | ``` 74 | 75 | (The somewhat bizarre `tee` is necessary to prevent Wine from blocking indefinitely on start-up. If anyone knows why this is the case, kindly let me know.) 76 | 77 | ### Within FL Studio 78 | 79 | * On the main menu, click `Options | Audio settings...` and set `Device` to `WineASIO`. 80 | * Observe the JACK graph in qjackctl. Eight (8) inputs and eight (8) outputs will be created and connected. 81 | 82 | Play the demo song, then dig in! :) 83 | -------------------------------------------------------------------------------- /asio.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wineasio/wineasio-old-docs/fcd020dff6027b35d5a9930dcf04ea76c137b3c4/asio.h -------------------------------------------------------------------------------- /asio32.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------------- 2 | //--------------------------------------------------------------------------------------------------- 3 | 4 | /* 5 | Steinberg Audio Stream I/O API 6 | (c) 1997 - 2013, Steinberg Media Technologies GmbH 7 | 8 | ASIO Interface Specification v 2.3 9 | 10 | 2005 - Added support for DSD sample data (in cooperation with Sony) 11 | 2012 - Added support for drop out detection 12 | 13 | 14 | 15 | basic concept is an i/o synchronous double-buffer scheme: 16 | 17 | on bufferSwitch(index == 0), host will read/write: 18 | 19 | after ASIOStart(), the 20 | read first input buffer A (index 0) 21 | | will be invalid (empty) 22 | * ------------------------ 23 | |------------------------|-----------------------| 24 | | | | 25 | | Input Buffer A (0) | Input Buffer B (1) | 26 | | | | 27 | |------------------------|-----------------------| 28 | | | | 29 | | Output Buffer A (0) | Output Buffer B (1) | 30 | | | | 31 | |------------------------|-----------------------| 32 | * ------------------------- 33 | | before calling ASIOStart(), 34 | write host will have filled output 35 | buffer B (index 1) already 36 | 37 | *please* take special care of proper statement of input 38 | and output latencies (see ASIOGetLatencies()), these 39 | control sequencer sync accuracy 40 | 41 | */ 42 | 43 | //--------------------------------------------------------------------------------------------------- 44 | //--------------------------------------------------------------------------------------------------- 45 | 46 | /* 47 | 48 | prototypes summary: 49 | 50 | ASIOError ASIOInit(ASIODriverInfo *info); 51 | ASIOError ASIOExit(void); 52 | ASIOError ASIOStart(void); 53 | ASIOError ASIOStop(void); 54 | ASIOError ASIOGetChannels(LONG *numInputChannels, LONG *numOutputChannels); 55 | ASIOError ASIOGetLatencies(LONG *inputLatency, LONG *outputLatency); 56 | ASIOError ASIOGetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity); 57 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); 58 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); 59 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); 60 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, LONG *numSources); 61 | ASIOError ASIOSetClockSource(LONG reference); 62 | ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); 63 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); 64 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, LONG numChannels, 65 | LONG bufferSize, ASIOCallbacks *callbacks); 66 | ASIOError ASIODisposeBuffers(void); 67 | ASIOError ASIOControlPanel(void); 68 | void *ASIOFuture(LONG selector, void *params); 69 | ASIOError ASIOOutputReady(void); 70 | 71 | */ 72 | 73 | //--------------------------------------------------------------------------------------------------- 74 | //--------------------------------------------------------------------------------------------------- 75 | 76 | #ifndef __ASIO_H 77 | #define __ASIO_H 78 | 79 | // force 4 byte alignment 80 | #if defined(_MSC_VER) && !defined(__MWERKS__) 81 | #pragma pack(push,4) 82 | #elif PRAGMA_ALIGN_SUPPORTED 83 | #pragma options align = native 84 | #endif 85 | 86 | //- - - - - - - - - - - - - - - - - - - - - - - - - 87 | // Type definitions 88 | //- - - - - - - - - - - - - - - - - - - - - - - - - 89 | 90 | // number of samples data type is 64 bit integer 91 | #if NATIVE_INT64 92 | typedef LONGLONG ASIOSamples; 93 | #else 94 | typedef struct ASIOSamples { 95 | ULONG hi; 96 | ULONG lo; 97 | } ASIOSamples; 98 | #endif 99 | 100 | // Timestamp data type is 64 bit integer, 101 | // Time format is Nanoseconds. 102 | #if NATIVE_INT64 103 | typedef LONGLONG ASIOTimeStamp ; 104 | #else 105 | typedef struct ASIOTimeStamp { 106 | ULONG hi; 107 | ULONG lo; 108 | } ASIOTimeStamp; 109 | #endif 110 | 111 | // Samplerates are expressed in IEEE 754 64 bit double float, 112 | // native format as host computer 113 | #if IEEE754_64FLOAT 114 | typedef double ASIOSampleRate; 115 | #else 116 | typedef struct ASIOSampleRate { 117 | char ieee[8]; 118 | } ASIOSampleRate; 119 | #endif 120 | 121 | // Boolean values are expressed as LONG 122 | typedef LONG ASIOBool; 123 | enum { 124 | ASIOFalse = 0, 125 | ASIOTrue = 1 126 | }; 127 | 128 | // Sample Types are expressed as LONG 129 | typedef LONG ASIOSampleType; 130 | enum { 131 | ASIOSTInt16MSB = 0, 132 | ASIOSTInt24MSB = 1, // used for 20 bits as well 133 | ASIOSTInt32MSB = 2, 134 | ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float 135 | ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float 136 | 137 | // these are used for 32 bit data buffer, with different alignment of the data inside 138 | // 32 bit PCI bus systems can be more easily used with these 139 | ASIOSTInt32MSB16 = 8, // 32 bit data with 16 bit alignment 140 | ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment 141 | ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment 142 | ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment 143 | 144 | ASIOSTInt16LSB = 16, 145 | ASIOSTInt24LSB = 17, // used for 20 bits as well 146 | ASIOSTInt32LSB = 18, 147 | ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture 148 | ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture 149 | 150 | // these are used for 32 bit data buffer, with different alignment of the data inside 151 | // 32 bit PCI bus systems can more easily used with these 152 | ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment 153 | ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment 154 | ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment 155 | ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment 156 | 157 | // ASIO DSD format. 158 | ASIOSTDSDInt8LSB1 = 32, // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit. 159 | ASIOSTDSDInt8MSB1 = 33, // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit. 160 | ASIOSTDSDInt8NER8 = 40, // DSD 8 bit data, 1 sample per byte. No Endianness required. 161 | 162 | ASIOSTLastEntry 163 | }; 164 | 165 | /*----------------------------------------------------------------------------- 166 | // DSD operation and buffer layout 167 | // Definition by Steinberg/Sony Oxford. 168 | // 169 | // We have tried to treat DSD as PCM and so keep a consistant structure across 170 | // the ASIO interface. 171 | // 172 | // DSD's sample rate is normally referenced as a multiple of 44.1Khz, so 173 | // the standard sample rate is refered to as 64Fs (or 2.8224Mhz). We looked 174 | // at making a special case for DSD and adding a field to the ASIOFuture that 175 | // would allow the user to select the Over Sampleing Rate (OSR) as a seperate 176 | // entity but decided in the end just to treat it as a simple value of 177 | // 2.8224Mhz and use the standard interface to set it. 178 | // 179 | // The second problem was the "word" size, in PCM the word size is always a 180 | // greater than or equal to 8 bits (a byte). This makes life easy as we can 181 | // then pack the samples into the "natural" size for the machine. 182 | // In DSD the "word" size is 1 bit. This is not a major problem and can easily 183 | // be dealt with if we ensure that we always deal with a multiple of 8 samples. 184 | // 185 | // DSD brings with it another twist to the Endianness religion. How are the 186 | // samples packed into the byte. It would be nice to just say the most significant 187 | // bit is always the first sample, however there would then be a performance hit 188 | // on little endian machines. Looking at how some of the processing goes... 189 | // Little endian machines like the first sample to be in the Least Significant Bit, 190 | // this is because when you write it to memory the data is in the correct format 191 | // to be shifted in and out of the words. 192 | // Big endian machine prefer the first sample to be in the Most Significant Bit, 193 | // again for the same reasion. 194 | // 195 | // And just when things were looking really muddy there is a proposed extension to 196 | // DSD that uses 8 bit word sizes. It does not care what endianness you use. 197 | // 198 | // Switching the driver between DSD and PCM mode 199 | // ASIOFuture allows for extending the ASIO API quite transparently. 200 | // See kAsioSetIoFormat, kAsioGetIoFormat, kAsioCanDoIoFormat 201 | // 202 | //-----------------------------------------------------------------------------*/ 203 | 204 | 205 | //- - - - - - - - - - - - - - - - - - - - - - - - - 206 | // Error codes 207 | //- - - - - - - - - - - - - - - - - - - - - - - - - 208 | 209 | typedef LONG ASIOError; 210 | enum { 211 | ASE_OK = 0, // This value will be returned whenever the call succeeded 212 | ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls 213 | ASE_NotPresent = -1000, // hardware input or output is not present or available 214 | ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) 215 | ASE_InvalidParameter, // input parameter invalid 216 | ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode 217 | ASE_SPNotAdvancing, // hardware is not running when sample position is inquired 218 | ASE_NoClock, // sample clock or rate cannot be determined or is not present 219 | ASE_NoMemory // not enough memory for completing the request 220 | }; 221 | 222 | //--------------------------------------------------------------------------------------------------- 223 | //--------------------------------------------------------------------------------------------------- 224 | 225 | //- - - - - - - - - - - - - - - - - - - - - - - - - 226 | // Time Info support 227 | //- - - - - - - - - - - - - - - - - - - - - - - - - 228 | 229 | typedef struct ASIOTimeCode 230 | { 231 | double speed; // speed relation (fraction of nominal speed) 232 | // optional; set to 0. or 1. if not supported 233 | ASIOSamples timeCodeSamples; // time in samples 234 | ULONG flags; // some information flags (see below) 235 | char future[64]; 236 | } ASIOTimeCode; 237 | 238 | typedef enum ASIOTimeCodeFlags 239 | { 240 | kTcValid = 1, 241 | kTcRunning = 1 << 1, 242 | kTcReverse = 1 << 2, 243 | kTcOnspeed = 1 << 3, 244 | kTcStill = 1 << 4, 245 | 246 | kTcSpeedValid = 1 << 8 247 | } ASIOTimeCodeFlags; 248 | 249 | typedef struct AsioTimeInfo 250 | { 251 | double speed; // absolute speed (1. = nominal) 252 | ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds 253 | // on mac, must be derived from Microseconds() (not UpTime()!) 254 | // on windows, must be derived from timeGetTime() 255 | ASIOSamples samplePosition; 256 | ASIOSampleRate sampleRate; // current rate 257 | ULONG flags; // (see below) 258 | char reserved[12]; 259 | } AsioTimeInfo; 260 | 261 | typedef enum AsioTimeInfoFlags 262 | { 263 | kSystemTimeValid = 1, // must always be valid 264 | kSamplePositionValid = 1 << 1, // must always be valid 265 | kSampleRateValid = 1 << 2, 266 | kSpeedValid = 1 << 3, 267 | 268 | kSampleRateChanged = 1 << 4, 269 | kClockSourceChanged = 1 << 5 270 | } AsioTimeInfoFlags; 271 | 272 | typedef struct ASIOTime // both input/output 273 | { 274 | LONG reserved[4]; // must be 0 275 | struct AsioTimeInfo timeInfo; // required 276 | struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) 277 | } ASIOTime; 278 | 279 | /* 280 | 281 | using time info: 282 | it is recommended to use the new method with time info even if the asio 283 | device does not support timecode; continuous calls to ASIOGetSamplePosition 284 | and ASIOGetSampleRate are avoided, and there is a more defined relationship 285 | between callback time and the time info. 286 | 287 | see the example below. 288 | to initiate time info mode, after you have received the callbacks pointer in 289 | ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo 290 | as the argument. if this returns 1, host has accepted time info mode. 291 | now host expects the new callback bufferSwitchTimeInfo to be used instead 292 | of the old bufferSwitch method. the ASIOTime structure is assumed to be valid 293 | and accessible until the callback returns. 294 | 295 | using time code: 296 | if the device supports reading time code, it will call host's asioMessage callback 297 | with kAsioSupportsTimeCode as the selector. it may then fill the according 298 | fields and set the kTcValid flag. 299 | host will call the future method with the kAsioEnableTimeCodeRead selector when 300 | it wants to enable or disable tc reading by the device. you should also support 301 | the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). 302 | 303 | note: 304 | the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. 305 | as a matter of convention, the relationship between the sample 306 | position counter and the time code at buffer switch time is 307 | (ignoring offset between tc and sample pos when tc is running): 308 | 309 | on input: sample 0 -> input buffer sample 0 -> time code 0 310 | on output: sample 0 -> output buffer sample 0 -> time code 0 311 | 312 | this means that for 'real' calculations, one has to take into account 313 | the according latencies. 314 | 315 | example: 316 | 317 | ASIOTime asioTime; 318 | 319 | in createBuffers() 320 | { 321 | memset(&asioTime, 0, sizeof(ASIOTime)); 322 | AsioTimeInfo* ti = &asioTime.timeInfo; 323 | ti->sampleRate = theSampleRate; 324 | ASIOTimeCode* tc = &asioTime.timeCode; 325 | tc->speed = 1.; 326 | timeInfoMode = false; 327 | canTimeCode = false; 328 | if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) 329 | { 330 | timeInfoMode = true; 331 | #if kCanTimeCode 332 | if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) 333 | canTimeCode = true; 334 | #endif 335 | } 336 | } 337 | 338 | void switchBuffers(LONG doubleBufferIndex, bool processNow) 339 | { 340 | if(timeInfoMode) 341 | { 342 | AsioTimeInfo* ti = &asioTime.timeInfo; 343 | ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; 344 | ti->systemTime = theNanoSeconds; 345 | ti->samplePosition = theSamplePosition; 346 | if(ti->sampleRate != theSampleRate) 347 | ti->flags |= kSampleRateChanged; 348 | ti->sampleRate = theSampleRate; 349 | 350 | #if kCanTimeCode 351 | if(canTimeCode && timeCodeEnabled) 352 | { 353 | ASIOTimeCode* tc = &asioTime.timeCode; 354 | tc->timeCodeSamples = tcSamples; // tc in samples 355 | tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... 356 | } 357 | ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); 358 | #else 359 | callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); 360 | #endif 361 | } 362 | else 363 | callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); 364 | } 365 | 366 | ASIOError ASIOFuture(LONG selector, void *params) 367 | { 368 | switch(selector) 369 | { 370 | case kAsioEnableTimeCodeRead: 371 | timeCodeEnabled = true; 372 | return ASE_SUCCESS; 373 | case kAsioDisableTimeCodeRead: 374 | timeCodeEnabled = false; 375 | return ASE_SUCCESS; 376 | case kAsioCanTimeInfo: 377 | return ASE_SUCCESS; 378 | #if kCanTimeCode 379 | case kAsioCanTimeCode: 380 | return ASE_SUCCESS; 381 | #endif 382 | } 383 | return ASE_NotPresent; 384 | }; 385 | 386 | */ 387 | 388 | //- - - - - - - - - - - - - - - - - - - - - - - - - 389 | // application's audio stream handler callbacks 390 | //- - - - - - - - - - - - - - - - - - - - - - - - - 391 | 392 | typedef struct ASIOCallbacks 393 | { 394 | void (*bufferSwitch) (LONG doubleBufferIndex, ASIOBool directProcess); 395 | // bufferSwitch indicates that both input and output are to be processed. 396 | // the current buffer half index (0 for A, 1 for B) determines 397 | // - the output buffer that the host should start to fill. the other buffer 398 | // will be passed to output hardware regardless of whether it got filled 399 | // in time or not. 400 | // - the input buffer that is now filled with incoming data. Note that 401 | // because of the synchronicity of i/o, the input always has at 402 | // least one buffer latency in relation to the output. 403 | // directProcess suggests to the host whether it should immedeately 404 | // start processing (directProcess == ASIOTrue), or whether its process 405 | // should be deferred because the call comes from a very low level 406 | // (for instance, a high level priority interrupt), and direct processing 407 | // would cause timing instabilities for the rest of the system. If in doubt, 408 | // directProcess should be set to ASIOFalse. 409 | // Note: bufferSwitch may be called at interrupt time for highest efficiency. 410 | 411 | void (*sampleRateDidChange) (ASIOSampleRate sRate); 412 | // gets called when the AudioStreamIO detects a sample rate change 413 | // If sample rate is unknown, 0 is passed (for instance, clock loss 414 | // when externally synchronized). 415 | 416 | LONG (*asioMessage) (LONG selector, LONG value, void* message, double* opt); 417 | // generic callback for various purposes, see selectors below. 418 | // note this is only present if the asio version is 2 or higher 419 | 420 | ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, LONG doubleBufferIndex, ASIOBool directProcess); 421 | // new callback with time info. makes ASIOGetSamplePosition() and various 422 | // calls to ASIOGetSampleRate obsolete, 423 | // and allows for timecode sync etc. to be preferred; will be used if 424 | // the driver calls asioMessage with selector kAsioSupportsTimeInfo. 425 | } ASIOCallbacks; 426 | 427 | // asioMessage selectors 428 | enum 429 | { 430 | kAsioSelectorSupported = 1, // selector in , returns 1L if supported, 431 | // 0 otherwise 432 | kAsioEngineVersion, // returns engine (host) asio implementation version, 433 | // 2 or higher 434 | kAsioResetRequest, // request driver reset. if accepted, this 435 | // will close the driver (ASIO_Exit() ) and 436 | // re-open it again (ASIO_Init() etc). some 437 | // drivers need to reconfigure for instance 438 | // when the sample rate changes, or some basic 439 | // changes have been made in ASIO_ControlPanel(). 440 | // returns 1L; note the request is merely passed 441 | // to the application, there is no way to determine 442 | // if it gets accepted at this time (but it usually 443 | // will be). 444 | kAsioBufferSizeChange, // not yet supported, will currently always return 0L. 445 | // for now, use kAsioResetRequest instead. 446 | // once implemented, the new buffer size is expected 447 | // in , and on success returns 1L 448 | kAsioResyncRequest, // the driver went out of sync, such that 449 | // the timestamp is no LONGer valid. this 450 | // is a request to re-start the engine and 451 | // slave devices (sequencer). returns 1 for ok, 452 | // 0 if not supported. 453 | kAsioLatenciesChanged, // the drivers latencies have changed. The engine 454 | // will refetch the latencies. 455 | kAsioSupportsTimeInfo, // if host returns true here, it will expect the 456 | // callback bufferSwitchTimeInfo to be called instead 457 | // of bufferSwitch 458 | kAsioSupportsTimeCode, // 459 | kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands 460 | kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this 461 | kAsioSupportsInputGain, // unused and undefined 462 | kAsioSupportsInputMeter, // unused and undefined 463 | kAsioSupportsOutputGain, // unused and undefined 464 | kAsioSupportsOutputMeter, // unused and undefined 465 | kAsioOverload, // driver detected an overload 466 | 467 | kAsioNumMessageSelectors 468 | }; 469 | 470 | //--------------------------------------------------------------------------------------------------- 471 | //--------------------------------------------------------------------------------------------------- 472 | 473 | //- - - - - - - - - - - - - - - - - - - - - - - - - 474 | // (De-)Construction 475 | //- - - - - - - - - - - - - - - - - - - - - - - - - 476 | 477 | typedef struct ASIODriverInfo 478 | { 479 | LONG asioVersion; // currently, 2 480 | LONG driverVersion; // driver specific 481 | char name[32]; 482 | char errorMessage[124]; 483 | void *sysRef; // on input: system reference 484 | // (Windows: application main window handle, Mac & SGI: 0) 485 | } ASIODriverInfo; 486 | 487 | ASIOError ASIOInit(ASIODriverInfo *info); 488 | /* Purpose: 489 | Initialize the AudioStreamIO. 490 | Parameter: 491 | info: pointer to an ASIODriver structure: 492 | - asioVersion: 493 | - on input, the host version. *** Note *** this is 0 for earlier asio 494 | implementations, and the asioMessage callback is implemeted 495 | only if asioVersion is 2 or greater. sorry but due to a design fault 496 | the driver doesn't have access to the host version in ASIOInit :-( 497 | added selector for host (engine) version in the asioMessage callback 498 | so we're ok from now on. 499 | - on return, asio implementation version. 500 | older versions are 1 501 | if you support this version (namely, ASIO_outputReady() ) 502 | this should be 2 or higher. also see the note in 503 | ASIO_getTimeStamp() ! 504 | - version: on return, the driver version (format is driver specific) 505 | - name: on return, a null-terminated string containing the driver's name 506 | - error message: on return, should contain a user message describing 507 | the type of error that occured during ASIOInit(), if any. 508 | - sysRef: platform specific 509 | Returns: 510 | If neither input nor output is present ASE_NotPresent 511 | will be returned. 512 | ASE_NoMemory, ASE_HWMalfunction are other possible error conditions 513 | */ 514 | 515 | ASIOError ASIOExit(void); 516 | /* Purpose: 517 | Terminates the AudioStreamIO. 518 | Parameter: 519 | None. 520 | Returns: 521 | If neither input nor output is present ASE_NotPresent 522 | will be returned. 523 | Notes: this implies ASIOStop() and ASIODisposeBuffers(), 524 | meaning that no host callbacks must be accessed after ASIOExit(). 525 | */ 526 | 527 | //- - - - - - - - - - - - - - - - - - - - - - - - - 528 | // Start/Stop 529 | //- - - - - - - - - - - - - - - - - - - - - - - - - 530 | 531 | ASIOError ASIOStart(void); 532 | /* Purpose: 533 | Start input and output processing synchronously. 534 | This will 535 | - reset the sample counter to zero 536 | - start the hardware (both input and output) 537 | The first call to the hosts' bufferSwitch(index == 0) then tells 538 | the host to read from input buffer A (index 0), and start 539 | processing to output buffer A while output buffer B (which 540 | has been filled by the host prior to calling ASIOStart()) 541 | is possibly sounding (see also ASIOGetLatencies()) 542 | Parameter: 543 | None. 544 | Returns: 545 | If neither input nor output is present, ASE_NotPresent 546 | will be returned. 547 | If the hardware fails to start, ASE_HWMalfunction will be returned. 548 | Notes: 549 | There is no restriction on the time that ASIOStart() takes 550 | to perform (that is, it is not considered a realtime trigger). 551 | */ 552 | 553 | ASIOError ASIOStop(void); 554 | /* Purpose: 555 | Stops input and output processing altogether. 556 | Parameter: 557 | None. 558 | Returns: 559 | If neither input nor output is present ASE_NotPresent 560 | will be returned. 561 | Notes: 562 | On return from ASIOStop(), the driver must in no 563 | case call the hosts' bufferSwitch() routine. 564 | */ 565 | 566 | //- - - - - - - - - - - - - - - - - - - - - - - - - 567 | // Inquiry methods and sample rate 568 | //- - - - - - - - - - - - - - - - - - - - - - - - - 569 | 570 | ASIOError ASIOGetChannels(LONG *numInputChannels, LONG *numOutputChannels); 571 | /* Purpose: 572 | Returns number of individual input/output channels. 573 | Parameter: 574 | numInputChannels will hold the number of available input channels 575 | numOutputChannels will hold the number of available output channels 576 | Returns: 577 | If no input/output is present ASE_NotPresent will be returned. 578 | If only inputs, or only outputs are available, the according 579 | other parameter will be zero, and ASE_OK is returned. 580 | */ 581 | 582 | ASIOError ASIOGetLatencies(LONG *inputLatency, LONG *outputLatency); 583 | /* Purpose: 584 | Returns the input and output latencies. This includes 585 | device specific delays, like FIFOs etc. 586 | Parameter: 587 | inputLatency will hold the 'age' of the first sample frame 588 | in the input buffer when the hosts reads it in bufferSwitch() 589 | (this is theoretical, meaning it does not include the overhead 590 | and delay between the actual physical switch, and the time 591 | when bufferSitch() enters). 592 | This will usually be the size of one block in sample frames, plus 593 | device specific latencies. 594 | 595 | outputLatency will specify the time between the buffer switch, 596 | and the time when the next play buffer will start to sound. 597 | The next play buffer is defined as the one the host starts 598 | processing after (or at) bufferSwitch(), indicated by the 599 | index parameter (0 for buffer A, 1 for buffer B). 600 | It will usually be either one block, if the host writes directly 601 | to a dma buffer, or two or more blocks if the buffer is 'latched' by 602 | the driver. As an example, on ASIOStart(), the host will have filled 603 | the play buffer at index 1 already; when it gets the callback (with 604 | the parameter index == 0), this tells it to read from the input 605 | buffer 0, and start to fill the play buffer 0 (assuming that now 606 | play buffer 1 is already sounding). In this case, the output 607 | latency is one block. If the driver decides to copy buffer 1 608 | at that time, and pass it to the hardware at the next slot (which 609 | is most commonly done, but should be avoided), the output latency 610 | becomes two blocks instead, resulting in a total i/o latency of at least 611 | 3 blocks. As memory access is the main bottleneck in native dsp processing, 612 | and to acheive less latency, it is highly recommended to try to avoid 613 | copying (this is also why the driver is the owner of the buffers). To 614 | summarize, the minimum i/o latency can be acheived if the input buffer 615 | is processed by the host into the output buffer which will physically 616 | start to sound on the next time slice. Also note that the host expects 617 | the bufferSwitch() callback to be accessed for each time slice in order 618 | to retain sync, possibly recursively; if it fails to process a block in 619 | time, it will suspend its operation for some time in order to recover. 620 | Returns: 621 | If no input/output is present ASE_NotPresent will be returned. 622 | */ 623 | 624 | ASIOError ASIOGetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity); 625 | /* Purpose: 626 | Returns min, max, and preferred buffer sizes for input/output 627 | Parameter: 628 | minSize will hold the minimum buffer size 629 | maxSize will hold the maxium possible buffer size 630 | preferredSize will hold the preferred buffer size (a size which 631 | best fits performance and hardware requirements) 632 | granularity will hold the granularity at which buffer sizes 633 | may differ. Usually, the buffer size will be a power of 2; 634 | in this case, granularity will hold -1 on return, signalling 635 | possible buffer sizes starting from minSize, increased in 636 | powers of 2 up to maxSize. 637 | Returns: 638 | If no input/output is present ASE_NotPresent will be returned. 639 | Notes: 640 | When minimum and maximum buffer size are equal, 641 | the preferred buffer size has to be the same value as well; granularity 642 | should be 0 in this case. 643 | */ 644 | 645 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); 646 | /* Purpose: 647 | Inquires the hardware for the available sample rates. 648 | Parameter: 649 | sampleRate is the rate in question. 650 | Returns: 651 | If the inquired sample rate is not supported, ASE_NoClock will be returned. 652 | If no input/output is present ASE_NotPresent will be returned. 653 | */ 654 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); 655 | /* Purpose: 656 | Get the current sample Rate. 657 | Parameter: 658 | currentRate will hold the current sample rate on return. 659 | Returns: 660 | If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. 661 | If no input/output is present ASE_NotPresent will be returned. 662 | Notes: 663 | */ 664 | 665 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); 666 | /* Purpose: 667 | Set the hardware to the requested sample Rate. If sampleRate == 0, 668 | enable external sync. 669 | Parameter: 670 | sampleRate: on input, the requested rate 671 | Returns: 672 | If sampleRate is unknown ASE_NoClock will be returned. 673 | If the current clock is external, and sampleRate is != 0, 674 | ASE_InvalidMode will be returned 675 | If no input/output is present ASE_NotPresent will be returned. 676 | Notes: 677 | */ 678 | 679 | typedef struct ASIOClockSource 680 | { 681 | LONG index; // as used for ASIOSetClockSource() 682 | LONG associatedChannel; // for instance, S/PDIF or AES/EBU 683 | LONG associatedGroup; // see channel groups (ASIOGetChannelInfo()) 684 | ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source 685 | char name[32]; // for user selection 686 | } ASIOClockSource; 687 | 688 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, LONG *numSources); 689 | /* Purpose: 690 | Get the available external audio clock sources 691 | Parameter: 692 | clocks points to an array of ASIOClockSource structures: 693 | - index: this is used to identify the clock source 694 | when ASIOSetClockSource() is accessed, should be 695 | an index counting from zero 696 | - associatedInputChannel: the first channel of an associated 697 | input group, if any. 698 | - associatedGroup: the group index of that channel. 699 | groups of channels are defined to seperate for 700 | instance analog, S/PDIF, AES/EBU, ADAT connectors etc, 701 | when present simultaniously. Note that associated channel 702 | is enumerated according to numInputs/numOutputs, means it 703 | is independant from a group (see also ASIOGetChannelInfo()) 704 | inputs are associated to a clock if the physical connection 705 | transfers both data and clock (like S/PDIF, AES/EBU, or 706 | ADAT inputs). if there is no input channel associated with 707 | the clock source (like Word Clock, or internal oscillator), both 708 | associatedChannel and associatedGroup should be set to -1. 709 | - isCurrentSource: on exit, ASIOTrue if this is the current clock 710 | source, ASIOFalse else 711 | - name: a null-terminated string for user selection of the available sources. 712 | numSources: 713 | on input: the number of allocated array members 714 | on output: the number of available clock sources, at least 715 | 1 (internal clock generator). 716 | Returns: 717 | If no input/output is present ASE_NotPresent will be returned. 718 | Notes: 719 | */ 720 | 721 | ASIOError ASIOSetClockSource(LONG index); 722 | /* Purpose: 723 | Set the audio clock source 724 | Parameter: 725 | index as obtained from an inquiry to ASIOGetClockSources() 726 | Returns: 727 | If no input/output is present ASE_NotPresent will be returned. 728 | If the clock can not be selected because an input channel which 729 | carries the current clock source is active, ASE_InvalidMode 730 | *may* be returned (this depends on the properties of the driver 731 | and/or hardware). 732 | Notes: 733 | Should *not* return ASE_NoClock if there is no clock signal present 734 | at the selected source; this will be inquired via ASIOGetSampleRate(). 735 | It should call the host callback procedure sampleRateHasChanged(), 736 | if the switch causes a sample rate change, or if no external clock 737 | is present at the selected source. 738 | */ 739 | 740 | ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); 741 | /* Purpose: 742 | Inquires the sample position/time stamp pair. 743 | Parameter: 744 | sPos will hold the sample position on return. The sample 745 | position is reset to zero when ASIOStart() gets called. 746 | tStamp will hold the system time when the sample position 747 | was latched. 748 | Returns: 749 | If no input/output is present, ASE_NotPresent will be returned. 750 | If there is no clock, ASE_SPNotAdvancing will be returned. 751 | Notes: 752 | 753 | in order to be able to synchronise properly, 754 | the sample position / time stamp pair must refer to the current block, 755 | that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() 756 | callback and expect the time for the current block. thus, when requested 757 | in the very first bufferSwitch after ASIO_Start(), the sample position 758 | should be zero, and the time stamp should refer to the very time where 759 | the stream was started. it also means that the sample position must be 760 | block aligned. the driver must ensure proper interpolation if the system 761 | time can not be determined for the block position. the driver is responsible 762 | for precise time stamps as it usually has most direct access to lower 763 | level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() 764 | are essential for precise media synchronization! 765 | */ 766 | 767 | typedef struct ASIOChannelInfo 768 | { 769 | LONG channel; // on input, channel index 770 | ASIOBool isInput; // on input 771 | ASIOBool isActive; // on exit 772 | LONG channelGroup; // dto 773 | ASIOSampleType type; // dto 774 | char name[32]; // dto 775 | } ASIOChannelInfo; 776 | 777 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); 778 | /* Purpose: 779 | retreive information about the nature of a channel 780 | Parameter: 781 | info: pointer to a ASIOChannelInfo structure with 782 | - channel: on input, the channel index of the channel in question. 783 | - isInput: on input, ASIOTrue if info for an input channel is 784 | requested, else output 785 | - channelGroup: on return, the channel group that the channel 786 | beLONGs to. For drivers which support different types of 787 | channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, 788 | there should be a reasonable grouping of these types. Groups 789 | are always independant form a channel index, that is, a channel 790 | index always counts from 0 to numInputs/numOutputs regardless 791 | of the group it may beLONG to. 792 | There will always be at least one group (group 0). Please 793 | also note that by default, the host may decide to activate 794 | channels 0 and 1; thus, these should beLONG to the most 795 | useful type (analog i/o, if present). 796 | - type: on return, contains the sample type of the channel 797 | - isActive: on return, ASIOTrue if channel is active as it was 798 | installed by ASIOCreateBuffers(), ASIOFalse else 799 | - name: describing the type of channel in question. Used to allow 800 | for user selection, and enabling of specific channels. examples: 801 | "Analog In", "SPDIF Out" etc 802 | Returns: 803 | If no input/output is present ASE_NotPresent will be returned. 804 | Notes: 805 | If possible, the string should be organised such that the first 806 | characters are most significantly describing the nature of the 807 | port, to allow for identification even if the view showing the 808 | port name is too small to display more than 8 characters, for 809 | instance. 810 | */ 811 | 812 | //- - - - - - - - - - - - - - - - - - - - - - - - - 813 | // Buffer preparation 814 | //- - - - - - - - - - - - - - - - - - - - - - - - - 815 | 816 | typedef struct ASIOBufferInfo 817 | { 818 | ASIOBool isInput; // on input: ASIOTrue: input, else output 819 | LONG channelNum; // on input: channel index 820 | void *buffers[2]; // on output: double buffer addresses 821 | } ASIOBufferInfo; 822 | 823 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, LONG numChannels, 824 | LONG bufferSize, ASIOCallbacks *callbacks); 825 | 826 | /* Purpose: 827 | Allocates input/output buffers for all input and output channels to be activated. 828 | Parameter: 829 | bufferInfos is a pointer to an array of ASIOBufferInfo structures: 830 | - isInput: on input, ASIOTrue if the buffer is to be allocated 831 | for an input, output buffer else 832 | - channelNum: on input, the index of the channel in question 833 | (counting from 0) 834 | - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. 835 | the size of the buffer(s) of course depend on both the ASIOSampleType 836 | as obtained from ASIOGetChannelInfo(), and bufferSize 837 | numChannels is the sum of all input and output channels to be created; 838 | thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo 839 | structures. 840 | bufferSize selects one of the possible buffer sizes as obtained from 841 | ASIOGetBufferSizes(). 842 | callbacks is a pointer to an ASIOCallbacks structure. 843 | Returns: 844 | If not enough memory is available ASE_NoMemory will be returned. 845 | If no input/output is present ASE_NotPresent will be returned. 846 | If bufferSize is not supported, or one or more of the bufferInfos elements 847 | contain invalid settings, ASE_InvalidMode will be returned. 848 | Notes: 849 | If individual channel selection is not possible but requested, 850 | the driver has to handle this. namely, bufferSwitch() will only 851 | have filled buffers of enabled outputs. If possible, processing 852 | and buss activities overhead should be avoided for channels which 853 | were not enabled here. 854 | */ 855 | 856 | ASIOError ASIODisposeBuffers(void); 857 | /* Purpose: 858 | Releases all buffers for the device. 859 | Parameter: 860 | None. 861 | Returns: 862 | If no buffer were ever prepared, ASE_InvalidMode will be returned. 863 | If no input/output is present ASE_NotPresent will be returned. 864 | Notes: 865 | This implies ASIOStop(). 866 | */ 867 | 868 | ASIOError ASIOControlPanel(void); 869 | /* Purpose: 870 | request the driver to start a control panel component 871 | for device specific user settings. This will not be 872 | accessed on some platforms (where the component is accessed 873 | instead). 874 | Parameter: 875 | None. 876 | Returns: 877 | If no panel is available ASE_NotPresent will be returned. 878 | Actually, the return code is ignored. 879 | Notes: 880 | if the user applied settings which require a re-configuration 881 | of parts or all of the enigine and/or driver (such as a change of 882 | the block size), the asioMessage callback can be used (see 883 | ASIO_Callbacks). 884 | */ 885 | 886 | ASIOError ASIOFuture(LONG selector, void *params); 887 | /* Purpose: 888 | various 889 | Parameter: 890 | selector: operation Code as to be defined. zero is reserved for 891 | testing purposes. 892 | params: depends on the selector; usually pointer to a structure 893 | for passing and retreiving any type and amount of parameters. 894 | Returns: 895 | the return value is also selector dependant. if the selector 896 | is unknown, ASE_InvalidParameter should be returned to prevent 897 | further calls with this selector. on success, ASE_SUCCESS 898 | must be returned (note: ASE_OK is *not* sufficient!) 899 | Notes: 900 | see selectors defined below. 901 | */ 902 | 903 | enum 904 | { 905 | kAsioEnableTimeCodeRead = 1, // no arguments 906 | kAsioDisableTimeCodeRead, // no arguments 907 | kAsioSetInputMonitor, // ASIOInputMonitor* in params 908 | kAsioTransport, // ASIOTransportParameters* in params 909 | kAsioSetInputGain, // ASIOChannelControls* in params, apply gain 910 | kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter 911 | kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain 912 | kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter 913 | kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors 914 | kAsioCanTimeInfo, 915 | kAsioCanTimeCode, 916 | kAsioCanTransport, 917 | kAsioCanInputGain, 918 | kAsioCanInputMeter, 919 | kAsioCanOutputGain, 920 | kAsioCanOutputMeter, 921 | kAsioOptionalOne, 922 | 923 | // DSD support 924 | // The following extensions are required to allow switching 925 | // and control of the DSD subsystem. 926 | kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */ 927 | kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */ 928 | kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */ 929 | 930 | // Extension for drop out detection 931 | kAsioCanReportOverload = 0x24042012, /* return ASE_SUCCESS if driver can detect and report overloads */ 932 | 933 | kAsioGetInternalBufferSamples = 0x25042012 /* ASIOInternalBufferInfo * in params. Deliver size of driver internal buffering, return ASE_SUCCESS if supported */ 934 | }; 935 | 936 | typedef struct ASIOInputMonitor 937 | { 938 | LONG input; // this input was set to monitor (or off), -1: all 939 | LONG output; // suggested output for monitoring the input (if so) 940 | LONG gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) 941 | ASIOBool state; // ASIOTrue => on, ASIOFalse => off 942 | LONG pan; // suggested pan, 0 => all left, 0x7fffffff => right 943 | } ASIOInputMonitor; 944 | 945 | typedef struct ASIOChannelControls 946 | { 947 | LONG channel; // on input, channel index 948 | ASIOBool isInput; // on input 949 | LONG gain; // on input, ranges 0 thru 0x7fffffff 950 | LONG meter; // on return, ranges 0 thru 0x7fffffff 951 | char future[32]; 952 | } ASIOChannelControls; 953 | 954 | typedef struct ASIOTransportParameters 955 | { 956 | LONG command; // see enum below 957 | ASIOSamples samplePosition; 958 | LONG track; 959 | LONG trackSwitches[16]; // 512 tracks on/off 960 | char future[64]; 961 | } ASIOTransportParameters; 962 | 963 | enum 964 | { 965 | kTransStart = 1, 966 | kTransStop, 967 | kTransLocate, // to samplePosition 968 | kTransPunchIn, 969 | kTransPunchOut, 970 | kTransArmOn, // track 971 | kTransArmOff, // track 972 | kTransMonitorOn, // track 973 | kTransMonitorOff, // track 974 | kTransArm, // trackSwitches 975 | kTransMonitor // trackSwitches 976 | }; 977 | 978 | /* 979 | // DSD support 980 | // Some notes on how to use ASIOIoFormatType. 981 | // 982 | // The caller will fill the format with the request types. 983 | // If the board can do the request then it will leave the 984 | // values unchanged. If the board does not support the 985 | // request then it will change that entry to Invalid (-1) 986 | // 987 | // So to request DSD then 988 | // 989 | // ASIOIoFormat NeedThis={kASIODSDFormat}; 990 | // 991 | // if(ASE_SUCCESS != ASIOFuture(kAsioSetIoFormat,&NeedThis) ){ 992 | // // If the board did not accept one of the parameters then the 993 | // // whole call will fail and the failing parameter will 994 | // // have had its value changes to -1. 995 | // } 996 | // 997 | // Note: Switching between the formats need to be done before the "prepared" 998 | // state (see ASIO 2 documentation) is entered. 999 | */ 1000 | typedef LONG ASIOIoFormatType; 1001 | enum ASIOIoFormatType_e 1002 | { 1003 | kASIOFormatInvalid = -1, 1004 | kASIOPCMFormat = 0, 1005 | kASIODSDFormat = 1, 1006 | }; 1007 | 1008 | typedef struct ASIOIoFormat_s 1009 | { 1010 | ASIOIoFormatType FormatType; 1011 | char future[512-sizeof(ASIOIoFormatType)]; 1012 | } ASIOIoFormat; 1013 | 1014 | // Extension for drop detection 1015 | // Note: Refers to buffering that goes beyond the double buffer e.g. used by USB driver designs 1016 | typedef struct ASIOInternalBufferInfo 1017 | { 1018 | LONG inputSamples; // size of driver's internal input buffering which is included in getLatencies 1019 | LONG outputSamples; // size of driver's internal output buffering which is included in getLatencies 1020 | } ASIOInternalBufferInfo; 1021 | 1022 | 1023 | ASIOError ASIOOutputReady(void); 1024 | /* Purpose: 1025 | this tells the driver that the host has completed processing 1026 | the output buffers. if the data format required by the hardware 1027 | differs from the supported asio formats, but the hardware 1028 | buffers are DMA buffers, the driver will have to convert 1029 | the audio stream data; as the bufferSwitch callback is 1030 | usually issued at dma block switch time, the driver will 1031 | have to convert the *previous* host buffer, which increases 1032 | the output latency by one block. 1033 | when the host finds out that ASIOOutputReady() returns 1034 | true, it will issue this call whenever it completed 1035 | output processing. then the driver can convert the 1036 | host data directly to the dma buffer to be played next, 1037 | reducing output latency by one block. 1038 | another way to look at it is, that the buffer switch is called 1039 | in order to pass the *input* stream to the host, so that it can 1040 | process the input into the output, and the output stream is passed 1041 | to the driver when the host has completed its process. 1042 | Parameter: 1043 | None 1044 | Returns: 1045 | only if the above mentioned scenario is given, and a reduction 1046 | of output latency can be acheived by this mechanism, should 1047 | ASE_OK be returned. otherwise (and usually), ASE_NotPresent 1048 | should be returned in order to prevent further calls to this 1049 | function. note that the host may want to determine if it is 1050 | to use this when the system is not yet fully initialized, so 1051 | ASE_OK should always be returned if the mechanism makes sense. 1052 | Notes: 1053 | please remeber to adjust ASIOGetLatencies() according to 1054 | whether ASIOOutputReady() was ever called or not, if your 1055 | driver supports this scenario. 1056 | also note that the engine may fail to call ASIO_OutputReady() 1057 | in time in overload cases. as already mentioned, bufferSwitch 1058 | should be called for every block regardless of whether a block 1059 | could be processed in time. 1060 | */ 1061 | 1062 | // restore old alignment 1063 | #if defined(_MSC_VER) && !defined(__MWERKS__) 1064 | #pragma pack(pop) 1065 | #elif PRAGMA_ALIGN_SUPPORTED 1066 | #pragma options align = reset 1067 | #endif 1068 | 1069 | #endif 1070 | 1071 | -------------------------------------------------------------------------------- /asio64.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------------- 2 | //--------------------------------------------------------------------------------------------------- 3 | 4 | /* 5 | Steinberg Audio Stream I/O API 6 | (c) 1997 - 2013, Steinberg Media Technologies GmbH 7 | 8 | ASIO Interface Specification v 2.3 9 | 10 | 2005 - Added support for DSD sample data (in cooperation with Sony) 11 | 2012 - Added support for drop out detection 12 | 13 | 14 | 15 | basic concept is an i/o synchronous double-buffer scheme: 16 | 17 | on bufferSwitch(index == 0), host will read/write: 18 | 19 | after ASIOStart(), the 20 | read first input buffer A (index 0) 21 | | will be invalid (empty) 22 | * ------------------------ 23 | |------------------------|-----------------------| 24 | | | | 25 | | Input Buffer A (0) | Input Buffer B (1) | 26 | | | | 27 | |------------------------|-----------------------| 28 | | | | 29 | | Output Buffer A (0) | Output Buffer B (1) | 30 | | | | 31 | |------------------------|-----------------------| 32 | * ------------------------- 33 | | before calling ASIOStart(), 34 | write host will have filled output 35 | buffer B (index 1) already 36 | 37 | *please* take special care of proper statement of input 38 | and output latencies (see ASIOGetLatencies()), these 39 | control sequencer sync accuracy 40 | 41 | */ 42 | 43 | //--------------------------------------------------------------------------------------------------- 44 | //--------------------------------------------------------------------------------------------------- 45 | 46 | /* 47 | 48 | prototypes summary: 49 | 50 | ASIOError ASIOInit(ASIODriverInfo *info); 51 | ASIOError ASIOExit(void); 52 | ASIOError ASIOStart(void); 53 | ASIOError ASIOStop(void); 54 | ASIOError ASIOGetChannels(LONG *numInputChannels, LONG *numOutputChannels); 55 | ASIOError ASIOGetLatencies(LONG *inputLatency, LONG *outputLatency); 56 | ASIOError ASIOGetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity); 57 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); 58 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); 59 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); 60 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, LONG *numSources); 61 | ASIOError ASIOSetClockSource(LONG reference); 62 | ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); 63 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); 64 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, LONG numChannels, 65 | LONG bufferSize, ASIOCallbacks *callbacks); 66 | ASIOError ASIODisposeBuffers(void); 67 | ASIOError ASIOControlPanel(void); 68 | void *ASIOFuture(LONG selector, void *params); 69 | ASIOError ASIOOutputReady(void); 70 | 71 | */ 72 | 73 | //--------------------------------------------------------------------------------------------------- 74 | //--------------------------------------------------------------------------------------------------- 75 | 76 | #ifndef __ASIO_H 77 | #define __ASIO_H 78 | 79 | // force 4 byte alignment 80 | #if defined(_MSC_VER) && !defined(__MWERKS__) 81 | #pragma pack(push,4) 82 | #elif PRAGMA_ALIGN_SUPPORTED 83 | #pragma options align = native 84 | #endif 85 | 86 | //- - - - - - - - - - - - - - - - - - - - - - - - - 87 | // Type definitions 88 | //- - - - - - - - - - - - - - - - - - - - - - - - - 89 | 90 | // number of samples data type is 64 bit integer 91 | #if NATIVE_INT64 92 | typedef LONGLONG ASIOSamples; 93 | #else 94 | typedef struct ASIOSamples { 95 | ULONG hi; 96 | ULONG lo; 97 | } ASIOSamples; 98 | #endif 99 | 100 | // Timestamp data type is 64 bit integer, 101 | // Time format is Nanoseconds. 102 | #if NATIVE_INT64 103 | typedef LONGLONG ASIOTimeStamp ; 104 | #else 105 | typedef struct ASIOTimeStamp { 106 | ULONG hi; 107 | ULONG lo; 108 | } ASIOTimeStamp; 109 | #endif 110 | 111 | // Samplerates are expressed in IEEE 754 64 bit double float, 112 | // native format as host computer 113 | #if IEEE754_64FLOAT 114 | typedef double ASIOSampleRate; 115 | #else 116 | typedef struct ASIOSampleRate { 117 | char ieee[8]; 118 | } ASIOSampleRate; 119 | #endif 120 | 121 | // Boolean values are expressed as LONG 122 | typedef LONG ASIOBool; 123 | enum { 124 | ASIOFalse = 0, 125 | ASIOTrue = 1 126 | }; 127 | 128 | // Sample Types are expressed as LONG 129 | typedef LONG ASIOSampleType; 130 | enum { 131 | ASIOSTInt16MSB = 0, 132 | ASIOSTInt24MSB = 1, // used for 20 bits as well 133 | ASIOSTInt32MSB = 2, 134 | ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float 135 | ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float 136 | 137 | // these are used for 32 bit data buffer, with different alignment of the data inside 138 | // 32 bit PCI bus systems can be more easily used with these 139 | ASIOSTInt32MSB16 = 8, // 32 bit data with 16 bit alignment 140 | ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment 141 | ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment 142 | ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment 143 | 144 | ASIOSTInt16LSB = 16, 145 | ASIOSTInt24LSB = 17, // used for 20 bits as well 146 | ASIOSTInt32LSB = 18, 147 | ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture 148 | ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture 149 | 150 | // these are used for 32 bit data buffer, with different alignment of the data inside 151 | // 32 bit PCI bus systems can more easily used with these 152 | ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment 153 | ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment 154 | ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment 155 | ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment 156 | 157 | // ASIO DSD format. 158 | ASIOSTDSDInt8LSB1 = 32, // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit. 159 | ASIOSTDSDInt8MSB1 = 33, // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit. 160 | ASIOSTDSDInt8NER8 = 40, // DSD 8 bit data, 1 sample per byte. No Endianness required. 161 | 162 | ASIOSTLastEntry 163 | }; 164 | 165 | /*----------------------------------------------------------------------------- 166 | // DSD operation and buffer layout 167 | // Definition by Steinberg/Sony Oxford. 168 | // 169 | // We have tried to treat DSD as PCM and so keep a consistant structure across 170 | // the ASIO interface. 171 | // 172 | // DSD's sample rate is normally referenced as a multiple of 44.1Khz, so 173 | // the standard sample rate is refered to as 64Fs (or 2.8224Mhz). We looked 174 | // at making a special case for DSD and adding a field to the ASIOFuture that 175 | // would allow the user to select the Over Sampleing Rate (OSR) as a seperate 176 | // entity but decided in the end just to treat it as a simple value of 177 | // 2.8224Mhz and use the standard interface to set it. 178 | // 179 | // The second problem was the "word" size, in PCM the word size is always a 180 | // greater than or equal to 8 bits (a byte). This makes life easy as we can 181 | // then pack the samples into the "natural" size for the machine. 182 | // In DSD the "word" size is 1 bit. This is not a major problem and can easily 183 | // be dealt with if we ensure that we always deal with a multiple of 8 samples. 184 | // 185 | // DSD brings with it another twist to the Endianness religion. How are the 186 | // samples packed into the byte. It would be nice to just say the most significant 187 | // bit is always the first sample, however there would then be a performance hit 188 | // on little endian machines. Looking at how some of the processing goes... 189 | // Little endian machines like the first sample to be in the Least Significant Bit, 190 | // this is because when you write it to memory the data is in the correct format 191 | // to be shifted in and out of the words. 192 | // Big endian machine prefer the first sample to be in the Most Significant Bit, 193 | // again for the same reasion. 194 | // 195 | // And just when things were looking really muddy there is a proposed extension to 196 | // DSD that uses 8 bit word sizes. It does not care what endianness you use. 197 | // 198 | // Switching the driver between DSD and PCM mode 199 | // ASIOFuture allows for extending the ASIO API quite transparently. 200 | // See kAsioSetIoFormat, kAsioGetIoFormat, kAsioCanDoIoFormat 201 | // 202 | //-----------------------------------------------------------------------------*/ 203 | 204 | 205 | //- - - - - - - - - - - - - - - - - - - - - - - - - 206 | // Error codes 207 | //- - - - - - - - - - - - - - - - - - - - - - - - - 208 | 209 | typedef LONG ASIOError; 210 | enum { 211 | ASE_OK = 0, // This value will be returned whenever the call succeeded 212 | ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls 213 | ASE_NotPresent = -1000, // hardware input or output is not present or available 214 | ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) 215 | ASE_InvalidParameter, // input parameter invalid 216 | ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode 217 | ASE_SPNotAdvancing, // hardware is not running when sample position is inquired 218 | ASE_NoClock, // sample clock or rate cannot be determined or is not present 219 | ASE_NoMemory // not enough memory for completing the request 220 | }; 221 | 222 | //--------------------------------------------------------------------------------------------------- 223 | //--------------------------------------------------------------------------------------------------- 224 | 225 | //- - - - - - - - - - - - - - - - - - - - - - - - - 226 | // Time Info support 227 | //- - - - - - - - - - - - - - - - - - - - - - - - - 228 | 229 | typedef struct ASIOTimeCode 230 | { 231 | double speed; // speed relation (fraction of nominal speed) 232 | // optional; set to 0. or 1. if not supported 233 | ASIOSamples timeCodeSamples; // time in samples 234 | ULONG flags; // some information flags (see below) 235 | char future[64]; 236 | } ASIOTimeCode; 237 | 238 | typedef enum ASIOTimeCodeFlags 239 | { 240 | kTcValid = 1, 241 | kTcRunning = 1 << 1, 242 | kTcReverse = 1 << 2, 243 | kTcOnspeed = 1 << 3, 244 | kTcStill = 1 << 4, 245 | 246 | kTcSpeedValid = 1 << 8 247 | } ASIOTimeCodeFlags; 248 | 249 | typedef struct AsioTimeInfo 250 | { 251 | double speed; // absolute speed (1. = nominal) 252 | ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds 253 | // on mac, must be derived from Microseconds() (not UpTime()!) 254 | // on windows, must be derived from timeGetTime() 255 | ASIOSamples samplePosition; 256 | ASIOSampleRate sampleRate; // current rate 257 | ULONG flags; // (see below) 258 | char reserved[12]; 259 | } AsioTimeInfo; 260 | 261 | typedef enum AsioTimeInfoFlags 262 | { 263 | kSystemTimeValid = 1, // must always be valid 264 | kSamplePositionValid = 1 << 1, // must always be valid 265 | kSampleRateValid = 1 << 2, 266 | kSpeedValid = 1 << 3, 267 | 268 | kSampleRateChanged = 1 << 4, 269 | kClockSourceChanged = 1 << 5 270 | } AsioTimeInfoFlags; 271 | 272 | typedef struct ASIOTime // both input/output 273 | { 274 | LONG reserved[4]; // must be 0 275 | struct AsioTimeInfo timeInfo; // required 276 | struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) 277 | } ASIOTime; 278 | 279 | /* 280 | 281 | using time info: 282 | it is recommended to use the new method with time info even if the asio 283 | device does not support timecode; continuous calls to ASIOGetSamplePosition 284 | and ASIOGetSampleRate are avoided, and there is a more defined relationship 285 | between callback time and the time info. 286 | 287 | see the example below. 288 | to initiate time info mode, after you have received the callbacks pointer in 289 | ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo 290 | as the argument. if this returns 1, host has accepted time info mode. 291 | now host expects the new callback bufferSwitchTimeInfo to be used instead 292 | of the old bufferSwitch method. the ASIOTime structure is assumed to be valid 293 | and accessible until the callback returns. 294 | 295 | using time code: 296 | if the device supports reading time code, it will call host's asioMessage callback 297 | with kAsioSupportsTimeCode as the selector. it may then fill the according 298 | fields and set the kTcValid flag. 299 | host will call the future method with the kAsioEnableTimeCodeRead selector when 300 | it wants to enable or disable tc reading by the device. you should also support 301 | the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). 302 | 303 | note: 304 | the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. 305 | as a matter of convention, the relationship between the sample 306 | position counter and the time code at buffer switch time is 307 | (ignoring offset between tc and sample pos when tc is running): 308 | 309 | on input: sample 0 -> input buffer sample 0 -> time code 0 310 | on output: sample 0 -> output buffer sample 0 -> time code 0 311 | 312 | this means that for 'real' calculations, one has to take into account 313 | the according latencies. 314 | 315 | example: 316 | 317 | ASIOTime asioTime; 318 | 319 | in createBuffers() 320 | { 321 | memset(&asioTime, 0, sizeof(ASIOTime)); 322 | AsioTimeInfo* ti = &asioTime.timeInfo; 323 | ti->sampleRate = theSampleRate; 324 | ASIOTimeCode* tc = &asioTime.timeCode; 325 | tc->speed = 1.; 326 | timeInfoMode = false; 327 | canTimeCode = false; 328 | if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) 329 | { 330 | timeInfoMode = true; 331 | #if kCanTimeCode 332 | if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) 333 | canTimeCode = true; 334 | #endif 335 | } 336 | } 337 | 338 | void switchBuffers(LONG doubleBufferIndex, bool processNow) 339 | { 340 | if(timeInfoMode) 341 | { 342 | AsioTimeInfo* ti = &asioTime.timeInfo; 343 | ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; 344 | ti->systemTime = theNanoSeconds; 345 | ti->samplePosition = theSamplePosition; 346 | if(ti->sampleRate != theSampleRate) 347 | ti->flags |= kSampleRateChanged; 348 | ti->sampleRate = theSampleRate; 349 | 350 | #if kCanTimeCode 351 | if(canTimeCode && timeCodeEnabled) 352 | { 353 | ASIOTimeCode* tc = &asioTime.timeCode; 354 | tc->timeCodeSamples = tcSamples; // tc in samples 355 | tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... 356 | } 357 | ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); 358 | #else 359 | callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); 360 | #endif 361 | } 362 | else 363 | callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); 364 | } 365 | 366 | ASIOError ASIOFuture(LONG selector, void *params) 367 | { 368 | switch(selector) 369 | { 370 | case kAsioEnableTimeCodeRead: 371 | timeCodeEnabled = true; 372 | return ASE_SUCCESS; 373 | case kAsioDisableTimeCodeRead: 374 | timeCodeEnabled = false; 375 | return ASE_SUCCESS; 376 | case kAsioCanTimeInfo: 377 | return ASE_SUCCESS; 378 | #if kCanTimeCode 379 | case kAsioCanTimeCode: 380 | return ASE_SUCCESS; 381 | #endif 382 | } 383 | return ASE_NotPresent; 384 | }; 385 | 386 | */ 387 | 388 | //- - - - - - - - - - - - - - - - - - - - - - - - - 389 | // application's audio stream handler callbacks 390 | //- - - - - - - - - - - - - - - - - - - - - - - - - 391 | 392 | typedef struct ASIOCallbacks 393 | { 394 | void (CALLBACK *bufferSwitch) (LONG doubleBufferIndex, ASIOBool directProcess); 395 | // bufferSwitch indicates that both input and output are to be processed. 396 | // the current buffer half index (0 for A, 1 for B) determines 397 | // - the output buffer that the host should start to fill. the other buffer 398 | // will be passed to output hardware regardless of whether it got filled 399 | // in time or not. 400 | // - the input buffer that is now filled with incoming data. Note that 401 | // because of the synchronicity of i/o, the input always has at 402 | // least one buffer latency in relation to the output. 403 | // directProcess suggests to the host whether it should immedeately 404 | // start processing (directProcess == ASIOTrue), or whether its process 405 | // should be deferred because the call comes from a very low level 406 | // (for instance, a high level priority interrupt), and direct processing 407 | // would cause timing instabilities for the rest of the system. If in doubt, 408 | // directProcess should be set to ASIOFalse. 409 | // Note: bufferSwitch may be called at interrupt time for highest efficiency. 410 | 411 | void (CALLBACK *sampleRateDidChange) (ASIOSampleRate sRate); 412 | // gets called when the AudioStreamIO detects a sample rate change 413 | // If sample rate is unknown, 0 is passed (for instance, clock loss 414 | // when externally synchronized). 415 | 416 | LONG (CALLBACK *asioMessage) (LONG selector, LONG value, void* message, double* opt); 417 | // generic callback for various purposes, see selectors below. 418 | // note this is only present if the asio version is 2 or higher 419 | 420 | ASIOTime* (CALLBACK *bufferSwitchTimeInfo) (ASIOTime* params, LONG doubleBufferIndex, ASIOBool directProcess); 421 | // new callback with time info. makes ASIOGetSamplePosition() and various 422 | // calls to ASIOGetSampleRate obsolete, 423 | // and allows for timecode sync etc. to be preferred; will be used if 424 | // the driver calls asioMessage with selector kAsioSupportsTimeInfo. 425 | } ASIOCallbacks; 426 | 427 | // asioMessage selectors 428 | enum 429 | { 430 | kAsioSelectorSupported = 1, // selector in , returns 1L if supported, 431 | // 0 otherwise 432 | kAsioEngineVersion, // returns engine (host) asio implementation version, 433 | // 2 or higher 434 | kAsioResetRequest, // request driver reset. if accepted, this 435 | // will close the driver (ASIO_Exit() ) and 436 | // re-open it again (ASIO_Init() etc). some 437 | // drivers need to reconfigure for instance 438 | // when the sample rate changes, or some basic 439 | // changes have been made in ASIO_ControlPanel(). 440 | // returns 1L; note the request is merely passed 441 | // to the application, there is no way to determine 442 | // if it gets accepted at this time (but it usually 443 | // will be). 444 | kAsioBufferSizeChange, // not yet supported, will currently always return 0L. 445 | // for now, use kAsioResetRequest instead. 446 | // once implemented, the new buffer size is expected 447 | // in , and on success returns 1L 448 | kAsioResyncRequest, // the driver went out of sync, such that 449 | // the timestamp is no LONGer valid. this 450 | // is a request to re-start the engine and 451 | // slave devices (sequencer). returns 1 for ok, 452 | // 0 if not supported. 453 | kAsioLatenciesChanged, // the drivers latencies have changed. The engine 454 | // will refetch the latencies. 455 | kAsioSupportsTimeInfo, // if host returns true here, it will expect the 456 | // callback bufferSwitchTimeInfo to be called instead 457 | // of bufferSwitch 458 | kAsioSupportsTimeCode, // 459 | kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands 460 | kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this 461 | kAsioSupportsInputGain, // unused and undefined 462 | kAsioSupportsInputMeter, // unused and undefined 463 | kAsioSupportsOutputGain, // unused and undefined 464 | kAsioSupportsOutputMeter, // unused and undefined 465 | kAsioOverload, // driver detected an overload 466 | 467 | kAsioNumMessageSelectors 468 | }; 469 | 470 | //--------------------------------------------------------------------------------------------------- 471 | //--------------------------------------------------------------------------------------------------- 472 | 473 | //- - - - - - - - - - - - - - - - - - - - - - - - - 474 | // (De-)Construction 475 | //- - - - - - - - - - - - - - - - - - - - - - - - - 476 | 477 | typedef struct ASIODriverInfo 478 | { 479 | LONG asioVersion; // currently, 2 480 | LONG driverVersion; // driver specific 481 | char name[32]; 482 | char errorMessage[124]; 483 | void *sysRef; // on input: system reference 484 | // (Windows: application main window handle, Mac & SGI: 0) 485 | } ASIODriverInfo; 486 | 487 | ASIOError ASIOInit(ASIODriverInfo *info); 488 | /* Purpose: 489 | Initialize the AudioStreamIO. 490 | Parameter: 491 | info: pointer to an ASIODriver structure: 492 | - asioVersion: 493 | - on input, the host version. *** Note *** this is 0 for earlier asio 494 | implementations, and the asioMessage callback is implemeted 495 | only if asioVersion is 2 or greater. sorry but due to a design fault 496 | the driver doesn't have access to the host version in ASIOInit :-( 497 | added selector for host (engine) version in the asioMessage callback 498 | so we're ok from now on. 499 | - on return, asio implementation version. 500 | older versions are 1 501 | if you support this version (namely, ASIO_outputReady() ) 502 | this should be 2 or higher. also see the note in 503 | ASIO_getTimeStamp() ! 504 | - version: on return, the driver version (format is driver specific) 505 | - name: on return, a null-terminated string containing the driver's name 506 | - error message: on return, should contain a user message describing 507 | the type of error that occured during ASIOInit(), if any. 508 | - sysRef: platform specific 509 | Returns: 510 | If neither input nor output is present ASE_NotPresent 511 | will be returned. 512 | ASE_NoMemory, ASE_HWMalfunction are other possible error conditions 513 | */ 514 | 515 | ASIOError ASIOExit(void); 516 | /* Purpose: 517 | Terminates the AudioStreamIO. 518 | Parameter: 519 | None. 520 | Returns: 521 | If neither input nor output is present ASE_NotPresent 522 | will be returned. 523 | Notes: this implies ASIOStop() and ASIODisposeBuffers(), 524 | meaning that no host callbacks must be accessed after ASIOExit(). 525 | */ 526 | 527 | //- - - - - - - - - - - - - - - - - - - - - - - - - 528 | // Start/Stop 529 | //- - - - - - - - - - - - - - - - - - - - - - - - - 530 | 531 | ASIOError ASIOStart(void); 532 | /* Purpose: 533 | Start input and output processing synchronously. 534 | This will 535 | - reset the sample counter to zero 536 | - start the hardware (both input and output) 537 | The first call to the hosts' bufferSwitch(index == 0) then tells 538 | the host to read from input buffer A (index 0), and start 539 | processing to output buffer A while output buffer B (which 540 | has been filled by the host prior to calling ASIOStart()) 541 | is possibly sounding (see also ASIOGetLatencies()) 542 | Parameter: 543 | None. 544 | Returns: 545 | If neither input nor output is present, ASE_NotPresent 546 | will be returned. 547 | If the hardware fails to start, ASE_HWMalfunction will be returned. 548 | Notes: 549 | There is no restriction on the time that ASIOStart() takes 550 | to perform (that is, it is not considered a realtime trigger). 551 | */ 552 | 553 | ASIOError ASIOStop(void); 554 | /* Purpose: 555 | Stops input and output processing altogether. 556 | Parameter: 557 | None. 558 | Returns: 559 | If neither input nor output is present ASE_NotPresent 560 | will be returned. 561 | Notes: 562 | On return from ASIOStop(), the driver must in no 563 | case call the hosts' bufferSwitch() routine. 564 | */ 565 | 566 | //- - - - - - - - - - - - - - - - - - - - - - - - - 567 | // Inquiry methods and sample rate 568 | //- - - - - - - - - - - - - - - - - - - - - - - - - 569 | 570 | ASIOError ASIOGetChannels(LONG *numInputChannels, LONG *numOutputChannels); 571 | /* Purpose: 572 | Returns number of individual input/output channels. 573 | Parameter: 574 | numInputChannels will hold the number of available input channels 575 | numOutputChannels will hold the number of available output channels 576 | Returns: 577 | If no input/output is present ASE_NotPresent will be returned. 578 | If only inputs, or only outputs are available, the according 579 | other parameter will be zero, and ASE_OK is returned. 580 | */ 581 | 582 | ASIOError ASIOGetLatencies(LONG *inputLatency, LONG *outputLatency); 583 | /* Purpose: 584 | Returns the input and output latencies. This includes 585 | device specific delays, like FIFOs etc. 586 | Parameter: 587 | inputLatency will hold the 'age' of the first sample frame 588 | in the input buffer when the hosts reads it in bufferSwitch() 589 | (this is theoretical, meaning it does not include the overhead 590 | and delay between the actual physical switch, and the time 591 | when bufferSitch() enters). 592 | This will usually be the size of one block in sample frames, plus 593 | device specific latencies. 594 | 595 | outputLatency will specify the time between the buffer switch, 596 | and the time when the next play buffer will start to sound. 597 | The next play buffer is defined as the one the host starts 598 | processing after (or at) bufferSwitch(), indicated by the 599 | index parameter (0 for buffer A, 1 for buffer B). 600 | It will usually be either one block, if the host writes directly 601 | to a dma buffer, or two or more blocks if the buffer is 'latched' by 602 | the driver. As an example, on ASIOStart(), the host will have filled 603 | the play buffer at index 1 already; when it gets the callback (with 604 | the parameter index == 0), this tells it to read from the input 605 | buffer 0, and start to fill the play buffer 0 (assuming that now 606 | play buffer 1 is already sounding). In this case, the output 607 | latency is one block. If the driver decides to copy buffer 1 608 | at that time, and pass it to the hardware at the next slot (which 609 | is most commonly done, but should be avoided), the output latency 610 | becomes two blocks instead, resulting in a total i/o latency of at least 611 | 3 blocks. As memory access is the main bottleneck in native dsp processing, 612 | and to acheive less latency, it is highly recommended to try to avoid 613 | copying (this is also why the driver is the owner of the buffers). To 614 | summarize, the minimum i/o latency can be acheived if the input buffer 615 | is processed by the host into the output buffer which will physically 616 | start to sound on the next time slice. Also note that the host expects 617 | the bufferSwitch() callback to be accessed for each time slice in order 618 | to retain sync, possibly recursively; if it fails to process a block in 619 | time, it will suspend its operation for some time in order to recover. 620 | Returns: 621 | If no input/output is present ASE_NotPresent will be returned. 622 | */ 623 | 624 | ASIOError ASIOGetBufferSize(LONG *minSize, LONG *maxSize, LONG *preferredSize, LONG *granularity); 625 | /* Purpose: 626 | Returns min, max, and preferred buffer sizes for input/output 627 | Parameter: 628 | minSize will hold the minimum buffer size 629 | maxSize will hold the maxium possible buffer size 630 | preferredSize will hold the preferred buffer size (a size which 631 | best fits performance and hardware requirements) 632 | granularity will hold the granularity at which buffer sizes 633 | may differ. Usually, the buffer size will be a power of 2; 634 | in this case, granularity will hold -1 on return, signalling 635 | possible buffer sizes starting from minSize, increased in 636 | powers of 2 up to maxSize. 637 | Returns: 638 | If no input/output is present ASE_NotPresent will be returned. 639 | Notes: 640 | When minimum and maximum buffer size are equal, 641 | the preferred buffer size has to be the same value as well; granularity 642 | should be 0 in this case. 643 | */ 644 | 645 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); 646 | /* Purpose: 647 | Inquires the hardware for the available sample rates. 648 | Parameter: 649 | sampleRate is the rate in question. 650 | Returns: 651 | If the inquired sample rate is not supported, ASE_NoClock will be returned. 652 | If no input/output is present ASE_NotPresent will be returned. 653 | */ 654 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); 655 | /* Purpose: 656 | Get the current sample Rate. 657 | Parameter: 658 | currentRate will hold the current sample rate on return. 659 | Returns: 660 | If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. 661 | If no input/output is present ASE_NotPresent will be returned. 662 | Notes: 663 | */ 664 | 665 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); 666 | /* Purpose: 667 | Set the hardware to the requested sample Rate. If sampleRate == 0, 668 | enable external sync. 669 | Parameter: 670 | sampleRate: on input, the requested rate 671 | Returns: 672 | If sampleRate is unknown ASE_NoClock will be returned. 673 | If the current clock is external, and sampleRate is != 0, 674 | ASE_InvalidMode will be returned 675 | If no input/output is present ASE_NotPresent will be returned. 676 | Notes: 677 | */ 678 | 679 | typedef struct ASIOClockSource 680 | { 681 | LONG index; // as used for ASIOSetClockSource() 682 | LONG associatedChannel; // for instance, S/PDIF or AES/EBU 683 | LONG associatedGroup; // see channel groups (ASIOGetChannelInfo()) 684 | ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source 685 | char name[32]; // for user selection 686 | } ASIOClockSource; 687 | 688 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, LONG *numSources); 689 | /* Purpose: 690 | Get the available external audio clock sources 691 | Parameter: 692 | clocks points to an array of ASIOClockSource structures: 693 | - index: this is used to identify the clock source 694 | when ASIOSetClockSource() is accessed, should be 695 | an index counting from zero 696 | - associatedInputChannel: the first channel of an associated 697 | input group, if any. 698 | - associatedGroup: the group index of that channel. 699 | groups of channels are defined to seperate for 700 | instance analog, S/PDIF, AES/EBU, ADAT connectors etc, 701 | when present simultaniously. Note that associated channel 702 | is enumerated according to numInputs/numOutputs, means it 703 | is independant from a group (see also ASIOGetChannelInfo()) 704 | inputs are associated to a clock if the physical connection 705 | transfers both data and clock (like S/PDIF, AES/EBU, or 706 | ADAT inputs). if there is no input channel associated with 707 | the clock source (like Word Clock, or internal oscillator), both 708 | associatedChannel and associatedGroup should be set to -1. 709 | - isCurrentSource: on exit, ASIOTrue if this is the current clock 710 | source, ASIOFalse else 711 | - name: a null-terminated string for user selection of the available sources. 712 | numSources: 713 | on input: the number of allocated array members 714 | on output: the number of available clock sources, at least 715 | 1 (internal clock generator). 716 | Returns: 717 | If no input/output is present ASE_NotPresent will be returned. 718 | Notes: 719 | */ 720 | 721 | ASIOError ASIOSetClockSource(LONG index); 722 | /* Purpose: 723 | Set the audio clock source 724 | Parameter: 725 | index as obtained from an inquiry to ASIOGetClockSources() 726 | Returns: 727 | If no input/output is present ASE_NotPresent will be returned. 728 | If the clock can not be selected because an input channel which 729 | carries the current clock source is active, ASE_InvalidMode 730 | *may* be returned (this depends on the properties of the driver 731 | and/or hardware). 732 | Notes: 733 | Should *not* return ASE_NoClock if there is no clock signal present 734 | at the selected source; this will be inquired via ASIOGetSampleRate(). 735 | It should call the host callback procedure sampleRateHasChanged(), 736 | if the switch causes a sample rate change, or if no external clock 737 | is present at the selected source. 738 | */ 739 | 740 | ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); 741 | /* Purpose: 742 | Inquires the sample position/time stamp pair. 743 | Parameter: 744 | sPos will hold the sample position on return. The sample 745 | position is reset to zero when ASIOStart() gets called. 746 | tStamp will hold the system time when the sample position 747 | was latched. 748 | Returns: 749 | If no input/output is present, ASE_NotPresent will be returned. 750 | If there is no clock, ASE_SPNotAdvancing will be returned. 751 | Notes: 752 | 753 | in order to be able to synchronise properly, 754 | the sample position / time stamp pair must refer to the current block, 755 | that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() 756 | callback and expect the time for the current block. thus, when requested 757 | in the very first bufferSwitch after ASIO_Start(), the sample position 758 | should be zero, and the time stamp should refer to the very time where 759 | the stream was started. it also means that the sample position must be 760 | block aligned. the driver must ensure proper interpolation if the system 761 | time can not be determined for the block position. the driver is responsible 762 | for precise time stamps as it usually has most direct access to lower 763 | level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() 764 | are essential for precise media synchronization! 765 | */ 766 | 767 | typedef struct ASIOChannelInfo 768 | { 769 | LONG channel; // on input, channel index 770 | ASIOBool isInput; // on input 771 | ASIOBool isActive; // on exit 772 | LONG channelGroup; // dto 773 | ASIOSampleType type; // dto 774 | char name[32]; // dto 775 | } ASIOChannelInfo; 776 | 777 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); 778 | /* Purpose: 779 | retreive information about the nature of a channel 780 | Parameter: 781 | info: pointer to a ASIOChannelInfo structure with 782 | - channel: on input, the channel index of the channel in question. 783 | - isInput: on input, ASIOTrue if info for an input channel is 784 | requested, else output 785 | - channelGroup: on return, the channel group that the channel 786 | beLONGs to. For drivers which support different types of 787 | channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, 788 | there should be a reasonable grouping of these types. Groups 789 | are always independant form a channel index, that is, a channel 790 | index always counts from 0 to numInputs/numOutputs regardless 791 | of the group it may beLONG to. 792 | There will always be at least one group (group 0). Please 793 | also note that by default, the host may decide to activate 794 | channels 0 and 1; thus, these should beLONG to the most 795 | useful type (analog i/o, if present). 796 | - type: on return, contains the sample type of the channel 797 | - isActive: on return, ASIOTrue if channel is active as it was 798 | installed by ASIOCreateBuffers(), ASIOFalse else 799 | - name: describing the type of channel in question. Used to allow 800 | for user selection, and enabling of specific channels. examples: 801 | "Analog In", "SPDIF Out" etc 802 | Returns: 803 | If no input/output is present ASE_NotPresent will be returned. 804 | Notes: 805 | If possible, the string should be organised such that the first 806 | characters are most significantly describing the nature of the 807 | port, to allow for identification even if the view showing the 808 | port name is too small to display more than 8 characters, for 809 | instance. 810 | */ 811 | 812 | //- - - - - - - - - - - - - - - - - - - - - - - - - 813 | // Buffer preparation 814 | //- - - - - - - - - - - - - - - - - - - - - - - - - 815 | 816 | typedef struct ASIOBufferInfo 817 | { 818 | ASIOBool isInput; // on input: ASIOTrue: input, else output 819 | LONG channelNum; // on input: channel index 820 | void *buffers[2]; // on output: double buffer addresses 821 | } ASIOBufferInfo; 822 | 823 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, LONG numChannels, 824 | LONG bufferSize, ASIOCallbacks *callbacks); 825 | 826 | /* Purpose: 827 | Allocates input/output buffers for all input and output channels to be activated. 828 | Parameter: 829 | bufferInfos is a pointer to an array of ASIOBufferInfo structures: 830 | - isInput: on input, ASIOTrue if the buffer is to be allocated 831 | for an input, output buffer else 832 | - channelNum: on input, the index of the channel in question 833 | (counting from 0) 834 | - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. 835 | the size of the buffer(s) of course depend on both the ASIOSampleType 836 | as obtained from ASIOGetChannelInfo(), and bufferSize 837 | numChannels is the sum of all input and output channels to be created; 838 | thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo 839 | structures. 840 | bufferSize selects one of the possible buffer sizes as obtained from 841 | ASIOGetBufferSizes(). 842 | callbacks is a pointer to an ASIOCallbacks structure. 843 | Returns: 844 | If not enough memory is available ASE_NoMemory will be returned. 845 | If no input/output is present ASE_NotPresent will be returned. 846 | If bufferSize is not supported, or one or more of the bufferInfos elements 847 | contain invalid settings, ASE_InvalidMode will be returned. 848 | Notes: 849 | If individual channel selection is not possible but requested, 850 | the driver has to handle this. namely, bufferSwitch() will only 851 | have filled buffers of enabled outputs. If possible, processing 852 | and buss activities overhead should be avoided for channels which 853 | were not enabled here. 854 | */ 855 | 856 | ASIOError ASIODisposeBuffers(void); 857 | /* Purpose: 858 | Releases all buffers for the device. 859 | Parameter: 860 | None. 861 | Returns: 862 | If no buffer were ever prepared, ASE_InvalidMode will be returned. 863 | If no input/output is present ASE_NotPresent will be returned. 864 | Notes: 865 | This implies ASIOStop(). 866 | */ 867 | 868 | ASIOError ASIOControlPanel(void); 869 | /* Purpose: 870 | request the driver to start a control panel component 871 | for device specific user settings. This will not be 872 | accessed on some platforms (where the component is accessed 873 | instead). 874 | Parameter: 875 | None. 876 | Returns: 877 | If no panel is available ASE_NotPresent will be returned. 878 | Actually, the return code is ignored. 879 | Notes: 880 | if the user applied settings which require a re-configuration 881 | of parts or all of the enigine and/or driver (such as a change of 882 | the block size), the asioMessage callback can be used (see 883 | ASIO_Callbacks). 884 | */ 885 | 886 | ASIOError ASIOFuture(LONG selector, void *params); 887 | /* Purpose: 888 | various 889 | Parameter: 890 | selector: operation Code as to be defined. zero is reserved for 891 | testing purposes. 892 | params: depends on the selector; usually pointer to a structure 893 | for passing and retreiving any type and amount of parameters. 894 | Returns: 895 | the return value is also selector dependant. if the selector 896 | is unknown, ASE_InvalidParameter should be returned to prevent 897 | further calls with this selector. on success, ASE_SUCCESS 898 | must be returned (note: ASE_OK is *not* sufficient!) 899 | Notes: 900 | see selectors defined below. 901 | */ 902 | 903 | enum 904 | { 905 | kAsioEnableTimeCodeRead = 1, // no arguments 906 | kAsioDisableTimeCodeRead, // no arguments 907 | kAsioSetInputMonitor, // ASIOInputMonitor* in params 908 | kAsioTransport, // ASIOTransportParameters* in params 909 | kAsioSetInputGain, // ASIOChannelControls* in params, apply gain 910 | kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter 911 | kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain 912 | kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter 913 | kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors 914 | kAsioCanTimeInfo, 915 | kAsioCanTimeCode, 916 | kAsioCanTransport, 917 | kAsioCanInputGain, 918 | kAsioCanInputMeter, 919 | kAsioCanOutputGain, 920 | kAsioCanOutputMeter, 921 | kAsioOptionalOne, 922 | 923 | // DSD support 924 | // The following extensions are required to allow switching 925 | // and control of the DSD subsystem. 926 | kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */ 927 | kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */ 928 | kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */ 929 | 930 | // Extension for drop out detection 931 | kAsioCanReportOverload = 0x24042012, /* return ASE_SUCCESS if driver can detect and report overloads */ 932 | 933 | kAsioGetInternalBufferSamples = 0x25042012 /* ASIOInternalBufferInfo * in params. Deliver size of driver internal buffering, return ASE_SUCCESS if supported */ 934 | }; 935 | 936 | typedef struct ASIOInputMonitor 937 | { 938 | LONG input; // this input was set to monitor (or off), -1: all 939 | LONG output; // suggested output for monitoring the input (if so) 940 | LONG gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) 941 | ASIOBool state; // ASIOTrue => on, ASIOFalse => off 942 | LONG pan; // suggested pan, 0 => all left, 0x7fffffff => right 943 | } ASIOInputMonitor; 944 | 945 | typedef struct ASIOChannelControls 946 | { 947 | LONG channel; // on input, channel index 948 | ASIOBool isInput; // on input 949 | LONG gain; // on input, ranges 0 thru 0x7fffffff 950 | LONG meter; // on return, ranges 0 thru 0x7fffffff 951 | char future[32]; 952 | } ASIOChannelControls; 953 | 954 | typedef struct ASIOTransportParameters 955 | { 956 | LONG command; // see enum below 957 | ASIOSamples samplePosition; 958 | LONG track; 959 | LONG trackSwitches[16]; // 512 tracks on/off 960 | char future[64]; 961 | } ASIOTransportParameters; 962 | 963 | enum 964 | { 965 | kTransStart = 1, 966 | kTransStop, 967 | kTransLocate, // to samplePosition 968 | kTransPunchIn, 969 | kTransPunchOut, 970 | kTransArmOn, // track 971 | kTransArmOff, // track 972 | kTransMonitorOn, // track 973 | kTransMonitorOff, // track 974 | kTransArm, // trackSwitches 975 | kTransMonitor // trackSwitches 976 | }; 977 | 978 | /* 979 | // DSD support 980 | // Some notes on how to use ASIOIoFormatType. 981 | // 982 | // The caller will fill the format with the request types. 983 | // If the board can do the request then it will leave the 984 | // values unchanged. If the board does not support the 985 | // request then it will change that entry to Invalid (-1) 986 | // 987 | // So to request DSD then 988 | // 989 | // ASIOIoFormat NeedThis={kASIODSDFormat}; 990 | // 991 | // if(ASE_SUCCESS != ASIOFuture(kAsioSetIoFormat,&NeedThis) ){ 992 | // // If the board did not accept one of the parameters then the 993 | // // whole call will fail and the failing parameter will 994 | // // have had its value changes to -1. 995 | // } 996 | // 997 | // Note: Switching between the formats need to be done before the "prepared" 998 | // state (see ASIO 2 documentation) is entered. 999 | */ 1000 | typedef LONG ASIOIoFormatType; 1001 | enum ASIOIoFormatType_e 1002 | { 1003 | kASIOFormatInvalid = -1, 1004 | kASIOPCMFormat = 0, 1005 | kASIODSDFormat = 1, 1006 | }; 1007 | 1008 | typedef struct ASIOIoFormat_s 1009 | { 1010 | ASIOIoFormatType FormatType; 1011 | char future[512-sizeof(ASIOIoFormatType)]; 1012 | } ASIOIoFormat; 1013 | 1014 | // Extension for drop detection 1015 | // Note: Refers to buffering that goes beyond the double buffer e.g. used by USB driver designs 1016 | typedef struct ASIOInternalBufferInfo 1017 | { 1018 | LONG inputSamples; // size of driver's internal input buffering which is included in getLatencies 1019 | LONG outputSamples; // size of driver's internal output buffering which is included in getLatencies 1020 | } ASIOInternalBufferInfo; 1021 | 1022 | 1023 | ASIOError ASIOOutputReady(void); 1024 | /* Purpose: 1025 | this tells the driver that the host has completed processing 1026 | the output buffers. if the data format required by the hardware 1027 | differs from the supported asio formats, but the hardware 1028 | buffers are DMA buffers, the driver will have to convert 1029 | the audio stream data; as the bufferSwitch callback is 1030 | usually issued at dma block switch time, the driver will 1031 | have to convert the *previous* host buffer, which increases 1032 | the output latency by one block. 1033 | when the host finds out that ASIOOutputReady() returns 1034 | true, it will issue this call whenever it completed 1035 | output processing. then the driver can convert the 1036 | host data directly to the dma buffer to be played next, 1037 | reducing output latency by one block. 1038 | another way to look at it is, that the buffer switch is called 1039 | in order to pass the *input* stream to the host, so that it can 1040 | process the input into the output, and the output stream is passed 1041 | to the driver when the host has completed its process. 1042 | Parameter: 1043 | None 1044 | Returns: 1045 | only if the above mentioned scenario is given, and a reduction 1046 | of output latency can be acheived by this mechanism, should 1047 | ASE_OK be returned. otherwise (and usually), ASE_NotPresent 1048 | should be returned in order to prevent further calls to this 1049 | function. note that the host may want to determine if it is 1050 | to use this when the system is not yet fully initialized, so 1051 | ASE_OK should always be returned if the mechanism makes sense. 1052 | Notes: 1053 | please remeber to adjust ASIOGetLatencies() according to 1054 | whether ASIOOutputReady() was ever called or not, if your 1055 | driver supports this scenario. 1056 | also note that the engine may fail to call ASIO_OutputReady() 1057 | in time in overload cases. as already mentioned, bufferSwitch 1058 | should be called for every block regardless of whether a block 1059 | could be processed in time. 1060 | */ 1061 | 1062 | // restore old alignment 1063 | #if defined(_MSC_VER) && !defined(__MWERKS__) 1064 | #pragma pack(pop) 1065 | #elif PRAGMA_ALIGN_SUPPORTED 1066 | #pragma options align = reset 1067 | #endif 1068 | 1069 | #endif 1070 | 1071 | -------------------------------------------------------------------------------- /classid.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 15 | */ 16 | 17 | #include "classid.h" 18 | 19 | 20 | /****************************************************************************** 21 | * Define GUID for WineASIO class 22 | * 23 | * {48D0C522-BFCC-45cc-8B84-17F25F33E6E8} 24 | */ 25 | DEFINE_GUID (CLSID_WineASIO, 0x48d0c522, 26 | 0xbfcc, 27 | 0x45cc, 28 | 0x8b, 0x84, 0x17, 0xf2, 0x5f, 0x33, 0xe6, 0xe8); 29 | -------------------------------------------------------------------------------- /classid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 15 | */ 16 | 17 | #ifndef __CLSID_H__ 18 | #define __CLSID_H__ 19 | 20 | #include 21 | #include 22 | 23 | 24 | /****************************************************************************** 25 | * External declarations 26 | */ 27 | extern const GUID CLSID_WineASIO DECLSPEC_HIDDEN; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef __WINEASIO_CONFIG_H__ 2 | #define __WINEASIO_CONFIG_H__ 3 | #endif 4 | -------------------------------------------------------------------------------- /jackasio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 15 | */ 16 | 17 | #ifndef __JACKASIO_H__ 18 | #define __JACKASIO_H__ 19 | 20 | #include 21 | 22 | 23 | /****************************************************************************** 24 | * ASIO drivers (breaking the COM specification) use the Microsoft variety of 25 | * thiscall calling convention which gcc is unable to produce. These macros 26 | * add an extra layer to fixup the registers. Borrowed from config.h and the 27 | * wine source code. 28 | */ 29 | 30 | /* From config.h */ 31 | #define __ASM_DEFINE_FUNC(name,suffix,code) asm(".text\n\t.align 4\n\t.globl " #name suffix "\n\t.type " #name suffix ",@function\n" #name suffix ":\n\t.cfi_startproc\n\t" code "\n\t.cfi_endproc\n\t.previous"); 32 | #define __ASM_GLOBAL_FUNC(name,code) __ASM_DEFINE_FUNC(name,"",code) 33 | #define __ASM_NAME(name) name 34 | #define __ASM_STDCALL(args) "" 35 | 36 | /* From wine source */ 37 | #ifdef __i386__ /* thiscall functions are i386-specific */ 38 | 39 | #define THISCALL(func) __thiscall_ ## func 40 | #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func) 41 | #define __thiscall __stdcall 42 | #define DEFINE_THISCALL_WRAPPER(func,args) \ 43 | extern void THISCALL(func)(void); \ 44 | __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ 45 | "popl %eax\n\t" \ 46 | "pushl %ecx\n\t" \ 47 | "pushl %eax\n\t" \ 48 | "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) ) 49 | #else /* __i386__ */ 50 | 51 | #define THISCALL(func) func 52 | #define THISCALL_NAME(func) __ASM_NAME(#func) 53 | #define __thiscall __cdecl 54 | #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */ 55 | 56 | #endif /* __i386__ */ 57 | 58 | 59 | /****************************************************************************** 60 | * MACRO: ENSURE_DRIVER_STATE () 61 | * 62 | * TODO: Do preprocessor magic to eliminate the need to pass both the enum 63 | * and the enum's string representation to the macro. 64 | */ 65 | #define ENSURE_DRIVER_STATE(state, str) \ 66 | do { \ 67 | if (This->wineasio_drv_state != state) \ 68 | { \ 69 | ERR ("failed; current driver state != %s\n", str); \ 70 | return ASE_NotPresent; \ 71 | } \ 72 | } while (0); 73 | 74 | 75 | /****************************************************************************** 76 | * MACRO: SET_NEW_STATE_TRACE () 77 | * 78 | * TODO: Some more magic required here so we don't have to pass a textual 79 | * representation of the driver state. 80 | */ 81 | #define SET_NEW_STATE_TRACE(state, state_str) \ 82 | do { \ 83 | This->wineasio_drv_state = state; \ 84 | TRACE ("new driver state is: `%s'\n", state_str); \ 85 | } while (0); 86 | 87 | 88 | /****************************************************************************** 89 | * MACRO: FUNC_COMPLETION_TRUE_TRACE () 90 | * 91 | * NOTE: This macro will only work with result codes of 92 | * type BOOL or ASIOBool, and assumes SUCCESS == TRUE. 93 | */ 94 | #define FUNC_COMPLETION_TRUE_TRACE(result) \ 95 | do { \ 96 | TRACE ("%s (%d)\n", result \ 97 | ? "completed successfully" : "failed", result); \ 98 | } while (0); 99 | 100 | 101 | /****************************************************************************** 102 | * MACRO: FUNC_COMPLETION_ASEOK_TRACE () 103 | * 104 | * NOTE: This macro will only work with result codes of 105 | * type ASIOBool, and assumes SUCCESS == ASE_OK. 106 | */ 107 | #define FUNC_COMPLETION_ASEOK_TRACE(result) \ 108 | do { \ 109 | TRACE ("%s (%d)\n", result == ASE_OK \ 110 | ? "completed successfully" : "failed", result); \ 111 | } while (0); 112 | 113 | 114 | /****************************************************************************** 115 | * Constants 116 | */ 117 | 118 | #define BUF_A 0 /* index for buffer A */ 119 | #define BUF_B 1 /* index for buffer B */ 120 | #define BUF_A_B 2 /* total of 2 buffer halves, A and B */ 121 | 122 | #define WINEASIO_IN 0 123 | #define WINEASIO_OUT 1 124 | #define WINEASIO_IN_OUT 2 125 | 126 | #define KB 1024 127 | 128 | #define NO_QUERY_RESULT (-1) // FIXME: what is this for? 129 | 130 | #define WINEASIO_NO_PORT_ID (-1) 131 | 132 | #define WINEASIO_INTERNAL_ERROR(code) \ 133 | do \ 134 | { \ 135 | ERR ("possible internal error, code (%d); please consider filing an" \ 136 | " Issue at https://wineasio.org describing what you were up to." \ 137 | "\n", code); \ 138 | } \ 139 | while (0); 140 | 141 | /****************************************************************************** 142 | * External declarations 143 | */ 144 | extern HRESULT WINAPI WineASIOCreateInstance (REFIID riid, 145 | LPVOID *ppobj); 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 Robert Reif 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "classid.h" 26 | #include "jackasio.h" 27 | 28 | 29 | WINE_DEFAULT_DEBUG_CHANNEL(asio); 30 | 31 | 32 | /****************************************************************************** 33 | * 34 | */ 35 | typedef struct 36 | { 37 | const IClassFactoryVtbl *lpVtbl; 38 | LONG ref; 39 | } 40 | IClassFactoryImpl; 41 | 42 | 43 | /****************************************************************************** 44 | * ClassFactory 45 | */ 46 | 47 | /****************************************************************************** 48 | * CF_QueryInterface 49 | */ 50 | static HRESULT WINAPI 51 | CF_QueryInterface (LPCLASSFACTORY iface, 52 | REFIID riid, 53 | LPVOID *ppobj) 54 | { 55 | IClassFactoryImpl *This = (IClassFactoryImpl *) iface; 56 | 57 | FIXME ("(%p, %s, %p) stub!\n", This, 58 | debugstr_guid(riid), 59 | ppobj); 60 | 61 | if (ppobj == NULL) 62 | { 63 | return E_POINTER; 64 | } 65 | 66 | return E_NOINTERFACE; 67 | } 68 | 69 | /****************************************************************************** 70 | * CF_AddRef 71 | */ 72 | static ULONG WINAPI 73 | CF_AddRef (LPCLASSFACTORY iface) 74 | { 75 | IClassFactoryImpl *This = (IClassFactoryImpl *) iface; 76 | ULONG ref = InterlockedIncrement (&(This->ref)); 77 | 78 | TRACE ("iface: %p, ref has been set to %x\n", This, 79 | ref); 80 | 81 | return ref; 82 | } 83 | 84 | /****************************************************************************** 85 | * CF_Release 86 | */ 87 | static ULONG WINAPI 88 | CF_Release (LPCLASSFACTORY iface) 89 | { 90 | IClassFactoryImpl *This = (IClassFactoryImpl *) iface; 91 | ULONG ref = InterlockedDecrement (&(This->ref)); 92 | 93 | TRACE ("iface %p, ref has been set to %x\n", This, 94 | ref); 95 | 96 | /* static class, won't be freed */ 97 | return ref; 98 | } 99 | 100 | /****************************************************************************** 101 | * CF_CreateInstance 102 | */ 103 | static HRESULT WINAPI 104 | CF_CreateInstance (LPCLASSFACTORY iface, 105 | LPUNKNOWN pOuter, 106 | REFIID riid, 107 | LPVOID *ppobj) 108 | { 109 | IClassFactoryImpl *This = (IClassFactoryImpl *) iface; 110 | 111 | TRACE ("iface: %p, pOuter: %p, riid: %s, ppobj: %p)\n", This, 112 | pOuter, 113 | debugstr_guid (riid), 114 | ppobj); 115 | 116 | if (pOuter) 117 | { 118 | return CLASS_E_NOAGGREGATION; 119 | } 120 | 121 | if (ppobj == NULL) 122 | { 123 | return E_INVALIDARG; // FIXME should be E_POINTER? 124 | } 125 | 126 | *ppobj = NULL; 127 | 128 | TRACE ("Creating the WineASIO object\n"); 129 | 130 | return WineASIOCreateInstance (riid, ppobj); 131 | } 132 | 133 | /****************************************************************************** 134 | * CF_LockServer 135 | */ 136 | static HRESULT WINAPI 137 | CF_LockServer (LPCLASSFACTORY iface, 138 | BOOL dolock) 139 | { 140 | IClassFactoryImpl *This = (IClassFactoryImpl *) iface; 141 | 142 | FIXME ("iface: %p, dolock: %d) stub!\n", This, 143 | dolock); 144 | 145 | return S_OK; 146 | } 147 | 148 | 149 | /****************************************************************************** 150 | * 151 | */ 152 | 153 | /****************************************************************************** 154 | * 155 | */ 156 | static const IClassFactoryVtbl CF_Vtbl = 157 | { 158 | CF_QueryInterface, 159 | CF_AddRef, 160 | CF_Release, 161 | CF_CreateInstance, 162 | CF_LockServer 163 | }; 164 | 165 | /****************************************************************************** 166 | * 167 | */ 168 | static IClassFactoryImpl WINEASIO_CF = 169 | { 170 | &CF_Vtbl, 1 171 | }; 172 | 173 | 174 | /****************************************************************************** 175 | * Entrypoints 176 | */ 177 | 178 | /****************************************************************************** 179 | * DllGetClassObject [DSOUND.@] 180 | * Retrieves class object from a DLL object 181 | * 182 | * NOTES 183 | * Docs say returns STDAPI 184 | * 185 | * PARAMS 186 | * rclsid [I] CLSID for the class object 187 | * riid [I] Reference to identifier of interface for class object 188 | * ppv [O] Address of variable to receive interface pointer for riid 189 | * 190 | * RETURNS 191 | * Success: S_OK 192 | * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, 193 | * E_UNEXPECTED 194 | */ 195 | HRESULT WINAPI 196 | DllGetClassObject (REFCLSID rclsid, 197 | REFIID riid, 198 | LPVOID *ppv) 199 | { 200 | TRACE ("rclsid: %s, riid: %s, ppv: %p)\n", debugstr_guid (rclsid), 201 | debugstr_guid (riid), 202 | ppv); 203 | 204 | if (ppv == NULL) 205 | { 206 | /* WARN("invalid parameter\n"); */ 207 | return E_INVALIDARG; 208 | } 209 | 210 | *ppv = NULL; 211 | 212 | if (!IsEqualIID (riid, &IID_IClassFactory) 213 | && !IsEqualIID (riid, &IID_IUnknown)) 214 | { 215 | /* WARN("no interface for %s\n", debugstr_guid(riid)); */ 216 | return E_NOINTERFACE; 217 | } 218 | 219 | if (IsEqualGUID (rclsid, &CLSID_WineASIO)) 220 | { 221 | CF_AddRef ((IClassFactory*) &WINEASIO_CF); 222 | *ppv = &WINEASIO_CF; 223 | return S_OK; 224 | } 225 | 226 | /* WARN("rclsid: %s, riid: %s, ppv: %p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); */ 227 | return CLASS_E_CLASSNOTAVAILABLE; 228 | } 229 | 230 | /****************************************************************************** 231 | * DllCanUnloadNow 232 | * Determines whether the DLL is in use. 233 | * 234 | * RETURNS 235 | * Success: S_OK 236 | * Failure: S_FALSE 237 | */ 238 | HRESULT WINAPI DllCanUnloadNow (void) 239 | { 240 | FIXME (": stub (S_FALSE)\n"); 241 | 242 | return S_FALSE; 243 | } 244 | 245 | /****************************************************************************** 246 | * DllMain (ASIO.init) 247 | */ 248 | BOOL WINAPI DllMain (HINSTANCE hInstDLL, 249 | DWORD fdwReason, 250 | LPVOID lpvReserved) 251 | { 252 | TRACE ("hInstDLL: %p, fdwReason: %x lpvReserved: %p)\n", hInstDLL, 253 | fdwReason, 254 | lpvReserved); 255 | 256 | switch (fdwReason) 257 | { 258 | case DLL_PROCESS_ATTACH: 259 | TRACE ("DLL_PROCESS_ATTACH\n"); 260 | break; 261 | case DLL_PROCESS_DETACH: 262 | TRACE ("DLL_PROCESS_DETACH\n"); 263 | break; 264 | case DLL_THREAD_ATTACH: 265 | TRACE ("DLL_THREAD_ATTACH\n"); 266 | break; 267 | case DLL_THREAD_DETACH: 268 | TRACE ("DLL_THREAD_DETACH\n"); 269 | break; 270 | default: 271 | TRACE("UNKNOWN REASON\n"); 272 | break; 273 | } 274 | 275 | return TRUE; 276 | } 277 | -------------------------------------------------------------------------------- /register.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Self-registerable DLL functions for wineasio.dll 3 | * 4 | * Copyright (C) 2003 John K. Hohm 5 | * Copyright (C) 2006 Robert Reif 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 | */ 21 | 22 | /* 23 | * Near the bottom of this file are the exported DllRegisterServer and 24 | * DllUnregisterServer, which make all this worthwhile. 25 | */ 26 | 27 | #include 28 | 29 | #define NONAMELESSSTRUCT 30 | #define NONAMELESSUNION 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "classid.h" 38 | 39 | 40 | WINE_DEFAULT_DEBUG_CHANNEL(asio); 41 | 42 | 43 | /****************************************************************************** 44 | * Class and interface structure declarations 45 | */ 46 | 47 | struct regsvr_coclass 48 | { 49 | CLSID const *clsid; /* NULL for end of list */ 50 | LPCSTR name; /* can be NULL to omit */ 51 | LPCSTR ips; /* can be NULL to omit */ 52 | LPCSTR ips32; /* can be NULL to omit */ 53 | LPCSTR ips32_tmodel; /* can be NULL to omit */ 54 | LPCSTR progid; /* can be NULL to omit */ 55 | LPCSTR viprogid; /* can be NULL to omit */ 56 | LPCSTR progid_extra; /* can be NULL to omit */ 57 | }; 58 | 59 | struct regsvr_interface 60 | { 61 | IID const *iid; /* NULL for end of list */ 62 | LPCSTR name; /* can be NULL to omit */ 63 | IID const *base_iid; /* can be NULL to omit */ 64 | int num_methods; /* can be <0 to omit */ 65 | CLSID const *ps_clsid; /* can be NULL to omit */ 66 | CLSID const *ps_clsid32; /* can be NULL to omit */ 67 | }; 68 | 69 | 70 | /****************************************************************************** 71 | * Static function declarations 72 | */ 73 | 74 | static void create_failed (LONG rc); 75 | static void set_failed (LONG rc); 76 | 77 | static LONG recursive_delete_key (HKEY key); 78 | static LONG recursive_delete_keyA (HKEY base, 79 | char const *name); 80 | static LONG recursive_delete_keyW (HKEY base, 81 | WCHAR const *name); 82 | 83 | static HRESULT unregister_driver (void); 84 | static HRESULT unregister_interfaces (struct regsvr_interface const *list); 85 | static HRESULT unregister_coclasses (struct regsvr_coclass const *list); 86 | 87 | static LONG register_key_defvalueA (HKEY base, 88 | WCHAR const *name, 89 | char const *value); 90 | static LONG register_key_defvalueW (HKEY base, 91 | WCHAR const *name, 92 | WCHAR const *value); 93 | static LONG register_key_guid (HKEY base, 94 | WCHAR const *name, 95 | GUID const *guid); 96 | 97 | static LONG register_progid (WCHAR const *clsid, 98 | char const *progid, 99 | char const *curver_progid, 100 | char const *name, 101 | char const *extra); 102 | 103 | static HRESULT register_driver (void); 104 | static HRESULT register_interfaces (struct regsvr_interface const *list); 105 | static HRESULT register_coclasses (struct regsvr_coclass const *list); 106 | 107 | 108 | /****************************************************************************** 109 | * String constant definitions 110 | */ 111 | static WCHAR const clsid_keyname[] = 112 | { 113 | 'C', 'L', 'S', 'I', 'D', 0 114 | }; 115 | static WCHAR const ips_keyname[] = 116 | { 117 | 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', 0 118 | }; 119 | static WCHAR const ips32_keyname[] = 120 | { 121 | 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', '3', '2', 0 122 | }; 123 | static WCHAR const progid_keyname[] = 124 | { 125 | 'P', 'r', 'o', 'g', 'I', 'D', 0 126 | }; 127 | static WCHAR const interface_keyname[] = 128 | { 129 | 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 130 | }; 131 | static WCHAR const base_ifa_keyname[] = 132 | { 133 | 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 134 | }; 135 | static WCHAR const num_methods_keyname[] = 136 | { 137 | 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 138 | }; 139 | static WCHAR const ps_clsid_keyname[] = 140 | { 141 | 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', 'i', 'd', 0 142 | }; 143 | static WCHAR const ps_clsid32_keyname[] = 144 | { 145 | 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', 'i', 'd', '3', 146 | '2', 0 147 | }; 148 | static WCHAR const curver_keyname[] = 149 | { 150 | 'C', 'u', 'r', 'V', 'e', 'r', 0 151 | }; 152 | static WCHAR const viprogid_keyname[] = 153 | { 154 | 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 155 | 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', 0 156 | }; 157 | 158 | static char const tmodel_valuename[] = "ThreadingModel"; 159 | 160 | 161 | /****************************************************************************** 162 | * Static Helper Functions 163 | */ 164 | 165 | /****************************************************************************** 166 | * create_failed 167 | */ 168 | static void 169 | create_failed (LONG rc) 170 | { 171 | ERR ("RegCreateKeyEx failed with code %d\n", rc); 172 | return; 173 | } 174 | 175 | /****************************************************************************** 176 | * set_failed 177 | */ 178 | static void 179 | set_failed (LONG rc) 180 | { 181 | ERR ("RegSetValueEx failed with code %d\n", rc); 182 | return; 183 | } 184 | 185 | /****************************************************************************** 186 | * recursive_delete_key 187 | */ 188 | static LONG 189 | recursive_delete_key (HKEY key) 190 | { 191 | LONG res; 192 | WCHAR subkey_name[MAX_PATH]; 193 | DWORD cName; 194 | HKEY subkey; 195 | 196 | for (;;) 197 | { 198 | cName = sizeof (subkey_name) / sizeof (WCHAR); 199 | res = RegEnumKeyExW (key, 0, 200 | subkey_name, &cName, NULL, 201 | NULL, NULL, 202 | NULL); 203 | if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 204 | { 205 | res = ERROR_SUCCESS; /* presumably we're done enumerating */ 206 | break; 207 | } 208 | 209 | res = RegOpenKeyExW (key, subkey_name, 0, 210 | KEY_READ | KEY_WRITE, 211 | &subkey); 212 | if (res == ERROR_FILE_NOT_FOUND) 213 | { 214 | continue; 215 | } 216 | if (res != ERROR_SUCCESS) 217 | { 218 | break; 219 | } 220 | 221 | res = recursive_delete_key (subkey); 222 | 223 | RegCloseKey (subkey); 224 | 225 | if (res != ERROR_SUCCESS) 226 | { 227 | break; 228 | } 229 | } 230 | 231 | if (res == ERROR_SUCCESS) 232 | { 233 | res = RegDeleteKeyW (key, 0); 234 | } 235 | 236 | return res; 237 | } 238 | 239 | /****************************************************************************** 240 | * recursive_delete_keyA 241 | */ 242 | static LONG 243 | recursive_delete_keyA (HKEY base, 244 | char const *name) 245 | { 246 | LONG res; 247 | HKEY key; 248 | 249 | res = RegOpenKeyExA (base, name, 0, 250 | KEY_READ | KEY_WRITE, 251 | &key); 252 | if (res == ERROR_FILE_NOT_FOUND) 253 | { 254 | res = ERROR_SUCCESS; 255 | goto out; 256 | } 257 | if (res != ERROR_SUCCESS) 258 | { 259 | goto out; 260 | } 261 | 262 | res = recursive_delete_key (key); 263 | 264 | RegCloseKey (key); 265 | out: 266 | return res; 267 | } 268 | 269 | /****************************************************************************** 270 | * recursive_delete_keyW 271 | */ 272 | static LONG 273 | recursive_delete_keyW(HKEY base, 274 | WCHAR const *name) 275 | { 276 | LONG res; 277 | HKEY key; 278 | 279 | res = RegOpenKeyExW (base, name, 0, 280 | KEY_READ | KEY_WRITE, 281 | &key); 282 | if (res == ERROR_FILE_NOT_FOUND) 283 | { 284 | res = ERROR_SUCCESS; 285 | goto out; 286 | } 287 | if (res != ERROR_SUCCESS) 288 | { 289 | goto out; 290 | } 291 | 292 | res = recursive_delete_key (key); 293 | 294 | RegCloseKey (key); 295 | out: 296 | return res; 297 | } 298 | 299 | /****************************************************************************** 300 | * unregister_driver 301 | */ 302 | static HRESULT 303 | unregister_driver (void) 304 | { 305 | LPCSTR asio_key = "Software\\ASIO\\WineASIO"; 306 | 307 | /* FIXME */ 308 | return recursive_delete_keyA (HKEY_LOCAL_MACHINE, asio_key); 309 | } 310 | 311 | /****************************************************************************** 312 | * unregister_interfaces 313 | */ 314 | static HRESULT 315 | unregister_interfaces (struct regsvr_interface const *list) 316 | { 317 | LONG res = ERROR_SUCCESS; 318 | HKEY interface_key; 319 | 320 | res = RegOpenKeyExW (HKEY_CLASSES_ROOT, interface_keyname, 0, 321 | KEY_READ | KEY_WRITE, 322 | &interface_key); 323 | if (res == ERROR_FILE_NOT_FOUND) 324 | { 325 | res = ERROR_SUCCESS; 326 | goto out; 327 | } 328 | if (res != ERROR_SUCCESS) 329 | { 330 | goto out; 331 | } 332 | 333 | for (; res == ERROR_SUCCESS && list->iid; ++list) 334 | { 335 | WCHAR buf[MAX_GUID_STRING_LEN]; 336 | 337 | StringFromGUID2 (list->iid, 338 | buf, 339 | MAX_GUID_STRING_LEN); 340 | 341 | res = recursive_delete_keyW (interface_key, 342 | buf); 343 | } 344 | RegCloseKey (interface_key); 345 | out: 346 | return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; 347 | } 348 | 349 | /****************************************************************************** 350 | * unregister_coclasses 351 | */ 352 | static HRESULT 353 | unregister_coclasses (struct regsvr_coclass const *list) 354 | { 355 | LONG res = ERROR_SUCCESS; 356 | HKEY coclass_key; 357 | 358 | res = RegOpenKeyExW (HKEY_CLASSES_ROOT, clsid_keyname, 0, 359 | KEY_READ | KEY_WRITE, 360 | &coclass_key); 361 | if (res == ERROR_FILE_NOT_FOUND) 362 | { 363 | res = ERROR_SUCCESS; 364 | goto out; 365 | } 366 | if (res != ERROR_SUCCESS) 367 | { 368 | goto out; 369 | } 370 | 371 | for (; res == ERROR_SUCCESS && list->clsid; ++list) 372 | { 373 | WCHAR buf[MAX_GUID_STRING_LEN]; 374 | 375 | StringFromGUID2 (list->clsid, 376 | buf, 377 | MAX_GUID_STRING_LEN); 378 | res = recursive_delete_keyW (coclass_key, 379 | buf); 380 | if (res != ERROR_SUCCESS) 381 | { 382 | goto err_out_close_coclass_key; 383 | } 384 | 385 | if (list->progid) 386 | { 387 | res = recursive_delete_keyA (HKEY_CLASSES_ROOT, 388 | list->progid); 389 | if (res != ERROR_SUCCESS) 390 | { 391 | goto err_out_close_coclass_key; 392 | } 393 | } 394 | 395 | if (list->viprogid) 396 | { 397 | res = recursive_delete_keyA (HKEY_CLASSES_ROOT, 398 | list->viprogid); 399 | if (res != ERROR_SUCCESS) 400 | { 401 | goto err_out_close_coclass_key; 402 | } 403 | } 404 | } 405 | err_out_close_coclass_key: 406 | RegCloseKey (coclass_key); 407 | out: 408 | return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32 (res) : S_OK; 409 | } 410 | 411 | /****************************************************************************** 412 | * register_key_defvalueA 413 | */ 414 | static LONG 415 | register_key_defvalueA (HKEY base, 416 | WCHAR const *name, 417 | char const *value) 418 | { 419 | LONG res; 420 | HKEY key; 421 | 422 | res = RegCreateKeyExW (base, name, 0, 423 | NULL, 424 | REG_OPTION_NON_VOLATILE, 425 | KEY_READ | KEY_WRITE, NULL, 426 | &key, NULL); 427 | if (res != ERROR_SUCCESS) 428 | { 429 | create_failed (res); 430 | goto out; 431 | } 432 | 433 | res = RegSetValueExA (key, NULL, 0, 434 | REG_SZ, (const BYTE *) value, 435 | lstrlenA (value) + 1); 436 | if (res != ERROR_SUCCESS) 437 | { 438 | set_failed (res); 439 | } 440 | 441 | RegCloseKey (key); 442 | out: 443 | return res; 444 | } 445 | 446 | /****************************************************************************** 447 | * register_key_defvalueW 448 | */ 449 | static LONG 450 | register_key_defvalueW (HKEY base, 451 | WCHAR const *name, 452 | WCHAR const *value) 453 | { 454 | LONG res; 455 | HKEY key; 456 | 457 | res = RegCreateKeyExW (base, name, 0, 458 | NULL, 459 | REG_OPTION_NON_VOLATILE, 460 | KEY_READ | KEY_WRITE, NULL, 461 | &key, NULL); 462 | if (res != ERROR_SUCCESS) 463 | { 464 | create_failed (res); 465 | goto out; 466 | } 467 | 468 | res = RegSetValueExW (key, NULL, 0, 469 | REG_SZ, (const BYTE *) value, 470 | (lstrlenW (value) + 1) * sizeof (WCHAR)); 471 | if (res != ERROR_SUCCESS) 472 | { 473 | set_failed (res); 474 | } 475 | 476 | RegCloseKey (key); 477 | out: 478 | return res; 479 | } 480 | 481 | /****************************************************************************** 482 | * register_key_guid 483 | */ 484 | static LONG 485 | register_key_guid (HKEY base, 486 | WCHAR const *name, 487 | GUID const *guid) 488 | { 489 | WCHAR buf[MAX_GUID_STRING_LEN]; 490 | 491 | StringFromGUID2 (guid, buf, MAX_GUID_STRING_LEN); 492 | 493 | return register_key_defvalueW (base, 494 | name, 495 | buf); 496 | } 497 | 498 | /****************************************************************************** 499 | * register_progid 500 | */ 501 | static LONG 502 | register_progid (WCHAR const *clsid, 503 | char const *progid, 504 | char const *curver_progid, 505 | char const *name, 506 | char const *extra) 507 | { 508 | LONG res; 509 | HKEY progid_key; 510 | 511 | res = RegCreateKeyExA (HKEY_CLASSES_ROOT, progid, 0, 512 | NULL, 513 | REG_OPTION_NON_VOLATILE, 514 | KEY_READ | KEY_WRITE, NULL, 515 | &progid_key, NULL); 516 | if (res != ERROR_SUCCESS) 517 | { 518 | create_failed (res); 519 | goto out; 520 | } 521 | 522 | if (name) 523 | { 524 | res = RegSetValueExA (progid_key, NULL, 0, 525 | REG_SZ, (const BYTE *) name, 526 | strlen (name) + 1); 527 | if (res != ERROR_SUCCESS) 528 | { 529 | set_failed (res); 530 | goto error_close_progid_key; 531 | } 532 | } 533 | 534 | if (clsid) 535 | { 536 | res = register_key_defvalueW (progid_key, 537 | clsid_keyname, 538 | clsid); 539 | if (res != ERROR_SUCCESS) 540 | { 541 | goto error_close_progid_key; 542 | } 543 | } 544 | 545 | if (curver_progid) 546 | { 547 | res = register_key_defvalueA (progid_key, 548 | curver_keyname, 549 | curver_progid); 550 | if (res != ERROR_SUCCESS) 551 | { 552 | goto error_close_progid_key; 553 | } 554 | } 555 | 556 | if (extra) 557 | { 558 | HKEY extra_key; 559 | 560 | res = RegCreateKeyExA (progid_key, extra, 0, 561 | NULL, 562 | REG_OPTION_NON_VOLATILE, 563 | KEY_READ | KEY_WRITE, NULL, 564 | &extra_key, NULL); 565 | if (res == ERROR_SUCCESS) 566 | { 567 | RegCloseKey (extra_key); 568 | } 569 | else 570 | { 571 | create_failed (res); 572 | } 573 | } 574 | error_close_progid_key: 575 | RegCloseKey (progid_key); 576 | out: 577 | return res; 578 | } 579 | 580 | /****************************************************************************** 581 | * register driver 582 | * 583 | * CREATES (if the WineASIO key doesn't exist): 584 | * HKEY_LOCAL_MACHINE\Software\ASIO\WineASIO\CLSID\ 585 | * HKEY_LOCAL_MACHINE\Software\ASIO\WineASIO\Description\WineASIO Driver 586 | */ 587 | static HRESULT 588 | register_driver (void) 589 | { 590 | LPCSTR asio_key = "Software\\ASIO\\WineASIO"; 591 | LPCSTR clsid = "CLSID"; 592 | LPCSTR wine_clsid = "{48D0C522-BFCC-45CC-8B84-17F25F33E6E8}"; 593 | LPCSTR desc = "Description"; 594 | LPCSTR wine_desc = "WineASIO Driver"; 595 | HKEY key; 596 | LONG rc; 597 | 598 | rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, asio_key, 0, 599 | KEY_READ | KEY_WRITE, 600 | &key); 601 | if (rc == ERROR_SUCCESS) 602 | { 603 | goto out; 604 | } 605 | 606 | rc = RegCreateKeyExA (HKEY_LOCAL_MACHINE, asio_key, 0, 607 | NULL, 608 | REG_OPTION_NON_VOLATILE, 609 | KEY_READ | KEY_WRITE, NULL, 610 | &key, NULL); 611 | if (rc != ERROR_SUCCESS) 612 | { 613 | create_failed (rc); 614 | goto out; 615 | } 616 | 617 | rc = RegSetValueExA (key, clsid, 0, 618 | REG_SZ, (const BYTE *) wine_clsid, 619 | strlen(wine_clsid) + 1); 620 | if (rc != ERROR_SUCCESS) 621 | { 622 | set_failed (rc); 623 | goto out; 624 | } 625 | 626 | rc = RegSetValueExA (key, desc, 0, 627 | REG_SZ, (const BYTE *) wine_desc, 628 | strlen(wine_desc) + 1); 629 | if (rc != ERROR_SUCCESS) 630 | { 631 | set_failed (rc); 632 | } 633 | out: 634 | RegCloseKey (key); 635 | 636 | return rc; 637 | } 638 | 639 | /****************************************************************************** 640 | * register_interfaces 641 | */ 642 | static HRESULT 643 | register_interfaces (struct regsvr_interface const *list) 644 | { 645 | LONG res = ERROR_SUCCESS; 646 | HKEY interface_key; 647 | 648 | res = RegCreateKeyExW (HKEY_CLASSES_ROOT, interface_keyname, 0, 649 | NULL, 650 | REG_OPTION_NON_VOLATILE, 651 | KEY_READ | KEY_WRITE, NULL, 652 | &interface_key, NULL); 653 | if (res != ERROR_SUCCESS) 654 | { 655 | create_failed (res); 656 | goto error_return; 657 | } 658 | 659 | for (; res == ERROR_SUCCESS && list->iid; ++list) 660 | { 661 | WCHAR buf[MAX_GUID_STRING_LEN]; 662 | HKEY iid_key; 663 | 664 | StringFromGUID2 (list->iid, buf, MAX_GUID_STRING_LEN); 665 | 666 | res = RegCreateKeyExW (interface_key, buf, 0, 667 | NULL, 668 | REG_OPTION_NON_VOLATILE, 669 | KEY_READ | KEY_WRITE, NULL, 670 | &iid_key, NULL); 671 | if (res != ERROR_SUCCESS) 672 | { 673 | create_failed (res); 674 | goto error_close_interface_key; 675 | } 676 | 677 | if (list->name) 678 | { 679 | res = RegSetValueExA (iid_key, NULL, 0, 680 | REG_SZ, (const BYTE*) (list->name), 681 | strlen (list->name) + 1); 682 | if (res != ERROR_SUCCESS) 683 | { 684 | set_failed (res); 685 | goto error_close_iid_key; 686 | } 687 | } 688 | 689 | if (list->base_iid) 690 | { 691 | res = register_key_guid (iid_key, 692 | base_ifa_keyname, 693 | list->base_iid); 694 | if (res != ERROR_SUCCESS) 695 | { 696 | goto error_close_iid_key; 697 | } 698 | } 699 | 700 | if (list->num_methods > 0) 701 | { 702 | static WCHAR const fmt[3] = { '%', 'd', 0 }; 703 | HKEY key; 704 | 705 | res = RegCreateKeyExW (iid_key, num_methods_keyname, 0, 706 | NULL, 707 | REG_OPTION_NON_VOLATILE, 708 | KEY_READ | KEY_WRITE, NULL, 709 | &key, NULL); 710 | if (res != ERROR_SUCCESS) 711 | { 712 | create_failed (res); 713 | goto error_close_iid_key; 714 | } 715 | 716 | wsprintfW (buf, fmt, list->num_methods); 717 | 718 | res = RegSetValueExW (key, NULL, 0, 719 | REG_SZ, (const BYTE *) buf, 720 | (lstrlenW (buf) + 1) * sizeof (WCHAR)); 721 | 722 | RegCloseKey (key); 723 | 724 | if (res != ERROR_SUCCESS) 725 | { 726 | set_failed (res); 727 | goto error_close_iid_key; 728 | } 729 | } 730 | 731 | if (list->ps_clsid) 732 | { 733 | res = register_key_guid (iid_key, 734 | ps_clsid_keyname, 735 | list->ps_clsid); 736 | if (res != ERROR_SUCCESS) 737 | { 738 | goto error_close_iid_key; 739 | } 740 | } 741 | 742 | if (list->ps_clsid32) 743 | { 744 | res = register_key_guid (iid_key, 745 | ps_clsid32_keyname, 746 | list->ps_clsid32); 747 | if (res != ERROR_SUCCESS) 748 | { 749 | goto error_close_iid_key; 750 | } 751 | } 752 | 753 | error_close_iid_key: 754 | RegCloseKey (iid_key); 755 | } 756 | 757 | error_close_interface_key: 758 | 759 | RegCloseKey (interface_key); 760 | error_return: 761 | return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32 (res) : S_OK; 762 | } 763 | 764 | /****************************************************************************** 765 | * register_coclasses 766 | * 767 | * Creates: 768 | * HKEY_CLASSES_ROOT\CLSID\\@\WineASIO Object 769 | * HKEY_CLASSES_ROOT\CLSID\\InProcServer\ips>[NULL] FIXME 770 | * HKEY_CLASSES_ROOT\CLSID\\InProcServer32\@\wineasio.dll 771 | * HKEY_CLASSES_ROOT\CLSID\\InProcServer32\ThreadingModel\Apartment 772 | */ 773 | static HRESULT 774 | register_coclasses (struct regsvr_coclass const *list) 775 | { 776 | LONG res = ERROR_SUCCESS; 777 | HKEY coclass_key; 778 | 779 | TRACE ("list: %p\n", list); 780 | 781 | res = RegCreateKeyExW (HKEY_CLASSES_ROOT, clsid_keyname, 0, 782 | NULL, 783 | REG_OPTION_NON_VOLATILE, 784 | KEY_READ | KEY_WRITE, NULL, 785 | &coclass_key, NULL); 786 | if (res != ERROR_SUCCESS) 787 | { 788 | create_failed (res); 789 | goto out; 790 | } 791 | 792 | for (; res == ERROR_SUCCESS && list->clsid; ++list) 793 | { 794 | WCHAR buf[MAX_GUID_STRING_LEN]; 795 | HKEY clsid_key; 796 | 797 | StringFromGUID2 (list->clsid, buf, MAX_GUID_STRING_LEN); 798 | 799 | res = RegCreateKeyExW (coclass_key, buf, 0, 800 | NULL, 801 | REG_OPTION_NON_VOLATILE, 802 | KEY_READ | KEY_WRITE, NULL, 803 | &clsid_key, NULL); 804 | if (res != ERROR_SUCCESS) 805 | { 806 | create_failed (res); 807 | goto err_out_close_coclass_key; 808 | } 809 | 810 | if (list->name) 811 | { 812 | res = RegSetValueExA (clsid_key, NULL, 0, 813 | REG_SZ, (const BYTE *) (list->name), 814 | strlen (list->name) + 1); 815 | if (res != ERROR_SUCCESS) 816 | { 817 | set_failed (res); 818 | goto err_out_close_clsid_key; 819 | } 820 | } 821 | 822 | if (list->ips) 823 | { 824 | res = register_key_defvalueA (clsid_key, 825 | ips_keyname, 826 | list->ips); 827 | if (res != ERROR_SUCCESS) 828 | { 829 | goto err_out_close_clsid_key; 830 | } 831 | } 832 | 833 | if (list->ips32) 834 | { 835 | HKEY ips32_key; 836 | 837 | res = RegCreateKeyExW (clsid_key, ips32_keyname, 0, 838 | NULL, 839 | REG_OPTION_NON_VOLATILE, 840 | KEY_READ | KEY_WRITE, NULL, 841 | &ips32_key, NULL); 842 | if (res != ERROR_SUCCESS) 843 | { 844 | create_failed (res); 845 | goto err_out_close_clsid_key; 846 | } 847 | 848 | res = RegSetValueExA (ips32_key, NULL, 0, 849 | REG_SZ, (const BYTE *) list->ips32, 850 | lstrlenA (list->ips32) + 1); 851 | if (res == ERROR_SUCCESS && list->ips32_tmodel) 852 | { 853 | res = RegSetValueExA (ips32_key, tmodel_valuename, 0, 854 | REG_SZ, (const BYTE*) list->ips32_tmodel, 855 | strlen (list->ips32_tmodel) + 1); 856 | } 857 | 858 | RegCloseKey (ips32_key); 859 | 860 | if (res != ERROR_SUCCESS) 861 | { 862 | set_failed (res); 863 | goto err_out_close_clsid_key; 864 | } 865 | } 866 | 867 | if (list->progid) 868 | { 869 | res = register_key_defvalueA (clsid_key, 870 | progid_keyname, 871 | list->progid); 872 | if (res != ERROR_SUCCESS) 873 | { 874 | goto err_out_close_clsid_key; 875 | } 876 | 877 | res = register_progid (buf, 878 | list->progid, 879 | NULL, 880 | list->name, 881 | list->progid_extra); 882 | if (res != ERROR_SUCCESS) 883 | { 884 | goto err_out_close_clsid_key; 885 | } 886 | } 887 | 888 | if (list->viprogid) 889 | { 890 | res = register_key_defvalueA (clsid_key, 891 | viprogid_keyname, 892 | list->viprogid); 893 | if (res != ERROR_SUCCESS) 894 | { 895 | goto err_out_close_clsid_key; 896 | } 897 | 898 | res = register_progid (buf, 899 | list->viprogid, 900 | list->progid, 901 | list->name, 902 | list->progid_extra); 903 | if (res != ERROR_SUCCESS) 904 | { 905 | goto err_out_close_clsid_key; 906 | } 907 | } 908 | err_out_close_clsid_key: 909 | RegCloseKey (clsid_key); 910 | } 911 | 912 | err_out_close_coclass_key: 913 | RegCloseKey (coclass_key); 914 | 915 | out: 916 | return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32 (res) : S_OK; 917 | } 918 | 919 | 920 | /****************************************************************************** 921 | * Class and Interface definitions 922 | */ 923 | static struct regsvr_coclass const coclass_list[] = 924 | { 925 | { 926 | &CLSID_WineASIO, 927 | "WineASIO Object", 928 | NULL, 929 | "wineasio.dll", 930 | "Apartment" 931 | }, 932 | { 933 | NULL /* list terminator */ 934 | } 935 | }; 936 | 937 | static struct regsvr_interface const interface_list[] = 938 | { 939 | { 940 | NULL /* list terminator */ 941 | } 942 | }; 943 | 944 | 945 | /****************************************************************************** 946 | * Entrypoints 947 | */ 948 | 949 | /****************************************************************************** 950 | * DllUnregisterServer (wineasio.@) 951 | */ 952 | HRESULT WINAPI 953 | DllUnregisterServer (void) 954 | { 955 | HRESULT hr; 956 | 957 | TRACE ("\n"); 958 | 959 | hr = unregister_coclasses (coclass_list); 960 | if (!SUCCEEDED (hr)) 961 | { 962 | goto out; 963 | } 964 | 965 | hr = unregister_interfaces (interface_list); 966 | if (!SUCCEEDED (hr)) 967 | { 968 | goto out; 969 | } 970 | 971 | hr = unregister_driver (); 972 | out: 973 | return hr; 974 | } 975 | 976 | /****************************************************************************** 977 | * DllRegisterServer (wineasio.@) 978 | */ 979 | HRESULT WINAPI 980 | DllRegisterServer (void) 981 | { 982 | HRESULT hr; 983 | 984 | TRACE("\n"); 985 | 986 | hr = register_coclasses (coclass_list); 987 | if (!SUCCEEDED (hr)) 988 | { 989 | goto out; 990 | } 991 | 992 | hr = register_interfaces (interface_list); 993 | if (!SUCCEEDED (hr)) 994 | { 995 | goto out; 996 | } 997 | 998 | hr = register_driver (); 999 | out: 1000 | return hr; 1001 | } 1002 | -------------------------------------------------------------------------------- /setwin10.reg: -------------------------------------------------------------------------------- 1 | REGEDIT4 2 | 3 | [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion] 4 | "CSDVersion"="" 5 | "CurrentBuildNumber"="15063" 6 | "CurrentVersion"="10.0" 7 | "ProductName"="Microsoft Windows 10" 8 | 9 | [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Windows] 10 | "CDSVersion"=dword:00000000 11 | 12 | [HKEY_CURRENT_USER\Control Panel\Desktop] 13 | "LogPixels"=dword:00000095 14 | -------------------------------------------------------------------------------- /tuneables.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 15 | */ 16 | 17 | #ifndef __WINEASIO_TUNEABLES_H__ 18 | #define __WINEASIO_TUNEABLES_H__ 19 | 20 | /****************************************************************************** 21 | * WineASIO Defaults 22 | * 23 | * Change these values to taste if you want to hardcode your defaults 24 | * and thus avoid having to pass parameters through the environment 25 | * or set these values from the registry at run-time. 26 | * 27 | * FIXME: how to construct env. var names. 28 | */ 29 | 30 | /* 31 | * Default number of writable JACK input ports FIXME: writable input? 32 | * on the Windows client application. 33 | */ 34 | #define DEFAULT_WINEASIO_NUM_PORTS_INP 16 35 | 36 | /* 37 | * Default number of readable JACK output ports 38 | * on the Windows client application. 39 | */ 40 | #define DEFAULT_WINEASIO_NUM_PORTS_OUT 16 41 | 42 | /* 43 | * Default boolean indicating whether the JACK 44 | * buffer size should be fixed and unchangeable. 45 | */ 46 | // FIXME: where does the value come from if fixed? 47 | #define DEFAULT_WINEASIO_FIXED_BUFSZ 1 48 | 49 | /* 50 | * Default preferred buffer size. 51 | */ 52 | // FIXME when is this used? 53 | #define DEFAULT_WINEASIO_PREFERD_BUFSZ 2048 54 | 55 | #define DEFAULT_WINEASIO_CONN_PORTS 1 56 | #define DEFAULT_WINEASIO_START_JACK 1 57 | 58 | 59 | /****************************************************************************** 60 | * YOU SHOULDN'T HAVE TO CHANGE THESE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING 61 | */ 62 | // FIXME: comment these. 63 | #define WINEASIO_MIN_BUFSZ 16 64 | #define WINEASIO_MAX_BUFSZ 8192 65 | 66 | /* 67 | * Sample format to be used by JACK. FIXME 68 | * 69 | * Valid values are: 70 | * - ASIOSTFloat32LSB 71 | * - ASIOSTInt32LSB 72 | */ 73 | #define WINEASIO_SMPL_FMT ASIOSTFloat32LSB 74 | 75 | #define WINEASIO_MAX_NAME_LEN 32 76 | #define WINEASIO_MAX_ENV_LEN 6 /* max len of env. value (incl. tr. NULL) */ 77 | 78 | #define WINEASIO_VERSION 95 79 | 80 | #define IEEE754_64FLOAT 1 81 | 82 | // FIXME: put NATIVE IN HERE 83 | #endif 84 | -------------------------------------------------------------------------------- /win32ify.sed: -------------------------------------------------------------------------------- 1 | s/unsigned long/ULONG/g 2 | s/long long int/LONGLONG/g 3 | s/long int/LONG/g 4 | s/long/LONG/g 5 | -------------------------------------------------------------------------------- /win64ify.sed: -------------------------------------------------------------------------------- 1 | s/unsigned long/ULONG/g 2 | s/long long int/LONGLONG/g 3 | s/long int/LONG/g 4 | s/long/LONG/g 5 | 6 | # The following 4 lines are necessary for win64 but cause win32 to crash 7 | s/(\(\*bufferSwitch)\)/(CALLBACK \1/g 8 | s/(\(\*sampleRateDidChange)\)/(CALLBACK \1/g 9 | s/(\(\*asioMessage)\)/(CALLBACK \1/g 10 | s/(\(\*bufferSwitchTimeInfo)\)/(CALLBACK \1/g 11 | -------------------------------------------------------------------------------- /wineasio.dll.spec: -------------------------------------------------------------------------------- 1 | @ stdcall -private DllRegisterServer() 2 | @ stdcall -private DllGetClassObject(ptr ptr ptr) 3 | @ stdcall -private DllCanUnloadNow() 4 | @ stdcall -private DllUnregisterServer() 5 | --------------------------------------------------------------------------------