Repository: madderscientist/noteDigger Branch: main Commit: d62567861517 Files: 52 Total size: 11.1 MB Directory structure: gitextract_zaftgd5a/ ├── LICENSE ├── README.md ├── app.js ├── core/ │ ├── app_analyser.js │ ├── app_audioplayer.js │ ├── app_beatbar.js │ ├── app_hscrollbar.js │ ├── app_io.js │ ├── app_keyboard.js │ ├── app_midiaction.js │ ├── app_midiplayer.js │ ├── app_spectrogram.js │ └── app_timebar.js ├── dataProcess/ │ ├── AI/ │ │ ├── AIEntrance.js │ │ ├── SpectralClustering.js │ │ ├── basicamt_44100.onnx │ │ ├── basicamt_worker.js │ │ ├── dist/ │ │ │ └── ort-wasm-simd.wasm │ │ ├── postprocess.js │ │ ├── septimbre_44100.onnx │ │ └── septimbre_worker.js │ ├── ANA.js │ ├── CQT/ │ │ ├── cqt.js │ │ └── cqt_worker.js │ ├── NNLS.js │ ├── aboutANA.md │ ├── analyser.js │ ├── bpmEst.js │ ├── fft_real.js │ └── stftGPU.js ├── docs/ │ └── DEVELOPMENT.md ├── index.html ├── jsconfig.json ├── lib/ │ ├── beatBar.js │ ├── fakeAudio.js │ ├── midi.js │ ├── saver.js │ ├── snapshot.js │ └── tinySynth.js ├── plugins/ │ ├── chordEst.js │ └── pitchName.js ├── style/ │ ├── askUI.css │ ├── channelDiv.css │ ├── contextMenu.css │ ├── icon/ │ │ └── iconfont.css │ ├── myRange.css │ ├── siderMenu.css │ └── style.css └── ui/ ├── channelDiv.js ├── contextMenu.js ├── myRange.js └── siderMenu.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================
logo
noteDigger
~前端辅助人工扒谱工具~
# noteDigger! “NoteDigger”——音符挖掘者,即扒谱。模仿的是软件wavetone,但是是**双击即用**、**现代UI**的**纯前端**应用。
就要重复造轮子!即:不使用框架、不使用外部库;目的是减小项目大小,并掌握各个环节。目前频谱分析的软件非常多,功能也超级强大,自知比不过……所以唯一能一战的就是项目体积了!作为一个纯前端项目,就要把易用的优点完全发扬!
[在线使用](https://madderscientist.github.io/noteDigger/)
视频演示(视频发布于更新节奏对齐之前) 点击封面跳转视频 ## 使用流程 1. 在线or下载到本地,用主流现代浏览器打开(开发使用Chrome)。 2. 导入音频——文件-上传,或直接将音频拖拽进去! 3. 选择声道分析,或者导入之前分析的结果(只有选择音频之后才有导入之前结果的接口) 4. 根据频谱分析,开始绘制midi音符!可参考下文推荐流程。 5. 导出为midi等,或者暂时导出项目(下次继续) ### [*建议的扒谱流程](https://www.bilibili.com/video/BV1LFRmBcEEU) 👈视频教程 1. 导入时选择CQT。视情况勾选GPU。 2. 在“分析”页面,点击“节奏分析”、“去除谐波”、“调性分析”(建议最后一个运行)。 3. 勾选“设置”-“播放节拍”,修正节拍;接着使用小节栏右键菜单的“合并下一小节”等功能修正节奏型。 4. 点击“分析”-“人工智障扒谱”,并在完成后将对应音轨锁定、静音,作为扒谱参考。 5. 切换吸附模式为“节拍吸附”(顶部工具栏;需要保证节拍已经修得不错了)。 6. 调整顶部滑条控制频谱强度,人工完成后续扒谱。 ## 导入导出说明 - 导出进度: 结果是.nd的二进制文件,保存频谱图、音符、音轨、小节等信息。导入的时候并不会强制要求匹配原曲!(会根据文件名判断一下,但不强制) - 导出为midi: 有两个模式。模式二只保证能听,节拍默认4/4,bpm默认60,midi类型默认1(同步多音轨),时间精度和设置的精度一致(因此如果midi先导入再导出会有量化误差);模式一会根据小节线进行对齐(需要用户设置好小节线),可以直接用于制谱,算法概述见下面“节奏对齐”。由于midi协议规定第十轨用于打击乐,因此扒谱时旋律需要避开第十轨,可以设置一个空音轨占位。本应用没有设计避开第十轨,也没设计扒鼓点,因此扒谱时第十轨虽然听起来还是乐音,但导出为midi后会变成鼓点。 - 导入midi: 将midi音符导入,只保证音轨、音符、音色能对应,音量默认127。如果导入后没有超过总音轨数,会在后面增加;否则会覆盖后面几轨(有提示)。 ## 常规操作 - 空格: 播放 - **双击**时间轴: 从双击的位置开始播放 - 在时间轴上拖拽: 设置重复区间 - 在时间轴上拉动小节线: 设置小节bpm;若按住shift拖动,只改变该小节线位置、不影响后续小节 - 鼠标**中键**时间轴: 将时间设置到点击位置,播放状态保持上一刻 - 鼠标**右键**时间轴(上半/下半): 具体设置重复时间/小节 - 按住空白拖动: 在当前音轨绘制一个音符 - 按住音符左半边拖动: 改变位置 - 按住音符右半边拖动: 改变时长 - Ctrl+点击音符: 多选音符 - delete: 删除选中的音符 - Ctrl+滚轮: 横向缩放 - 按住**中键**拖拽、**触摸板**滑动: 移动视野 ## 快捷键 只有在导入并分析音频之后才能使用这些快捷键 - Ctrl+Z: 撤销(只记录16次历史,音轨、音符、小节线操作均会被记录) - Ctrl+Y: 重做 - Ctrl+A: 全选当前音轨 - Ctrl+Shift+A: 全选所有音轨 - Ctrl+D: 取消选中 - Ctrl+C: 复制选中的音符 - Ctrl+X: 剪贴选中的音符 - Ctrl+V: 粘贴到选中的音轨上(暂不实现跨页面粘贴) - Ctrl+B: 呼出/收回音轨面板 - Shift+右键: 菜单,包含撤销/重做、复制/粘贴、反选当前轨、删除 - ←↑→↓: 视野移动一格 - PageUp、PageDown:向前翻页/向后翻页 - Home:设置播放位置为0,播放状态保持上一刻 ## 小细节 - 滑动条,如果旁边有数字,点击就可以恢复初始值。 - 多次点击“笔”右侧的选择工具,可以切换选择模式。(注意,只能选中当前音轨的音符) - 点击某个音符可以选中该轨。 - 选择乐器时,展开下拉框并且按首字母可以快速跳转(浏览器下拉框自带)。 - 音轨中,“闭眼”只是看不见,还是可以操作的;一般要搭配“锁定”使用,默认两者会联动。 ## 支持的格式 推荐使用常见的mp3、wav文件;除此之外,视频类文件也可以使用,比如mp4、mov、m4v。 但是如下格式不支持(浏览器API不支持解析)(仅仅在Chrome浏览器尝试过): - aiff(苹果的音频格式) 对于ios的Safari浏览器,上传音频文件也许有些困难。可以选择视频。(不过为什么要用触屏控制啊,根本没适配) ## 其他说明 分析-自动填充,原理是将大于阈值的标记出来,效果不堪入目……于是研究并引入了基于神经网络的扒谱(分析-人工智障扒谱),但是效果非常初级。如有想法欢迎call me。 ## 关于节奏对齐 若为了制谱,导出 MIDI 时,应该进行量化对齐。
对齐算法需要提供精度参数 $x$,会用时长比 $\frac{\text{音符时长}}{x}$ 小的、最大的 $2^k$ 分音符(时长为四分音符的 $2^{2-k}$)对开头和结尾时刻进行量化。例如 $x=2$ 时,四分音符将按照八分音符的划分对齐、八分音符则按十六分音符的划分对齐……不过这也意味着四分音符只可能在整数倍个八分音符的时长处开始,而不可能在第3个十六分音符的时刻起音。
因此,如果你保证对齐非常精准(比如使用了节拍吸附,见下文),那么 $x$ 应该调大一些;如果你大多时间用格点吸附或不吸附,那么 $x$ 应该小一些。 ### 新版本 新版本新增了按小节线吸附的方式,强烈推荐使用(可通过顶部工具栏的吸附模式切换)。在该模式下,音符可以完美对齐小节线。当然,三连音这类节奏仍需借助其他模式绘制。
横向缩放间距可调节吸附线的精度,从而支持任意有限位二进制小数表示的时长。这是一个很好的设计:既没有破坏以“秒”为单位的时间轴概念(下文),也兼容了小节对齐的需求。 ### 老版本 很长一段时间内,noteDigger只有格点吸附。音符绘制精度与最初选择的音频分析精度一致,绘制音符大概是不能精准对齐小节线了(但是导出midi的时候可以用对齐算法),**需要强迫症忍受一下**。
乐谱的基本单位是“x分音符”,而音频的基本单位是“秒”。要实现小节对齐,必须将单位统一为“x分音符”。 然而,整个程序的时间轴以“秒”为单位,这是由频谱分析决定的。若要实现类似制谱软件的对齐方式,音符绘制就必须按“x分音符”对齐。这意味着,在 120 BPM 小节下的音符,若被拖放到 60 BPM 的小节中,在以秒为单位的时间轴上,其时间会变长——Wavetone 正是这样处理的。
但是对着原曲扒谱,最好还是根据"秒"来绘制音符。用 Wavetone 扒谱的体验中,我最讨厌的就是被"x分音符"限制。用秒可以保证和原曲完全贴合,使用很灵活。但是这样导出的 MIDI 不能直接制谱。按照"x分音符"来绘制音符还会导致程序很难写。开发者和使用者都不快乐。
扒谱用秒为单位合适,而制谱用“x分音符”合适。为了跨越这个鸿沟,我这样设计了程序:使用midi文件作为对外的桥梁,在noteDigger内用秒为单位扒谱,导出为midi的时候根据小节进行量化,形成规整的midi用于制谱。具体实现是:在秒轴上加入小节轴,用户可以拖动小节轴的某个小节调节后面紧跟的bpm相同的小节。 > 因此老版本中量化对齐特别重要:小节线仅为视觉对齐辅助;而现在小节线以及内部的自动细分线,成为了节拍吸附模式下真正有用的吸附锚点。 ## 文件结构 ``` │ app.js: 最重要的文件,主程序 │ favicon.ico: 小图标 │ index.html: 程序入口, 其js主要是按钮的onclick │ jsconfig.json: 开发用 跨文件JS解析 │ LICENSE │ README.md │ ├─core: app.js用到的核心组件 │ app_analyser.js: 算法相关 │ app_audioplayer.js: 音频播放 │ app_beatbar.js: 小节轴 │ app_hscrollbar.js: 底部滑动条 │ app_io.js: 管理输入与输出 │ app_keyboard.js: 左侧键盘 │ app_midiaction.js: 与音符的交互 │ app_midiplayer.js: 音符播放 │ app_spectrogram.js: 频谱绘制 │ app_timebar.js: 时间轴 │ ├─lib │ beatBar.js: 节奏信息的稀疏存储 │ fakeAudio.js: 模拟了不会响的Audio,用于midi编辑器模式 │ midi.js: midi创建、解析类 │ saver.js: 二进制保存相关 │ snapshot.js: 快照类, 实现撤销和重做 │ tinySynth.js: 合成器类, 负责播放音频 | ├─ui │ channelDiv.js: 多音轨的UI界面类, 可拖拽列表 │ contextMenu.js: 右键菜单类 │ myRange.js: 横向滑动条的封装类 │ siderMenu.js: 侧边栏菜单类 │ ├─plugins │ chordEst.js │ pitchName.js | ├─dataProcess | | aboutANA.md: 自动音符对齐的数学建模 | | ANA.js: 自动音符对齐 │ │ bpmEst.js: 节奏分析 | │ analyser.js: 频域数据分析与简化 | │ fft_real.js: 执行实数FFT获取频域数据 | │ stftGPU.js: 使用WebGPU加速STFT | | NNLS.js: 非负最小二乘 用于去除谐波 | | | ├─AI │ │ │ AIEntrance.js: 开启AI的worker的入口 │ │ │ basicamt_44100.onnx: 音色无关转录 神经网络模型 │ │ │ basicamt_worker.js: 音色无关转录 新线程 │ │ │ postprocess.js:神经网络结果到音符的后处理 │ │ │ septimbre_44100.onnx: 音色分离转录 神经网络模型 │ │ │ septimbre_worker.js: 音色分离转录 新线程 │ │ │ SpectralClustering.js: 音色分离转录需要的 谱聚类 | │ │ | │ └─dist: onnxruntime打包 | │ bundle.min.js | │ ort-wasm-simd.wasm | | │ └─CQT │ cqt.js: 开启worker进行后台CQT │ cqt_worker.js: CQT类与新线程 │ ├─docs │ todo.md: 一些设计思路和权衡 │ ├─img │ bilibili-white.png │ github-mark-white.png │ logo-small.png │ logo.png │ logo_text.png │ └─style │ askUI.css: 达到类似效果 │ channelDiv.css: 多音轨UI样式 │ contextMenu.css: 右键菜单样式 │ myRange.css: 包装滑动条 │ siderMenu.css: 侧边菜单样式 │ style.css: index中独立元素的样式 │ └─icon: 从阿里图标库得到的icon iconfont.css iconfont.ttf iconfont.woff iconfont.woff2 ``` ## 重要更新记录 ### 2026 2 22 增加了和弦识别功能,并优化了项目结构。 ### 2026 2 14 利用NNLS完成了谐波的去除/基频的增强。
代码位于[reduceHarmonic](app_analyser.js)。原理为用谐波模板拟合频谱,进而得到谐波,并收集谐波的能量用于加强基频。该方法能大大增强基频的明显程度。 ### 2026 1 28 完成了基于WebGPU的STFT、CQT计算,即使在核显上也有显著加速。美中不足的是无法得知GPU算的进度,因此交互较弱
也尝试了利用CQT相位分析瞬时频率,但效果太鸡肋被放弃,相关代码在另一个分支。 ### 2026 1 23 更新了自动节奏检测功能,相关功能设置在“分析-节奏分析”中。
使用传统信号处理算法,**基于已经分析的频谱进行**,[原理点这](https://zhuanlan.zhihu.com/p/1995849093491222501)。目前节拍识别较为准确,但节奏型与重拍的跟踪(勾选“自动节奏型”)效果不佳。建议在CQT分析前后都进行一次(等10秒左右会发现频谱改变,改变前是STFT,改变后是CQT),基于STFT的节奏全局更准,基于CQT的局部更精确。目前的算法参数仅仅根据20帧/秒时调整,其他分辨率不保证效果。
为了让人工后处理更为便捷,在节奏栏右键增加了许多功能。 ### 2025 12 更新了音色无关转录模型,效果比之前好,且运行时间更短。
加入了音色分离转录,但是效果不怎么好,只适用于几个音色差异较大的简单场景,不同音色的音符不能重叠。推荐用于二重奏的情况,比如钢琴伴奏的某乐器独奏。 ### 2025 9 20 降低重绘频率,降低闲时CPU占用为原来的1/10。感谢[Initsnow的pr](https://github.com/madderscientist/noteDigger/pull/7)指出问题。
有三类地方会触发刷新: 1. 播放时保持高刷 在 `AudioPlayer.update` 中触发刷新 2. 所有键鼠操作。最初的想法是需要的地方触发刷新,但是牵扯的非常多—— - 快捷键。有些快捷键需要触发刷新,不如一刀切。 - 鼠标操作 - 在频谱画布上的操作:`MidiAction.updateView` 触发更新还不够(只负责了音符绘制模式),还有选择区域 - 在时间轴上的动作:重复区间 -> 可以在 `TimeBar.setRepeat` 中触发更新;设置节拍 -> 可以在回调中触发更新 - 在钢琴画布上的动作:垂直方向移动,回调触发即可 - 画布之外的操作 只能设置统一的api;而音轨操作这种却不好加 - 没考虑到的功能——谁知道漏了会发生什么问题 综合考虑下,选择终极一刀切——所有用户操作都会触发刷新,仅需额外添加回调,不需要考虑具体动作,便于维护。 3. `MidiAction.updateView` 处理一切音符变化。之所以不能被键鼠操作取代,因为ai扒谱延迟修改了音符。
由于`scroll2`调用了`updateView`,因此还覆盖了`resize`、Spectrogram setter ### 2025 8 21 实现了自动音符对齐(auto note alignment),输入数字谱,得到和音频同步的音符,即“数字谱+音频→midi”。入口为:“分析”-“数字谱对齐音频”,输入单声部的数字谱,并调整八度范围,确定即可。注意,"1"对应的是C5,比常规约定高了八度,这是因为我发现往往分析泛音更为准确。如果效果不好,可以通过前后增加中/小括号实现八度升降。
效果并不优秀,因为使用了传统的数学建模方法,但胜在计算量小。相关说明与建模见[aboutANA.md](./dataProcess/aboutANA.md)。
2025/12/27 将此算法整理为[文章](https://zhuanlan.zhihu.com/p/1988276192063800011)。 ### 2025 8 14 项目代码的整理,将功能拆分到单独文件(虽然模块间仍未解耦,但终于拆分了!),并增加了开发配置文件(感觉TS是对的啊!但放不下JS里面的奇技淫巧)。
修复了陈年bug:调整小节时不时“拉不动”、STFT偏早。 ### 2025 8 12 进行了频谱的归一化,便于后续的研究与分析。归一化基于能量谱,同[timbreAMT](https://github.com/madderscientist/timbreAMT/blob/main/model/CQT.py)的做法,简而言之:令每一帧的能量的方差为1。
重大的改动:WASM的CQT → JS的CQT。早期实验发现两者用时接近,为了纪念第一次使用WASM加速而保留。但升级CPU后发现JS版本用时不到WASM的一半,而且代码更少、文件更小。遂欣然废除。若要学习“C++编译为WASM”可以查看此前的历史提交。 ### 2025 3 25 引入了“自动音乐转录”,即“AI扒谱”,导入音频后(或进入MIDI编辑器模式)在“分析”页面点击“**人工智障扒谱**”选项,一首两分半的曲子大概需要半分钟分析。由于追求低内存开销,我没保存音频数据,因此AI扒谱前要重新选择文件。
使用的模型是我毕设的一部分,设计与训练过程请查看[timbreAMT](https://github.com/madderscientist/timbreAMT)的basicamt文件夹,我称之为“音色无关转录”,即不会根据乐器种类分轨输出,但对大部分音色有适用性。对标的是basicPitch,效果接近且更加轻量,但无论是我的还是他的,结果都仅仅能听,而我的相比basicPitch优点在于集成在了noteDigger中,可以便捷地进行人工后处理,如删去多余音符、对齐节奏等。
为了支持人工后处理,有了前几次更新,最重要的是: 1. 音符力度用透明度体现,便于用户看清AI扒谱结果中重要的音符。在“设置”中可以关掉透明度。 2. 音轨的锁,用于锁定AI扒谱结果,用户可以在新的音轨中“描”一遍,相当于把AI扒谱结果当做频谱。 ### 2024 8 29 引入了理论上更精确的CQT分析。非file协议时(不是双击html文件打开时),当STFT(默认的计算方法)计算完成会在后台自动开启CQT计算,CQT结果将与当前频谱融合(会发现突然频谱变了)。CQT计算非常慢,因此在后台计算以防阻塞,且用C++实现、编译为WASM以提速。
中途遇到很多坑,记录分布在/dataProcess/CQT的各个文件中,但效果其实并不值得这样的计算量。5分30秒的音频进行双声道CQT分析,需要45秒(从开启worker开始算),和直接进行js版的CQT用时差不多,加速了个寂寞。
关于CQT的研究,记录在[《CQT:从理论到代码实现》](https://zhuanlan.zhihu.com/p/716574483)。
此外尝试了“一边分析一边绘制频谱”,试图通过删除进度条达到感官上加速的效果。但是放在主线程造成严重卡顿,放弃。 ### 2024 8 2 完成了issue2:不导入音频的midi编辑器。点击文件菜单下的“MIDI编辑器模式”就可以进入。
视野的宽度取决于最后一个音符,模仿的是[signal](https://signal.vercel.app/edit)。也尝试过自动增加视野,可以一直往右拉,但是这样在播放的时候,开启“自动翻页”会永远停不下来(翻一页就自动拓展宽度)。
扒谱框架下的midi编辑器还是有些反人类,因为绘制音符时的单位是时间而不是x分音符。不过也能用。
原理是实现了一个空壳的Audio,只有计时功能,没有发声功能。一些做法写在了todo.md上。 ### 2024 2 22 加入了节拍对齐功能,使用逻辑是:扒谱界面提供视觉辅助,导出midi会自动对齐,以实现制谱友好。详细对齐的原理请参看“关于节奏对齐”板块和midiExport.js文件。
有一些细节:
1. 如果每个小节bpm都不一样(原曲的速度不稳,有波动),那导出midi前的对齐操作会以上一小节bpm为基准进行动态适应:先根据本小节的bpm量化音符为"x分音符",如果本小节bpm和上一小节的bpm差别在一定范围内,则再将"x分音符"的bpm设置全局量BPM;否则将全局BPM设置为当前小节的bpm。这个算法的要求是:的确要变速的前后bpm差异应该较大。
2. 在一个小节内,音符的近似方法: 1. 记一个四分音符的格数为aqt(因为音符的实际使用单位是格。这里隐含了一个时间到格数的变换),某时刻t对应音符长度为ntlen,小节开始时刻记为mt。首先获取音符时刻相对小节开头的位置nt=t-mt。(音符时刻:将一个音符拆分为开始时刻和结束时刻。一个音符可能跨好几个小节,因此这样处理最为合适) 2. 假设前提:时长长的音符的起点和终点的精度也低(精度这里指最小单位时长,低精度指单位时长对应的实际时间长)。因此近似精度accu采用自适应的方式:该音符可以用(ntlen/aqt)个四份音符表示,设其可以用一个(4*2^n)分音符近似,其中n满足:(1/2)^n<=ntlen/aqt<(1/2)^(n-1),则该音符的时长为aqt/(2^n),则精度设置为这个近似音符的一半:accu = aqt/(2^(n+1))。比如四份音符的精度是一个八分音符的时长。 3. 近似后的时刻为:round(nt/accu)*accu。同时设置一个最低精度:八分音符。因此accu=min(aqt/2, aqt/(2^(n+1))),其中(1/2)^n<=ntlen/aqt<(1/2)^(n-1)。 3. 小节信息如何存储、数据结构如何设计需要好好想想。大部分情况下(在原音频节奏稳定的情况下)只会变速几次,此时存变动时刻的bpm值就足矣。极端情况下每个小节都单独设置了bpm。如何设计数据结构能在两种情况下都取得较好的性能?使用稀疏数组。 ### 2024 2 9 在今年完成了所有基本功能!本次更新了设置相关,简单地设计了调性分析的算法,已经完全可以用了!【随后在bilibil投稿了视频】 ### 2024 2 8 文件系统已经完善!已经可以随心所欲导入导出保存啦!同时修复了一些小bug、完善了一些api。
界面上,本打算将文件相关选项放到logo上,但是侧边菜单似乎有些空了,于是就加入到侧边栏,而logo设置为刷新或开新界面(考察了其他网站的logo的用途)。同时给侧边菜单加入了“设置”和“分析”,但本次更新没做。
midi相关操作来自[我的另一个项目](https://github.com/madderscientist/je_score_operator)的midi类。将用midi转的wav导入分析,再导入原midi,两者同步播放的感觉真好! ### 2024 2 5 已经能用于扒谱了!完成了midi和原曲的播放与同步,填补了扒谱过程最重要的一环。
UI基本完成!将侧边栏、滑动条封装成了js类。在此基础上,设计了类似VScode的菜单,用于存放不常用的功能和界面;而顶部窄窄一条用于放置常用功能。
此外,完成了logo的设计。在2月4日的commit记录中(因为现在已经删除)可以看到设计的多种logo,最终选定了“在勺子里的音符”,这是一个被勺子dig出来的音符。其他思路可以概括为:“音符和铲子的组合”(logo2)、“埋在地里的音符”(logo5 logo6)、“像植物一样生长的八分音符”(logo8 logo10)、“音符和铲子结合”(logo12)。 ### 2024 2 1 完成了多音轨、合成器和主线的整合,象征着midi系统的完成!
统一了UI风格;完善了快捷键功能;新增框选功能;修复了大部分bug。 ### 2024 1 30 完成了midi合成器tinySynth.js,实现了128种音色的播放。只有演奏音符的作用,控制器一点没做。
原理是多个基础波形合成一个音色。波形参数来自 https://github.com/g200kg/webaudio-tinysynth ,因此程序设计也参考了它的设计。修改记录在todo.md中
对于reference的解析(作者注释一点没写,变量命名极为简单,因此主要是变量解释)存放于“./tone/解析.md”(文件夹已被删除,请去历史提交查看)。文件夹中还有tinySynth的测试页面。在下一次push时将删除tone文件夹。
这段时间内还完成了以下内容(全部记录在commit history的comments内): - 基本程序界面(三个画布:键盘、时频图、时间轴;UI界面:右键菜单、多音轨、滑动条) - 基本逻辑功能:音符交互绘制、快捷键以及模块的关联协同 ### 2023 12 13 从11月14日开始造js版fft轮子起,时隔一个月第一次提交项目,因为项目逻辑日渐复杂,需要能及时回退。主要完成了频谱绘制、钢琴键盘绘制、数据处理三部分,并初步确定了程序的结构框架。
数据处理核心:实数FFT,编写于我《数字信号处理》刚刚学完FFT算法之时,针对本项目的应用场景做了专门的设计,即针对音频STFT做了适配,具体表现为:实数加速、数据预计算、空间预分配、共用数组。
由于整个项目还没搭建起来,因此不能测试NoteAnalyser类的数据处理效果。此类用于将频域数据进一步离散为音符强度数据。
关于程序结构有一版废案,在文件夹"deprecated"中,设计思路是解耦、插件化,废弃理由是根本解耦不了。因此现在的代码耦合成一坨了。这个文件夹将在下一次push时被删除,存活于历史提交之中。
tone文件夹将存放我的合成器轮子,audioplaytest是我音频播放的实验文件夹,todo.md是部分设计思路。
2024/4/8补记:时频分析方法是STFT,但是面临时间和频率分辨率矛盾的问题,现在的分析精度只能到F#2。解决办法是用小波变换,或者更本质一点:用84个滤波器提取84个基准音以及其周围的频率的能量。这样能达到更高的频率分辨率和时间分辨率。但是现在的STFT用起来效果还可以,就不换了哈。 ================================================ FILE: app.js ================================================ // 用这种方式(原始构造函数)的原因:解耦太难了,不解了。this全部指同一个。其次为了保证效率 // 防止在html初始化之前getElement,所以封装成了构造函数,而不是直接写obj function App() { this.event = new EventTarget(); // 键盘和时间轴 其绘制由工作区管理 this.keyboard = document.getElementById('piano'); this.keyboard.ctx = this.keyboard.getContext('2d', { alpha: false, desynchronized: true }); this.timeBar = document.getElementById('timeBar'); this.timeBar.ctx = this.timeBar.getContext('2d', { alpha: false, desynchronized: true }); // 工作区图层 this.layerContainer = document.getElementById('main-layers'); this.layers = this.layerContainer.layers = { spectrum: LayeredCanvas.new2d('spectrum', false), action: LayeredCanvas.new2d('actions', true) }; Object.defineProperty(this.layers, 'width', { get: function () { return this.spectrum.width; }, set: function (w) { for (const c in this) this[c].width = w; }, enumerable: false }); Object.defineProperty(this.layers, 'height', { get: function () { return this.spectrum.height; }, set: function (h) { for (const c in this) this[c].height = h; }, enumerable: false }); Object.defineProperty(this.layers, 'addLayer', { value: (name, zIndex) => { if (this.layers[name]) return this.layers[name]; const canvas = document.createElement('canvas'); canvas.style.zIndex = zIndex; this.layerContainer.appendChild(canvas); return this.layers[name] = LayeredCanvas.new2d(canvas, true); }, enumerable: false }); Object.defineProperty(this.layers, 'removeLayer', { value: (name, zIndex) => { if (this.layers[name]) { this.layers[name].canvas.remove(); delete this.layers[name]; } }, enumerable: false }); this.layers.action.mask = '#25262da8'; Object.defineProperty(this.layers.action, 'Alpha', { get: function() { return parseInt(this.mask.substring(7), 16); }, set: function(a) { a = Math.min(255, Math.max(a | 0, 0)); this.mask = '#25262d' + a.toString(16).padStart(2, '0'); this.dirty = true; }, enumerable: false }); this.midiMode = false; this.TperP = -1; // 每个像素代表的ms this.PperT = -1; // 每ms代表的像素 this._width = 5; // 每格的宽度 Object.defineProperty(this, 'width', { get: function () { return this._width; }, set: function (w) { if (w <= 0) return; this._width = w; this.TimeBar.updateInterval(); this.HscrollBar.refreshSize(); // 刷新横向滑动条 this.TperP = this.dt / this._width; this.PperT = this._width / this.dt; this.Spectrogram.onresize(); } }); this._height = 15; // 每格的高度 Object.defineProperty(this, 'height', { get: function () { return this._height; }, set: function (h) { if (h <= 0) return; this._height = h; this.Keyboard.setYchange(h); this.keyboard.ctx.font = `${h + 2}px Arial`; this.layers.action.ctx.font = `${h}px Arial`; this.Spectrogram.onresize(); } }); this.ynum = 84; // 一共84个按键 this._xnum = 0; // 时间轴的最大长度 Object.defineProperty(this, 'xnum', { // midi模式下需要经常改变此值,故特设setter get: function () { return this._xnum; }, set: function (n) { if (n <= 0) return; this._xnum = n; // 刷新横向滑动条 this.HscrollBar.refreshPosition(); this.HscrollBar.refreshSize(); this.idXend = Math.min(this._xnum, Math.ceil((this.scrollX + this.layers.width) / this._width)); } }); this.dt = 50; // 每次分析的时间间隔 单位毫秒 在this.Analyser.stft this.io.onfile this.io.projFile.import 中更新 this.time = -1; // 当前时间 单位:毫秒 在this.AudioPlayer.update中更新 // 以下变量仅在scroll2中更新(特别标记的除外) this.scrollX = 0; // 视野左边和世界左边的距离 this.scrollY = 0; // 视野下边和世界下边的距离 this.idXstart = 0; // 开始的X序号 this.idYstart = 0; // 开始的Y序号 this.idXend = 0; // 【还在 xnum setter 中更新】 this.idYend = 0; this.rectXstart = 0;// 目前只有Spectrogram.update在使用 this.rectYstart = 0;// 画布开始的具体y坐标(因为最下面一个不完整) 迭代应该减height 被画频谱、画键盘共享 // spectrum的重绘仅在 视野滚动(scroll2) 数据改变(会触发scroll2) 倍率改变 // 下面的函数控制action层的重绘 重绘时机: scroll2; AudioPlayer.update; 键鼠操作 this.makeActDirty = () => { this.layers.action.dirty = true; }; // 供外部调用 /** * 设置播放时间 如果立即播放(keep==false)则有优化 * @param {number} t 时间点 单位:毫秒 * @param {boolean} keep 是否保存之前的状态 如果为false则立即开始 */ this.setTime = (t, keep = true) => { this.synthesizer.stopAll(); if (keep) { this.time = t; this.AudioPlayer.audio.currentTime = t / 1000; this.AudioPlayer.play_btn.firstChild.textContent = this.TimeBar.msToClockString(t); this.MidiPlayer.restart(); } else { // 用于双击时间轴立即播放 this.AudioPlayer.start(t); // 所有操作都在start中 } }; this._mouseY = 0; // 鼠标当前y坐标 Object.defineProperty(this, 'mouseY', { get: function () { return this._mouseY; }, set: function (y) { this._mouseY = y; this.Keyboard.highlight = Math.floor((this.scrollY + this.layers.height - y) / this._height) + 24; } }); this._mouseX = 0; // 鼠标当前x坐标 Object.defineProperty(this, 'mouseX', { get: function () { return this._mouseX; }, set: function (x) { this._mouseX = x; this.MidiAction.frameXid = Math.floor((x + this.scrollX) / this._width); } }); this.preventShortCut = false; // 当需要原始快捷键时(比如输入框)修改此为true this.audioContext = new AudioContext({ sampleRate: 44100 }); this.synthesizer = new TinySynth(this.audioContext); this.Spectrogram = new _Spectrogram(this); this.MidiAction = new _MidiAction(this); this.MidiPlayer = new _MidiPlayer(this); this.AudioPlayer = new _AudioPlayer(this); this.Keyboard = new _Keyboard(this); this.height = this._height; // 更新this.Keyboard._ychange this.TimeBar = new _TimeBar(this); this.BeatBar = new _BeatBar(this); // 撤销相关 this.snapshot = new Snapshot(16, { // 用对象包裹,实现字符串的引用 midi: { value: JSON.stringify(this.MidiAction.midi) }, // 音符移动、长度改变、channel改变后 channel: { value: JSON.stringify(this.MidiAction.channelDiv.channel) }, // 音轨改变序号、增删、修改参数后 beat: { value: JSON.stringify(this.BeatBar.beats) } }); // changed = channel变化<<1 | midi变化<<2 | beat变化<<3 this.snapshot.save = (changed = 0b111) => { const nowState = this.snapshot.nowState(); const lastStateNotExists = nowState == null; this.snapshot.add({ channel: (lastStateNotExists || (changed & 0b1)) ? { value: JSON.stringify(this.MidiAction.channelDiv.channel) } : nowState.channel, midi: (lastStateNotExists || (changed & 0b10)) ? { value: JSON.stringify(this.MidiAction.midi) } : nowState.midi, beat: (lastStateNotExists || (changed & 0b100)) ? { value: JSON.stringify(this.BeatBar.beats) } : nowState.beat }); }; this.HscrollBar = new _HscrollBar(this); this._copy = ''; // 用于复制音符 会是JSON字符串 this.shortcutActions = { // 快捷键动作 'Ctrl+Z': () => { // 撤销 let lastState = this.snapshot.undo(); if (!lastState) return; this.MidiAction.midi = JSON.parse(lastState.midi.value); this.MidiAction.selected = this.MidiAction.midi.filter((obj) => obj.selected); this.MidiAction.channelDiv.fromArray(JSON.parse(lastState.channel.value)); this.BeatBar.beats.copy(JSON.parse(lastState.beat.value)); this.MidiAction.updateView(); }, 'Ctrl+Y': () => { let nextState = this.snapshot.redo(); if (!nextState) return; this.MidiAction.midi = JSON.parse(nextState.midi.value); this.MidiAction.selected = this.MidiAction.midi.filter((obj) => obj.selected); this.MidiAction.channelDiv.fromArray(JSON.parse(nextState.channel.value)); this.BeatBar.beats.copy(JSON.parse(nextState.beat.value)); this.MidiAction.updateView(); }, 'Ctrl+A': () => { // 选中该通道的所有音符 let ch = this.MidiAction.channelDiv.selected; if (ch) { ch = ch.index; this.MidiAction.midi.forEach((note) => { note.selected = note.ch == ch; }); this.MidiAction.selected = this.MidiAction.midi.filter((nt) => nt.selected); } else this.shortcutActions['Ctrl+Shift+A'](); }, 'Ctrl+Shift+A': () => { // 真正意义上的全选 this.MidiAction.midi.forEach((note) => { note.selected = true; }); this.MidiAction.selected = [...this.MidiAction.midi]; }, 'Ctrl+D': () => { // 取消选中 this.MidiAction.clearSelected(); }, 'Ctrl+C': () => { if (this.MidiAction.selected.length == 0) return; this._copy = JSON.stringify(this.MidiAction.selected); }, 'Ctrl+X': () => { if (this.MidiAction.selected.length == 0) return; this._copy = JSON.stringify(this.MidiAction.selected); this.MidiAction.deleteNote(); // deleteNote会更新view和存档 }, 'Ctrl+V': () => { if (!this._copy) return; // 空字符串或null const ch = this.MidiAction.channelDiv.selected; if (!ch) { alert("请先选择一个音轨!"); return; } let chid = ch.index; let copy = JSON.parse(this._copy); // 找到第一个 let minX = Infinity; copy.forEach((note) => { note.ch = chid; note.selected = true; if (note.x1 < minX) minX = note.x1; }); this.MidiAction.clearSelected(); this.MidiAction.selected = copy; // 粘贴到光标位置 minX = (this.time / this.dt - minX) | 0; copy.forEach((note) => { note.x1 += minX; note.x2 += minX; }); this.MidiAction.midi.push(...copy); this.MidiAction.midi.sort((a, b) => a.x1 - b.x1); this.MidiAction.updateView(); this.snapshot.save(0b10); // 只保存midi的快照 }, 'Ctrl+B': () => { // 收回面板 const channelDiv = this.MidiAction.channelDiv.container.parentNode; if (channelDiv.style.display == 'none') { channelDiv.style.display = 'block'; } else { channelDiv.style.display = 'none'; } this.resize(); } }; /** * 改变工作区(频谱、键盘、时间轴)大小 * @param {number} w 工作区的新宽度 默认充满父容器 * @param {number} h 工作区的新高度 默认充满父容器 * 充满父容器,父容器需设置flex:1;overflow:hidden; */ this.resize = (w = undefined, h = undefined) => { const box = document.getElementById('Canvases-Container').getBoundingClientRect(); w = w || box.width; h = h || box.height; let spectrumWidth, spectrumHeight; if (w > 80) { spectrumWidth = w - 80; this.keyboard.width = 80; } else { spectrumWidth = 0.4 * w; this.keyboard.width = 0.6 * w; } if (h > 40) { spectrumHeight = h - 40; this.timeBar.height = 40; } else { spectrumHeight = 0.4 * h; this.timeBar.height = 0.6 * h; } this.keyboard.height = spectrumHeight; this.timeBar.width = spectrumWidth; for (const c in this.layers) { const canvas = this.layers[c]; canvas.width = spectrumWidth; canvas.height = spectrumHeight; canvas.ctx.lineWidth = 1; canvas.ctx.font = `${this._height}px Arial`; } document.getElementById('play-btn').style.width = this.keyboard.width + 'px'; // 改变画布长宽之后,设置的值会重置,需要重新设置 this.keyboard.ctx.lineWidth = 1; this.keyboard.ctx.font = `${this._height + 2}px Arial`; this.timeBar.ctx.font = '14px Arial'; // 触发滑动条/频谱缓冲区更新 还能在初始化的时候保证timeBar的文字间隔 this.width = this._width; this.scroll2(); }; /** * 移动到 scroll to (x, y) * 由目标位置得到合法的scrollX和scrollY,并更新XY方向的scroll离散值起点(序号) * @param {number} x 新视野左边和世界左边的距离 * @param {number} y 新视野下边和世界下边的距离 */ this.scroll2 = (x = this.scrollX, y = this.scrollY) => { this.scrollX = Math.max(0, Math.min(x, this._width * this._xnum - this.layers.width)); this.scrollY = Math.max(0, Math.min(y, this._height * this.ynum - this.layers.height)); this.idXstart = (this.scrollX / this._width) | 0; this.idYstart = (this.scrollY / this._height) | 0; this.idXend = Math.min(this._xnum, Math.ceil((this.scrollX + this.layers.width) / this._width)); this.idYend = Math.min(this.ynum, Math.ceil((this.scrollY + this.layers.height) / this._height)); this.rectXstart = this.idXstart * this._width - this.scrollX; this.rectYstart = this.layers.height - this.idYstart * this._height + this.scrollY; // 画图的y从左上角开始 // 滑动条 this.HscrollBar.refreshPosition(); // 更新音符 action.dirty 置位 this.MidiAction.updateView(); this.layers.spectrum.dirty = true; }; /** * 按倍数横向缩放时频图 以鼠标指针为中心 * @param {number} mouseX * @param {number} times 倍数 比用加减像素好,更连续 */ this.scaleX = (mouseX, times) => { let nw = this._width * times; if (nw < 1) return; if (nw > this.layers.spectrum.width) return; this.width = nw; this.scroll2((this.scrollX + mouseX) * times - mouseX, this.scrollY); }; /** * 状态更新与重绘 */ this.update = () => { this.AudioPlayer.update(); this.MidiPlayer.update(); for (const c in this.layers) this.layers[c].render() }; this.layers.spectrum.resetHandlers([this.Spectrogram.render]); this.layers.action.resetHandlers([ c => { // 绘制遮罩 let ctx = c.ctx; ctx.globalCompositeOperation = 'copy'; ctx.fillStyle = c.mask; ctx.fillRect(0, 0, c.width, c.height); ctx.globalCompositeOperation = 'source-over'; }, this.Keyboard.render,// 应最先 因为高亮显示不重要应该在最下面 this.BeatBar.render, this.MidiAction.render,// 应在BeatBar之后 节拍线在音符下面 this.TimeBar.render,// 应最后 时间指针应该在最上面 ]); this.trackMouseY = (e) => { // onmousemove this.mouseY = e.offsetY; }; this.trackMouseX = (e) => { // 用于框选,会更新frameX值 在this.MidiAction中add和remove事件监听器 this.mouseX = e.offsetX; }; this._trackMouseX = (e) => {// 给pitchName插件专用的 只会更新_mouseX this._mouseX = e.offsetX; }; /** * 动画循环绘制 * @param {boolean} loop 是否开启循环 */ this.loopUpdate = (loop = true) => { if (loop) { const update = (t) => { this.update(); this.loop = requestAnimationFrame(update); }; // 必须用箭头函数包裹,以固定this的指向 this.loop = requestAnimationFrame(update); } else { cancelAnimationFrame(this.loop); } }; this.loop = 0; // 接收requestAnimationFrame的返回 //=========数据解析相关=========// this.Analyser = new _Analyser(this); //========= 导入导出 =========// this.io = new _IO(this); //========= 事件注册 =========// document.getElementById('speedControl').addEventListener('input', (e) => { // 变速 this.AudioPlayer.audio.playbackRate = parseFloat(e.target.value); }); document.getElementById('multiControl').addEventListener('input', (e) => { // 变画频谱的倍率 this.Spectrogram.multiple = parseFloat(e.target.value); }); document.getElementById('contrastControl').addEventListener('input', (e) => { // 变频谱对比度 this.Spectrogram.contrast = parseFloat(e.target.value); }); document.getElementById('midivolumeControl').addEventListener('input', (e) => { // midi音量 this.synthesizer.out.gain.value = parseFloat(e.target.value) ** 2; }); document.getElementById('audiovolumeControl').addEventListener('input', (e) => {// 音频音量 this.AudioPlayer.audio.volume = parseFloat(e.target.value); }); document.addEventListener('keydown', (e) => { // 键盘事件 // 以下在没有频谱数据时不启用 if (this.preventShortCut) return; if (!this.Spectrogram._spectrogram) return; let shortcut = ''; // 检测平台并使用相应的修饰键 const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const cmdKey = isMac ? e.metaKey : e.ctrlKey; const ctrlKey = isMac ? e.ctrlKey : false; if (cmdKey) shortcut += 'Ctrl+'; // 统一使用Ctrl+标识符,但实际检测平台对应的键 if (ctrlKey && isMac) shortcut += 'RealCtrl+'; // Mac上的真正Ctrl键 if (e.shiftKey) shortcut += 'Shift+'; if (e.altKey) shortcut += 'Alt+'; if (shortcut != '') { // 组合键 shortcut += e.key.toUpperCase(); // 大小写一视同仁 if (this.shortcutActions.hasOwnProperty(shortcut)) { e.preventDefault(); // 阻止默认的快捷键行为 this.shortcutActions[shortcut](); } } else { // 单个按键 switch (e.key) { case 'ArrowUp': this.scroll2(this.scrollX, this.scrollY + this._height); break; case 'ArrowDown': this.scroll2(this.scrollX, this.scrollY - this._height); break; case 'ArrowLeft': this.scroll2(this.scrollX - this._width, this.scrollY); break; case 'ArrowRight': this.scroll2(this.scrollX + this._width, this.scrollY); break; case 'Delete': this.MidiAction.deleteNote(); break; case ' ': this.AudioPlayer.play_btn.click(); break; case 'PageUp': this.scroll2(this.scrollX - this.layers.spectrum.width, this.scrollY); break; case 'PageDown': this.scroll2(this.scrollX + this.layers.spectrum.width, this.scrollY); break; case 'Home': this.scroll2(0); this.setTime(0); break; } } }); // audio可以后台播放,但是requestAnimationFrame不行,而时间同步在requestAnimationFrame中 // 还有一个办法:在可见状态变化时,将update绑定到audio.ontimeupdate上,但是这个事件触发频率很低,而预测器根据60帧设计的 document.addEventListener('visibilitychange', () => { if (document.hidden) this.AudioPlayer.stop(); }); window.addEventListener('load', () => { this.resize(); }); window.addEventListener('resize', () => { this.resize(); }); this.layerContainer.addEventListener('wheel', (e) => { // e.deltaY 往前滚是负数 const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const cmdKey = isMac ? e.metaKey : e.ctrlKey; if (cmdKey) { // 缩放 e.preventDefault(); this.scaleX(e.offsetX, e.deltaY > 0 ? 0.8 : 1.25); } else if (e.shiftKey) { // 垂直滚动 // 只有鼠标滚轮时是有deltaY。所以这里让X方向能移动,做法是交换X和Y this.scroll2(this.scrollX + e.deltaY, this.scrollY + e.deltaX); } else { // 触摸板的滑动也是wheel this.scroll2(this.scrollX + e.deltaX, this.scrollY - e.deltaY); } // 只改状态,但不绘图。绘图交给固定时间刷新完成 this.trackMouseY(e); }); this.layerContainer.contextMenu = new ContextMenu([ { name: "撤销", callback: () => { this.shortcutActions['Ctrl+Z'](); }, onshow: () => this.Spectrogram._spectrogram && this.snapshot.lastState() }, { name: "重做", callback: () => { this.shortcutActions['Ctrl+Y'](); }, onshow: () => this.Spectrogram._spectrogram && this.snapshot.nextState() }, { name: "粘贴", callback: () => { this.shortcutActions['Ctrl+V'](); }, onshow: () => this.Spectrogram._spectrogram && this._copy != '' }, { name: "复制", callback: () => { this.shortcutActions['Ctrl+C'](); }, onshow: () => this.Spectrogram._spectrogram && this.MidiAction.selected.length > 0 }, { name: "反选", callback: () => { let ch = this.MidiAction.channelDiv.selected; let id = ch && ch.index; ch = !ch; for (const nt of this.MidiAction.midi) nt.selected = (ch || nt.ch == id) && !nt.selected; this.MidiAction.selected = this.MidiAction.midi.filter(nt => nt.selected); }, onshow: () => this.Spectrogram._spectrogram }, { name: '删除', callback: () => { this.MidiAction.deleteNote(); }, onshow: () => this.Spectrogram._spectrogram && this.MidiAction.selected.length > 0 } ]); this.layerContainer.addEventListener('mousedown', (e) => { if (e.button == 1) { // 中键按下 动作同触摸板滑动 视窗移动 const moveWindow = (e) => { this.scroll2(this.scrollX - e.movementX, this.scrollY + e.movementY); }; this.layerContainer.addEventListener('mousemove', moveWindow); const up = () => { this.layerContainer.removeEventListener('mousemove', moveWindow); document.removeEventListener('mouseup', up); }; document.addEventListener('mouseup', up); return; } // 以下在没有频谱数据时不启用 if (this.Spectrogram._spectrogram) { if (e.button == 0) this.MidiAction.onclick_L(e); // midi音符相关 else if (e.button == 2 && e.shiftKey) { this.layerContainer.contextMenu.show(e); e.stopPropagation(); } else this.MidiAction.clearSelected(); // 取消音符选中 } this.Keyboard.mousedown(); // 将发声放到后面,因为onclick_L会改变选中的音轨 }); this.layerContainer.addEventListener('mousemove', this.trackMouseY); this.layerContainer.addEventListener('contextmenu', (e) => { e.preventDefault(); e.stopPropagation(); }); this.timeBar.addEventListener('dblclick', (e) => { if (this.AudioPlayer.audio.readyState != 4) return; this.setTime((e.offsetX + this.scrollX) * this.AudioPlayer.audio.duration * 1000 / (this._xnum * this._width), false); }); this.timeBar.addEventListener('contextmenu', (e) => { e.preventDefault(); // 右键菜单 if (e.offsetY < this.timeBar.height >> 1) this.TimeBar.contextMenu.show(e); else this.BeatBar.contextMenu.show(e); e.stopPropagation(); }); this.timeBar.addEventListener('mousemove', this.BeatBar.moveCatch); this.timeBar.addEventListener('mousedown', (e) => { switch (e.button) { case 0: if (this.BeatBar.belongID > -1) { // 在小节轴上 let _anyAction = false; // 是否存档 this.timeBar.removeEventListener('mousemove', this.BeatBar.moveCatch); const m = this.BeatBar.beats.setMeasure(this.BeatBar.belongID, undefined, false); const startAt = m.start * this.PperT; let setMeasure; if (e.shiftKey) { // 只改变小节线位置 const nextM = this.BeatBar.beats.setMeasure(m.id + 1, undefined, false); this.BeatBar.beats.setMeasure(m.id + 2, undefined, false); // 下下个也要创建 setMeasure = (e2) => { _anyAction = true; m.interval = Math.max(100, (e2.offsetX + this.scrollX - startAt) * this.TperP); nextM.interval -= m.start + m.interval - nextM.start; this.BeatBar.beats.check(false); }; } else { // 改变小节线位置并移动后续小节 setMeasure = (e2) => { _anyAction = true; m.interval = Math.max(100, (e2.offsetX + this.scrollX - startAt) * this.TperP); this.BeatBar.beats.check(false); // 关闭小节合并 否则会丢失小节对象 }; } let removeEvents = () => { document.removeEventListener('mousemove', setMeasure); this.timeBar.addEventListener('mousemove', this.BeatBar.moveCatch); document.removeEventListener('mouseup', removeEvents); this.BeatBar.beats.check(true); if (_anyAction) this.snapshot.save(0b100); }; document.addEventListener('mousemove', setMeasure); document.addEventListener('mouseup', removeEvents); } else { const x = (e.offsetX + this.scrollX) / this._width * this.dt; // 毫秒数 const originStart = this.TimeBar.repeatStart; const originEnd = this.TimeBar.repeatEnd; const mouseDownX = e.offsetX; let mouseUpX = mouseDownX; const setRepeat = (e) => { mouseUpX = e.offsetX; const newX = (e.offsetX + this.scrollX) / this._width * this.dt; if (newX > x) this.TimeBar.setRepeat(x, newX); else this.TimeBar.setRepeat(newX, x); }; let removeEvents = () => { this.timeBar.removeEventListener('mousemove', setRepeat); document.removeEventListener('mouseup', removeEvents); // 有时候双击的小小移动会误触重复区间 所以如果区间太小则忽视 if (Math.abs(mouseUpX - mouseDownX) < 6) this.TimeBar.setRepeat(originStart, originEnd); }; this.timeBar.addEventListener('mousemove', setRepeat); document.addEventListener('mouseup', removeEvents); } break; case 1: // 中键跳转位置但不改变播放状态 this.setTime((e.offsetX + this.scrollX) / this._width * this.dt); break; } }); this.keyboard.addEventListener('wheel', (e) => { this.scroll2(this.scrollX, this.scrollY - e.deltaY); // 只能上下移动 }); this.keyboard.addEventListener('mousemove', this.trackMouseY); this.keyboard.addEventListener('contextmenu', (e) => { e.preventDefault(); e.stopPropagation(); }); this.keyboard.addEventListener('mousedown', (e) => { if (e.button == 1) { // 中键按下 动作同触摸板滑动 视窗移动 const moveWindow = (e) => { this.scroll2(this.scrollX, this.scrollY + e.movementY); }; this.keyboard.addEventListener('mousemove', moveWindow); const up = () => { this.keyboard.removeEventListener('mousemove', moveWindow); document.removeEventListener('mouseup', up); }; document.addEventListener('mouseup', up); return; } this.Keyboard.mousedown(); }); // 用户鼠标操作触发刷新 document.addEventListener('mousemove', this.makeActDirty); document.addEventListener('mousedown', this.makeActDirty); document.addEventListener('mouseup', this.makeActDirty); document.addEventListener('keydown', this.makeActDirty); // wheel->scroll2 已触发刷新 this.loopUpdate(true); } class LayeredCanvas extends HTMLCanvasElement { static new2d(canvas, alpha = true, desynchronized = true) { if (typeof canvas === 'string') canvas = document.getElementById(canvas); return LayeredCanvas.new(canvas, '2d', {alpha, desynchronized, willReadFrequently: false}); } static new(canvas, contextType = '2d', contextAttributes) { Object.setPrototypeOf(canvas, LayeredCanvas.prototype); canvas.init(contextType, contextAttributes); return canvas; } init(contextType, contextAttributes) { this.ctx = this.getContext(contextType, contextAttributes); this.handlers = []; // [{handler, priority}] this.dirty = true; } resetHandlers(handlers) { this.handlers = handlers .filter(handler => typeof handler === 'function') .map((handler, i) => ({handler, priority: i})); } /** * 注册渲染函数 * @param {function(LayeredCanvas): void} handler * @param {number} priority 优先级越小越先执行 */ register(handler, priority = null) { if (priority === null) { if (this.handlers.length) priority = this.handlers[this.handlers.length - 1].priority + 1; else priority = 0; } this.handlers.push({handler, priority}); this.handlers.sort((a, b) => a.priority - b.priority); } unregister(handler) { this.handlers = this.handlers.filter(h => h.handler !== handler); } render() { if (!this.dirty) return; for (const {handler} of this.handlers) handler(this); this.dirty = false; } } /* dom needed: #Canvases-Container div 决定画布尺寸 #piano canvas 画琴键 #timeBar canvas 画时间轴 #main-layers div 主工作区图层容器 #spectrum canvas 画频谱 #actions canvas 画其余 #funcSider div 音轨选择的容器 #speedControl input[type=range] 变速 #multiControl input[type=range] 改变画频谱的倍率 #contrastControl input[type=range] 改变画频谱的对比度 #midivolumeControl input[type=range] midi音量 #play-btn button 播放 #actMode div 动作模式选择,其下有两个btn #scrollbar-track div 滑动条轨道 #scrollbar-thumb div 滑动条 */ ================================================ FILE: core/app_analyser.js ================================================ /// /// /// /// /// /// /// /// /** * 数据解析相关算法 * @param {App} parent */ function _Analyser(parent) { /** * @param {AudioBuffer} audioBuffer 音频缓冲区 * @param {number} channel 选择哪个channel分析 0:left 1:right 2:l+r 3:l-r else:fft(l)+fft(r) * @returns {Array} 选择的channel数据 .sampleRate为采样率 */ this.selectChannel = (audioBuffer, channel) => { const channels = []; channels.sampleRate = audioBuffer.sampleRate; switch (channel) { case 0: channels.push(audioBuffer.getChannelData(0)); break; case 1: channels.push(audioBuffer.getChannelData(audioBuffer.numberOfChannels - 1)); break; case 2: { // L+R let length = audioBuffer.length; let timeDomain = audioBuffer.getChannelData(0); if (audioBuffer.numberOfChannels > 1) { timeDomain = new Float32Array(timeDomain); let channelData = audioBuffer.getChannelData(1); for (let i = 0; i < length; i++) timeDomain[i] += channelData[i]; } channels.push(timeDomain); break; } case 3: { // L-R let length = audioBuffer.length; let timeDomain = audioBuffer.getChannelData(0); if (audioBuffer.numberOfChannels > 1) { timeDomain = new Float32Array(timeDomain); let channelData = audioBuffer.getChannelData(1); for (let i = 0; i < length; i++) timeDomain[i] -= channelData[i]; } channels.push(timeDomain); break; } default: { // fft(L)+fft(R) for (let c = 0; c < audioBuffer.numberOfChannels; c++) channels.push(audioBuffer.getChannelData(c)); break; } } return channels; }; /** * 对channels执行STFT * @param {Array} channels 通道数据数组,每个元素为一个channel的数据 .sampleRate为采样率 * @param {number} tNum 一秒几次分析 决定步距 * @param {number} A4 频率表的A4频率 * @param {number} fftPoints 实数fft点数 * @param {boolean} useGPU 是否使用GPU加速 * @returns {Promise>} 时频谱数据 */ this.stft = async (channels, tNum = 20, A4 = 440, fftPoints = 8192, useGPU = true) => {// 8192点在44100采样率下,最低能分辨F#2,但是足矣 parent.dt = 1000 / tNum; parent.TperP = parent.dt / parent._width; parent.PperT = parent._width / parent.dt; const fs = channels.sampleRate ??= parent.audioContext.sampleRate; const dN = Math.round(fs / tNum); parent.Keyboard.freqTable.A4 = A4; let STFT; try { if (!useGPU) throw new Error("强制使用CPU计算STFT"); STFT = await stftGPU(fs, channels, dN, fftPoints); } catch (e) { console.warn("GPU加速STFT失败,回退至CPU计算\n原因:", e.message); STFT = await stftCPU(fs, channels, dN, fftPoints); } return NoteAnalyser.normalize(STFT); } async function stftCPU(fs, channels, hop, fftPoints) { const progressPerChannel = 1 / channels.length; var progressTrans = (x) => x * progressPerChannel; // 如果分阶段执行则需要自定义进度的变换 const fft = new realFFT(fftPoints); const analyser = new NoteAnalyser(fs / fftPoints, parent.Keyboard.freqTable); const nbins = parent.Keyboard.freqTable.length; const a = async (t) => { // 对t执行STFT,并整理为时频谱 let n = hop >> 1; const result = new Array(1 + (t.length - n) / hop | 0); const _data = new Float32Array(result.length * nbins); const window_left = fftPoints >> 1; // 窗口左边界偏移量 for (let k = 0, sub = 0; n <= t.length; n += hop, sub += nbins) { // n为窗口中心 result[k++] = analyser.mel(...fft.fft(t, n - window_left), _data.subarray(sub, sub + nbins)); // 一帧一次也太慢了。这里固定更新帧率 let tnow = performance.now(); if (tnow - lastFrame > 200) { lastFrame = tnow; // 打断分析 更新UI 等待下一周期 parent.event.dispatchEvent(new CustomEvent("progress", { detail: progressTrans(k / result.length) })); await new Promise(resolve => setTimeout(resolve, 0)); } } // 通知UI关闭的事件分发移到了audio.onloadeddata中 result.raw = _data; return result; }; await new Promise(resolve => setTimeout(resolve, 0)); // 等待UI var lastFrame = performance.now(); const result = await a(channels[0]); for (let i = 1; i < channels.length; i++) { progressTrans = (x) => (i + x) * progressPerChannel; const other = (await a(channels[i])).raw; const raw = result.raw; for (let j = 0; j < raw.length; j++) raw[j] += other[j]; } return result; }; async function stftGPU(fs, channels, hop, fftPoints) { const stftGPU = new STFTGPU(fftPoints, hop); parent.event.dispatchEvent(new CustomEvent("progress", { detail: 0.4 })); await stftGPU.initWebGPU(); console.log("WebGPU初始化成功,使用GPU计算STFT"); const analyser = new NoteAnalyser(fs / fftPoints, parent.Keyboard.freqTable); for (const c of channels) stftGPU.stft(c); const stftRes = await stftGPU.readGPU(); stftGPU.free(); const result = new Array(stftRes.length); const nbins = parent.Keyboard.freqTable.length; const _data = new Float32Array(result.length * nbins); for (let i = 0; i < stftRes.length; i++) result[i] = analyser.mel2(stftRes[i], _data.subarray(i * nbins, (i + 1) * nbins)); result.raw = _data; return result; } /** * 后台(worker)计算CQT * @param {Array} channels 通道数据数组,每个元素为一个channel的数据 .sampleRate为采样率 * @param {number} tNum 一秒几次分析 决定步距 * @param {boolean} useGPU 是否使用GPU加速计算CQT * @returns 不返回,直接作用于Spectrogram.spectrogram */ this.cqt = (channels, tNum, useGPU = false) => { if (!parent.io.canUseExternalWorker || window.cqt == undefined) return; // 开worker和fetch要求http console.time("CQT计算"); cqt(channels, tNum, parent.Keyboard.freqTable[0], useGPU).then((cqtData) => { // CQT结果准确但琐碎,STFT结果粗糙但平滑,所以混合一下 const s = parent.Spectrogram.spectrogram; let tLen = Math.min(cqtData.length, s.length); for (let i = 0; i < tLen; i++) { const cqtBins = cqtData[i]; const stftBins = s[i]; for (let j = 0; j < cqtBins.length; j++) { // 更重视CQT谱 若CQT谱更强则用更大的平均 if (stftBins[j] < cqtBins[j]) stftBins[j] = Math.hypot(stftBins[j], cqtBins[j]) / Math.SQRT2; else stftBins[j] = Math.sqrt(stftBins[j] * cqtBins[j]); } } console.timeEnd("CQT计算"); parent.Spectrogram.spectrogram = s; // 通知更新 }).catch(console.error); }; /** * 后台(worker)AI音色无关扒谱 * @param {AudioBuffer} audioBuffer 音频缓冲区 * @param {boolean} judgeOnly 是否只判断是否可以扒谱 * @returns promise,用于指示扒谱完成。如果judgeOnly为true则返回值代表是否可以AI扒谱 */ this.basicamt = (audioData, judgeOnly = false) => { if (!parent.io.canUseExternalWorker || window.AI == undefined) { alert("file协议下无法使用AI扒谱!"); return false; } if (!parent.Spectrogram._spectrogram) { alert('请导入音频或进入midi编辑模式!'); return false; } if (!parent.MidiAction.channelDiv.colorMask) { alert("音轨不足!请至少删除一个音轨!"); return false; } if (judgeOnly) return true; console.time("AI扒谱"); return AI.basicamt(audioData).then((events) => { console.timeEnd("AI扒谱"); const timescale = (256 * 1000) / (22050 * parent.dt); // basicAMT在22050Hz下以hop=256分析 // 逻辑同index.html中导入midi const chdiv = parent.MidiAction.channelDiv; chdiv.switchUpdateMode(false); const ch = chdiv.addChannel(); if (!ch) return; const chid = ch.index; ch.name = `AI扒谱${chid}`; ch.instrument = TinySynth.instrument[(ch.ch.instrument = 4)]; const maxIntensity = events.reduce((a, b) => a.velocity > b.velocity ? a : b).velocity; ch.ch.volume = maxIntensity * 127; const notes = events.map(({ onset, offset, note, velocity }) => { return { x1: onset * timescale, x2: offset * timescale, y: note - 24, ch: chid, selected: false, v: velocity / maxIntensity * 127 }; }); parent.MidiAction.midi.push(...notes); parent.MidiAction.midi.sort((a, b) => a.x1 - b.x1); chdiv.switchUpdateMode(true); }).catch(alert); }; /** * 后台(worker)AI音色分离扒谱 * @param {AudioBuffer} audioBuffer 音频缓冲区 * @returns promise,用于指示扒谱完成 */ this.septimbre = (audioData, k = 2) => { console.time("AI音色分离扒谱"); return AI.septimbre(audioData, k).then((tracks) => { console.timeEnd("AI音色分离扒谱"); const timescale = (256 * 1000) / (22050 * parent.dt); // 逻辑同index.html中导入midi const chdiv = parent.MidiAction.channelDiv; chdiv.switchUpdateMode(false); tracks.forEach((events) => { const ch = chdiv.addChannel(); if (!ch) return; const chid = ch.index; ch.name = `AI分离${chid}`; ch.instrument = TinySynth.instrument[(ch.ch.instrument = 4)]; const maxIntensity = events.reduce((a, b) => a.velocity > b.velocity ? a : b).velocity; ch.ch.volume = maxIntensity * 127; const notes = events.map(({ onset, offset, note, velocity }) => { return { x1: onset * timescale, x2: offset * timescale, y: note - 24, ch: chid, selected: false, v: velocity / maxIntensity * 127 }; }); parent.MidiAction.midi.push(...notes); }); parent.MidiAction.midi.sort((a, b) => a.x1 - b.x1); chdiv.switchUpdateMode(true); }).catch(alert); }; /** * “自动对齐音符”的入口 原理见 ~/dataProcess/aboutANA.md */ this.autoNoteAlign = () => { if (!parent.Spectrogram._spectrogram || parent.midiMode) { alert('请先导入音频!'); return false; } if (!parent.MidiAction.channelDiv.colorMask) { alert("音轨不足!请至少删除一个音轨!"); return false; } let tempDiv = document.createElement('div'); tempDiv.innerHTML = `
`; const UI = tempDiv.firstElementChild; const textarea = UI.querySelector('textarea'); const close = () => { UI.remove(); parent.preventShortCut = false; } const btns = UI.getElementsByTagName('button'); btns[0].onclick = close; btns[1].onclick = () => { textarea.value = '(' + textarea.value + ')'; }; btns[2].onclick = () => { textarea.value = '[' + textarea.value + ']'; }; btns[3].onclick = () => { // 重复区间内 const numberedScore = textarea.value.trim(); if (!numberedScore) { alert("请输入数字谱!"); return; } try { this._autoNoteAlign( numberedScore, parent.TimeBar.repeatStart / parent.dt, parent.TimeBar.repeatEnd / parent.dt ); close(); } catch (error) { alert(error.message); } }; btns[4].onclick = () => { // 所有时间 const numberedScore = textarea.value.trim(); if (!numberedScore) { alert("请输入数字谱!"); return; } try { this._autoNoteAlign(numberedScore); close(); } catch (error) { alert(error.message); } } parent.preventShortCut = true; // 禁止快捷键 document.body.insertBefore(UI, document.body.firstChild); }; this._autoNoteAlign = (noteSeq, begin, end) => { noteSeq = parseJE(noteSeq); let spectrum = parent.Spectrogram.spectrogram; if (begin != undefined) { begin = Math.max(0, Math.floor(begin)); end = Math.min(spectrum.length, Math.ceil(end)); spectrum = spectrum.slice(begin, end); } else begin = 0; if (noteSeq.length > spectrum.length) { throw new Error("数字谱长度超过频谱长度!(时长太短)"); } // 插入间隔(用-1表示) const paddedNoteSeq = [-1]; for (let i = 0; i < noteSeq.length; i++) { // 0对应C4 paddedNoteSeq.push(noteSeq[i] + 48, -1); } const path = autoNoteAlign(paddedNoteSeq, spectrum, 100 / parent.dt); const chdiv = parent.MidiAction.channelDiv; chdiv.switchUpdateMode(false); const ch = chdiv.addChannel(); if (!ch) return; const chid = ch.index; ch.name = `自动对齐${chid}`; for (let i = 0; i < path.length; ++i) { const [noteIdx, frameIdx] = path[i]; const n = paddedNoteSeq[noteIdx]; if (n == -1) continue; while (i < path.length && path[i][0] == noteIdx) ++i; --i; const frameEnd = path[i][1] + 1; parent.MidiAction.midi.push({ y: n, x1: frameIdx + begin, x2: frameEnd + begin, ch: chid, selected: false, }); } parent.MidiAction.midi.sort((a, b) => a.x1 - b.x1); chdiv.switchUpdateMode(true); }; /** * 自动节拍检测并生成节拍线 * @param {number} minBPM 最小BPM * @param {boolean} autoDownBeat 是否自动检测重拍位置 * @returns {number} 全局估计的BPM值 */ this.beatEst = (minBPM = 40, autoDownBeat = false) => { const sr = Math.round(1000 / parent.dt); const onset = Beat.extractOnset(parent.Spectrogram.spectrogram, Math.min(0.99, 16 / sr)); const maxInterval = Math.ceil(sr * 60 / minBPM); // 范围要大,所以方差大一些 const global = Beat.corrBPM(SIGNAL.autoCorr(onset, maxInterval), sr, 1.4, 105); const tempo = Beat.tempo(onset, sr, minBPM, 12.8, 1.6, global); const fftSize = Beat.fs2FFTN(sr, 12.8); const pulse = Beat.PLP(onset, sr, [40, 200], fftSize, Math.max(1, fftSize >> 3), Beat.PLPprior(tempo, 0.1)); for (let i = 0; i < pulse.length; i++) pulse[i] += onset[i]; const beatIdx = Beat.EllisBeatTrack(pulse, sr, 300, tempo); if (beatIdx.length < 2) { alert("未能检测到有效节拍!"); return; } if (beatIdx[0] == 0) beatIdx.shift(); // 不能引入pulse的干扰 得用原始的onset const beatStrength = Beat.beatStrength(onset, beatIdx); const beatbar = parent.BeatBar.beats; if (autoDownBeat) { // 用动态规划求解重拍位置 但不够稳定 const [downbeatIndices, downbeatMeters] = Beat.detectDownbeats(beatStrength, [2, 3, 4]); // 处理前面的拍 beatbar.length = 0; let prev = 0, id = 0, i = 0; for (; i <= downbeatIndices[0]; i++, id++) { const at = beatIdx[i] * parent.dt; beatbar.push(new eMeasure(id, prev, 1, 4, at - prev)); prev = at; } for (i = 0; i < downbeatIndices.length; i++, id++) { const pattern = downbeatMeters[i]; const beatdown = downbeatIndices[i]; if (i + 1 < downbeatIndices.length) { const nextBeatdown = downbeatIndices[i + 1]; const endtime = beatIdx[nextBeatdown] * parent.dt; beatbar.push(new eMeasure(id, prev, pattern, 4, endtime - prev)); prev = endtime; } else { let endtime; const time = beatIdx[beatIdx.length - 1] * parent.dt - prev; const cnt = beatIdx.length - 1 - beatdown; beatbar.push(new eMeasure(id, prev, pattern, 4, time / cnt * pattern)); } } } else { // 这两个估计结果有点差 暂时用1拍 // const [g_pattern, g_beatdown] = Beat.rhythmicPattern(beatStrength, [2, 3, 4]); let g_pattern = 1, g_beatdown = 0; beatbar.length = 0; let prev = 0, id = 0, i = 0; // 前面的用单小节处理 注意应该有等号 for (; i <= g_beatdown; i++, id++) { const at = beatIdx[i] * parent.dt; beatbar.push(new eMeasure(id, prev, 1, 4, at - prev)); prev = at; } for (i = i - 1 + g_pattern; i < beatIdx.length; i += g_pattern, id++) { const at = beatIdx[i] * parent.dt; beatbar.push(new eMeasure(id, prev, g_pattern, 4, at - prev)); prev = at; } } beatbar.check(true); parent.snapshot.save(0b100); parent.layers.action.dirty = true; // 如果正在用节拍则刷新节拍信息 if (parent.AudioPlayer.audio.paused === false && parent.MidiPlayer._ifBeat) { parent.MidiPlayer.restart(true); } return global; }; // 1(C4)->0 function parseJE(txt) { const parts = []; let n = 0; let octave = 0; const JEnotes = ["1", "#1", "2", "#2", "3", "4", "#4", "5", "#5", "6", "#6", "7"]; while (n < txt.length) { if (txt[n] == ')' || txt[n] == '[') ++octave; else if (txt[n] == '(' || txt[n] == ']') --octave; else { let m = 0; if (txt[n] == '#') m = 1; else if (txt[n] == 'b') m = -1; const noteEnd = n + Math.abs(m); const position = noteEnd < txt.length ? JEnotes.indexOf(txt[noteEnd]) : -1; if (position != -1) { parts.push(m + position + octave * 12); n = noteEnd; } } ++n; } return parts; }; this.reduceHarmonic = () => { let resolve, reject; let p = new Promise((res, rej) => { resolve = res; reject = rej; }); let tempDiv = document.createElement('div'); tempDiv.innerHTML = `
谐波衰减率
谐波数量
`; const UI = tempDiv.firstElementChild; const inputs = UI.querySelectorAll('input[type="number"]'); const decayInput = inputs[0]; const harmonicsInput = inputs[1]; const cancelBtn = UI.querySelector('.ui-cancel'); const inplace = UI.querySelector('input[type="checkbox"]'); const confirmBtn = UI.querySelector('.ui-confirm'); cancelBtn.onclick = () => { UI.remove(); resolve(false); }; confirmBtn.onclick = () => { let decay = parseFloat(decayInput.value); if (decay < 0.1 || decay > 0.9) { alert("衰减率必须在0.1到0.9之间!"); return; } let harmonics = parseInt(harmonicsInput.value); if (harmonics < 4 || harmonics > 16) { alert("谐波数量必须在4到16之间!"); return; } UI.remove(); this._reduceHarmonic(decay, harmonics, inplace.checked).then(() => { resolve(true); }).catch(reject); } document.body.insertBefore(UI, document.body.firstChild); return p; }; /** * 利用非负最小二乘去除频谱中的谐波成分并补偿基频 在幅度谱上进行 * 如果inplace为true则直接修改Spectrogram.spectrogram 否则会存储谐波成分矩阵于Spectrogram.harmonic * 原理是将谐波模板(每个音符的基频和若干个谐波)作为特征,拟合出每一帧中各个音符的强度,然后将这些音符的谐波成分从频谱中减去 * @param {number} decay 谐波衰减率,默认0.6,越大去除越彻底但可能过度拟合 * @param {number} harmonics 谐波数量 * @param {boolean} inplace 是否直接在原频谱上减去谐波 还是单独存储谐波成分 */ this._reduceHarmonic = async (decay = 0.6, harmonics = 10, inplace = false) => { const container = document.createElement('div'); container.innerHTML = `
00%
`; const progressUI = container.firstElementChild; const progress = progressUI.querySelector('.porgress-value'); const percent = progressUI.querySelector('span'); document.body.insertBefore(progressUI, document.body.firstChild); const onprogress = (detail) => { if (detail < 0) { progress.style.width = '100%'; percent.textContent = '100%'; progressUI.style.opacity = 0; setTimeout(() => progressUI.remove(), 200); } else if (detail >= 1) { detail = 1; progress.style.width = '100%'; percent.textContent = "加载界面……"; } else { progress.style.width = (detail * 100) + '%'; percent.textContent = (detail * 100).toFixed(2) + '%'; } }; var lastFrame = performance.now(); const s = parent.Spectrogram._spectrogram; const M = s[0].length, N = s.length; const M1 = M + 1; // 创建音符谐波模板 let harmonicAmp = Array.from({ length: harmonics }, (_, i) => decay ** i); const Harmonic = new Float32Array(M); for (let i = 0; i < harmonicAmp.length; i++) { const idx = 12 * Math.log2(i + 1); let l = Math.floor(idx), r = Math.ceil(idx); if (r < M) { if (l == r) Harmonic[l] = harmonicAmp[i]; else { Harmonic[l] += harmonicAmp[i] * (r - idx); Harmonic[r] += harmonicAmp[i] * (idx - l); } } } // 填充到模板矩阵A const A = new Float32Array(M * M); for (let i = 0; i < M; i++) A.set(Harmonic.subarray(0, M - i), i * M1); // 模式选择 if (!inplace) { harmonicAmp = Array(N); harmonicAmp.raw = new Float32Array(N * M); } else harmonicAmp = null; // 对每一帧执行NNLS const nnls = new NNLSSolver(M, M, 2e-4, Harmonic); for (let t = 0; t < N; t++) { const f = s[t]; const c = nnls.solve(A, f); // 计算谐波 Harmonic.fill(0); for (let i = 0; i < M; i++) { const a = i + 12; // start at 2f0 const off = i * M + a; let f0h = 0; for (let j = 0; j < M - a; j++) { let amp = A[off + j] * c[i]; f0h += amp * amp; Harmonic[a + j] += amp; }; // 加强基频。∵L2 200) { onprogress(t / N); await new Promise(resolve => setTimeout(resolve, 0)); // 等待UI lastFrame = tnow; } } if (!inplace) parent.Spectrogram.harmonic = harmonicAmp; parent.layers.spectrum.dirty = true; onprogress(-1); }; } ================================================ FILE: core/app_audioplayer.js ================================================ /// /** * 音频播放 * @param {App} parent */ function _AudioPlayer(parent) { this.name = "请上传文件"; // 在parent.io.onfile中赋值 this.audio = new Audio(); // 在parent.io.onfile中重新赋值 此处需要一个占位 this.play_btn = document.getElementById("play-btn"); this.durationString = ''; // 在parent.Analyser.audio.ondurationchange中更新 this.autoPage = false; // 自动翻页 this.repeat = true; // 是否区间循环 this.EQfreq = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000]; // midiMode下url为duration this.createAudio = (url) => { return new Promise((resolve, reject) => { const a = parent.midiMode ? new FakeAudio(url) : new Audio(url); a.loop = false; a.volume = parseFloat(document.getElementById('audiovolumeControl').value); a.ondurationchange = () => { let ms = a.duration * 1000; this.durationString = parent.TimeBar.msToClockString(ms); parent.BeatBar.beats.maxTime = ms; }; a.onended = () => { parent.time = 0; this.stop(); }; a.onloadeddata = () => { if (!parent.midiMode) { this.setEQ(); if (parent.audioContext.state == 'suspended') parent.audioContext.resume().then(() => a.pause()); document.title = this.name + "~扒谱"; } else { document.title = this.name; } a.playbackRate = document.getElementById('speedControl').value; // load之后会重置速度 parent.time = 0; resolve(a); a.onloadeddata = null; // 一次性 防止多次构造 this.play_btn.firstChild.textContent = parent.TimeBar.msToClockString(parent.time); this.play_btn.lastChild.textContent = this.durationString; }; a.onerror = (e) => { // 如果正常分析,是用不到这个回调的,因为WebAudioAPI读取就会报错。但上传已有结果不会再分析 // 发现一些如mov格式的视频,不在video/的支持列表中,用.readAsDataURL转为base64后无法播放,会触发这个错误 // 改正方法是用URL.createObjectURL(file)生成一个blob地址而不是解析为base64 console.error("Audio load error", e); reject(e); // 不再抛出错误事件 调用者自行处理 // parent.event.dispatchEvent(new Event('fileerror')); }; this.setAudio(a); }); }; let _crossFlag = false; // 上一时刻是否在重复区间终点左侧 this.update = () => { const a = this.audio; if (a.readyState != 4 || a.paused) return; parent.time = a.currentTime * 1000; // 【重要】更新时间 // 重复区间 let crossFlag = parent.time < parent.TimeBar.repeatEnd; if (this.repeat && parent.TimeBar.repeatEnd >= parent.TimeBar.repeatStart) { // 重复且重复区间有效 if (_crossFlag && !crossFlag) { // 从重复区间终点左侧到右侧 parent.time = parent.TimeBar.repeatStart; a.currentTime = parent.time / 1000; } } _crossFlag = crossFlag; this.play_btn.firstChild.textContent = parent.TimeBar.msToClockString(parent.time); this.play_btn.lastChild.textContent = this.durationString; // 自动翻页 if (parent.time > parent.idXend * parent.dt || parent.time < parent.idXstart * parent.dt) { // 在视图外 if (this.autoPage) parent.scroll2(((parent.time / parent.dt - 1) | 0) * parent._width, parent.scrollY); } else parent.layers.action.dirty = true; }; /** * 在指定的毫秒数开始播放 * @param {number} at 开始的毫秒数 如果是负数,则从当下开始 */ this.start = (at) => { const a = this.audio; if (a.readyState != 4) return; if (at >= 0) a.currentTime = at / 1000; _crossFlag = false; // 置此为假可以暂时取消重复区间 parent.MidiPlayer.restart(); if (a.readyState == 4) a.play(); else a.oncanplay = () => { a.play(); a.oncanplay = null; }; }; this.stop = () => { this.audio.pause(); parent.synthesizer.stopAll(); }; this.setEQ = (f = this.EQfreq) => { const a = this.audio; if (a.EQ) return; // 由于createMediaElementSource对一个audio只能调用一次,所以audio的EQ属性只能设置一次 const source = parent.audioContext.createMediaElementSource(a); let last = source; a.EQ = { source: source, filter: f.map((v) => { const filter = parent.audioContext.createBiquadFilter(); filter.type = "peaking"; filter.frequency.value = v; filter.Q.value = 1; filter.gain.value = 0; last.connect(filter); last = filter; return filter; }) }; last.connect(parent.audioContext.destination); }; this.setAudio = (newAudio) => { const a = this.audio; if (a) { a.pause(); a.onerror = null; // 防止触发fileerror a.src = ''; if (a.EQ) { a.EQ.source.disconnect(); for (const filter of a.EQ.filter) filter.disconnect(); } // 配合传参为URL.createObjectURL(file)使用,防止内存泄露 URL.revokeObjectURL(a.src); } this.audio = newAudio; }; this.play_btn.onclick = () => { if (this.audio.paused) this.start(-1); else this.stop(); this.play_btn.blur(); // 防止焦点在按钮上导致空格响应失败 }; } ================================================ FILE: core/app_beatbar.js ================================================ /// /// /** * 顶部小节轴 * @param {App} parent */ function _BeatBar(parent) { this.beats = new Beats(); this.minInterval = 20; // 最小画线间隔 单位:像素 // timeBar的下半部分画小节线和拍线 并在工作区画小节线 this.render = () => { const canvas = parent.timeBar; const ctx = parent.timeBar.ctx; ctx.fillStyle = '#2e3039'; const h = canvas.height >> 1; ctx.fillRect(0, h, canvas.width, canvas.width); ctx.fillStyle = '#8e95a6'; const spectrum = parent.layers.action.ctx; const spectrumHeight = parent.layers.action.height; ctx.strokeStyle = '#f0f0f0'; spectrum.strokeStyle = '#c0c0c0'; const beatX = []; // 小节内每一拍 const noteX = []; // 一拍内x分音符对齐线 const iterator = this.beats.iterator(parent.scrollX * parent.TperP, true); ctx.beginPath(); spectrum.beginPath(); while (1) { let measure = iterator.next(); if (measure.done) break; measure = measure.value; let x = measure.start * parent.PperT - parent.scrollX; if (x > canvas.width) break; ctx.moveTo(x, h); ctx.lineTo(x, canvas.height); spectrum.moveTo(x, 0); spectrum.lineTo(x, spectrumHeight); // 写字 会根据间隔决定是否显示拍型 const Interval = measure.interval * parent.PperT; ctx.fillText(Interval < 38 ? measure.id : `${measure.id}. ${measure.beatNum}/${measure.beatUnit}`, x + 2, h + 14); // 画更细的节拍线 const dp = Interval / measure.beatNum; if (dp < this.minInterval) continue; x += dp; for (let i = measure.beatNum - 1; i > 0; i--, x += dp) beatX.push(x); // 画x分音符的线 const noteNum = 1 << Math.log2(dp / this.minInterval); if (noteNum < 2) continue; const noteInterval = dp / noteNum; let i = ((x - canvas.width) / noteInterval) | 0; // 跳过末尾的 不然在极大的放大时会卡顿 if (i > 0) x -= i * noteInterval; else i = 0; for (let n = noteNum * measure.beatNum; i < n; i++, x -= noteInterval) { if (x < 0) break; if (i % noteNum == 0) continue; // 跳过beat线 noteX.push(x); } } ctx.stroke(); spectrum.stroke(); if (beatX.length != 0) { spectrum.beginPath(); spectrum.strokeStyle = '#909090'; for (const x of beatX) { spectrum.moveTo(x, 0); spectrum.lineTo(x, spectrumHeight); } spectrum.stroke(); } if (noteX.length != 0) { spectrum.beginPath(); spectrum.setLineDash([4, 4]); spectrum.strokeStyle = '#606060'; for (const x of noteX) { spectrum.moveTo(x, 0); spectrum.lineTo(x, spectrumHeight); } spectrum.stroke(); spectrum.setLineDash([]); // 恢复默认 } }; this.contextMenu = new ContextMenu([ { name: "设置小节", callback: (e_father, e_self) => { const bs = this.beats; const m = bs.setMeasure((e_father.offsetX + parent.scrollX) * parent.TperP, undefined, true); const tempDiv = document.createElement('div'); tempDiv.innerHTML = `
拍数
音符
BPM:
(忽略BPM)保持小节长度
(忽略以上)和上一小节一样
应用到后面相邻同类型小节
`; const Pannel = tempDiv.firstElementChild; document.body.insertBefore(Pannel, document.body.firstChild); Pannel.tabIndex = 0; Pannel.focus(); function close() { Pannel.remove(); } const inputs = Pannel.querySelectorAll('[name="ui-ask"]'); const btns = Pannel.getElementsByTagName('button'); inputs[0].value = m.beatNum; // 拍数 inputs[1].value = m.beatUnit; // 音符类型 inputs[2].value = m.bpm; // bpm btns[0].onclick = close; btns[1].onclick = () => { if (!inputs[5].checked) { // 后面不变 bs.setMeasure(m.id + 1, undefined, false); // 让下一个生成实体 } if (inputs[4].checked) { // 和上一小节一样 let last = bs.getMeasure(m.id - 1, false); m.copy(last); } else { m.beatNum = parseInt(inputs[0].value); m.beatUnit = parseInt(inputs[1].value); if (!inputs[3].checked) m.bpm = parseFloat(inputs[2].value); } bs.check(); close(); parent.snapshot.save(0b100); }; } }, { name: "后方插入一小节", callback: (e_father) => { this.beats.add((e_father.offsetX + parent.scrollX) * parent.TperP, true); parent.snapshot.save(0b100); } }, { name: "均分该小节", callback: (e_father) => { const beatarr = this.beats; const base = beatarr.setMeasure((e_father.offsetX + parent.scrollX) * parent.TperP, undefined, true, true); const baseM = beatarr[base]; // 下一小节若未定义则定义 则插入一个 防止影响后面 if (base + 1 >= beatarr.length || beatarr[base + 1].id > baseM.id + 1) beatarr.splice(base + 1, 0, eMeasure.baseOn(baseM, baseM.id + 1)); // 插入新的 用id位移实现 baseM.interval /= 2; for (let i = base + 1; i < beatarr.length; i++) beatarr[i].id++; beatarr.check(true); parent.snapshot.save(0b100); } }, { name: "分裂为单拍", callback: (e_father) => { const beatarr = this.beats; const base = beatarr.setMeasure((e_father.offsetX + parent.scrollX) * parent.TperP, undefined, true, true); const baseM = beatarr[base]; if (base + 1 >= beatarr.length || beatarr[base + 1].id > baseM.id + 1) beatarr.splice(base + 1, 0, eMeasure.baseOn(baseM, baseM.id + 1)); const beatNum = baseM.beatNum; baseM.interval /= beatNum; for (let i = base + 1; i < beatarr.length; i++) beatarr[i].id += beatNum - 1; beatarr.check(true); parent.snapshot.save(0b100); } }, { name: "合并下一小节", callback: (e_father) => { const beatarr = this.beats; const base = beatarr.setMeasure((e_father.offsetX + parent.scrollX) * parent.TperP, undefined, true, true); const baseM = beatarr[base]; // 下下个 const nextnext = beatarr.setMeasure(baseM.id + 2, undefined, false, true); const nextnextM = beatarr[nextnext]; if (nextnext === base + 2) { // 中间隔了一个小节头 const deleted = beatarr.splice(base + 1, 1)[0]; baseM.interval += deleted.interval; baseM.beatNum += deleted.beatNum; } else { baseM.interval += baseM.interval; baseM.beatNum += baseM.beatNum; } for (let i = base + 1; i < beatarr.length; i++) beatarr[i].id--; beatarr.check(true); parent.snapshot.save(0b100); } }, { name: "重置后面所有小节", callback: (e_father) => { const base = this.beats.getBaseIndex((e_father.offsetX + parent.scrollX) * parent.TperP, true); this.beats.splice(base + 1); parent.snapshot.save(0b100); } }, { name: '删除该小节', callback: (e_father, e_self) => { this.beats.delete((e_father.offsetX + parent.scrollX) * parent.TperP, true); parent.snapshot.save(0b100); } } ]); this.belongID = -1; // 小节线前一个小节的id this.moveCatch = (e) => { // 画布上光标移动到小节线上可以进入调整模式 // 判断是否在小节轴上 if (e.offsetY < parent.timeBar.height >> 1) { parent.timeBar.classList.remove('selecting'); this.belongID = -1; return; } const timeNow = (e.offsetX + parent.scrollX) * parent.TperP; const m = this.beats.getMeasure(timeNow, true); if (m == null) { this.belongID = -1; parent.timeBar.classList.remove('selecting'); return; } const threshold = 6 * parent.TperP; if (timeNow - m.start < threshold) { this.belongID = m.id - 1; parent.timeBar.classList.add('selecting'); } else if (m.start + m.interval - timeNow < threshold) { this.belongID = m.id; parent.timeBar.classList.add('selecting'); } else { this.belongID = -1; parent.timeBar.classList.remove('selecting'); } }; } ================================================ FILE: core/app_hscrollbar.js ================================================ /** * 配合scroll的滑动条 * @param {App} parent */ function _HscrollBar(parent) { this.maxScrollX = 0; this.refreshPosition = () => { // 在parent.scroll2中调用 if (this.maxScrollX <= 0) { thumb.style.left = '0px'; return; } let pos = (track.offsetWidth - thumb.offsetWidth) * parent.scrollX / this.maxScrollX; thumb.style.left = pos + 'px'; }; this.refreshSize = () => { // 需要在parent.xnum parent.width改变之后调用 在二者的setter中调用 track.style.display = 'block'; let all = parent._width * parent._xnum; let p = Math.min(1, parent.layers.width / all); // 由于有min存在所以xnum即使为零也能工作 let nw = p * track.offsetWidth; thumb.style.width = Math.max(nw, 10) + 'px'; // 限制最小宽度 this.maxScrollX = all - parent.layers.width; }; const track = document.getElementById('scrollbar-track'); const thumb = document.getElementById('scrollbar-thumb'); const thumbMousedown = (event) => { // 滑块跟随鼠标 event.stopPropagation(); // 防止触发track的mousedown const startX = event.clientX; const thumbLeft = thumb.offsetLeft; const moveThumb = (event) => { let currentX = event.clientX - startX + thumbLeft; let maxThumbLeft = track.offsetWidth - thumb.offsetWidth; parent.scroll2(currentX / maxThumbLeft * this.maxScrollX, parent.scrollY); } const stopMoveThumb = () => { document.removeEventListener("mousemove", moveThumb); document.removeEventListener("mouseup", stopMoveThumb); } document.addEventListener("mousemove", moveThumb); document.addEventListener("mouseup", stopMoveThumb); }; const trackMousedown = (e) => { // 滑块跳转 e.stopPropagation(); let maxThumbLeft = track.offsetWidth - thumb.offsetWidth; let p = (e.offsetX - (thumb.offsetWidth >> 1)) / maxThumbLeft; // nnd 减法优先级比位运算高 parent.scroll2(p * this.maxScrollX, parent.scrollY); }; thumb.addEventListener('mousedown', thumbMousedown); track.addEventListener('mousedown', trackMousedown); } ================================================ FILE: core/app_io.js ================================================ /// /// /** * 文件相关操作 * @param {App} parent */ function _IO(parent) { this.canUseExternalWorker = typeof window.Worker !== 'undefined' && window.location.protocol !== 'file:'; // midi模式下的假音频 function fakeInput(l = 0, tNum = 1000 / parent.dt) { if (!l || l <= 0) l = Math.ceil((parent.layers.width << 1) / parent.width); // 一个怎么取值都返回0的东西,充当频谱 parent.Spectrogram.spectrogram = new Proxy({ raw: new Uint8Array(parent.ynum).fill(0), _length: l, get length() { return this._length; }, set length(l) { // 只要改变频谱的长度就可以改变时长 长度改变在MidiAction.updateView中 if (l < 0) return; this._length = parent.xnum = l; parent.AudioPlayer.audio.duration = l / tNum; parent.AudioPlayer.play_btn.lastChild.textContent = parent.AudioPlayer.durationString; }, *[Symbol.iterator]() { for (let i = 0; i < this.length; i++) yield this.raw; } }, { get(obj, prop) { // 方括号传递的总是string if (isNaN(Number(prop))) return obj[prop]; return obj.raw; }, set(obj, prop, value) { if (isNaN(Number(prop))) obj[prop] = value; return true; } }); // 假音频 需要设置parent.midiMode=true; return parent.AudioPlayer.createAudio(l / tNum); } /** * 会发出如下event: * - fileui: 展示本函数的UI,需要外界关闭drag功能 * - fileuiclose: UI关闭,外界恢复drag功能 * - fileerror: 文件解析错误,外界提示用户; detail为Error对象 * - progress: 解析进度,detail为0~1的数字,-1表示完成 * event的意义是可以反复触发(比如进度文件错误可重试),而返回值的promise只能触发一次 * @param {File} file 音频文件 如果不传则进入midi编辑器模式 * @returns Promise 指示用户操作完成,即UI关闭 */ this.onfile = (file) => { // 依赖askUI.css let midimode = file == void 0; // 在确认后才能parent.midiMode=midimode if (midimode) { // 不传则说明是midi编辑器模式 file = { name: "MIDI编辑模式" }; } else if (!(file.type.startsWith('audio/') || file.type.startsWith('video/'))) { parent.event.dispatchEvent(new CustomEvent('fileerror', { detail: new Error("不支持的文件类型") })); return Promise.reject(); } else if (file.type == "audio/mid") { if (parent.Spectrogram._spectrogram) { this.midiFile.import(file); return Promise.resolve(); } // 没有设置时间精度,先弹设置UI return this.onfile().then(() => { this.midiFile.import(file); }); } if (parent.Spectrogram._spectrogram && !confirm("本页面已加载音频,是否替换?")) { return Promise.reject(); } // 指示是否完成 let resolve, reject; const donePromise = new Promise((res, rej) => { resolve = res; reject = rej; }); const loadAudio = (URLmode = true) => new Promise((res, rej) => { const fileReader = new FileReader(); // 音频文件错误标志本次会话结束 // 调用loadAudio不需要再写catch fileReader.onerror = (e) => { parent.event.dispatchEvent(new CustomEvent('fileerror', { detail: e })); console.error("FileReader error", e); reject(e); rej(e); }; fileReader.onload = (e) => { res(e.target.result); }; if (URLmode) fileReader.readAsDataURL(file); else fileReader.readAsArrayBuffer(file); }); parent.event.dispatchEvent(new Event('fileui')); // 关闭drag功能 let tempDiv = document.createElement('div'); // 为了不影响下面的事件绑定,midi模式下用display隐藏 const midiModeStyle = midimode ? ' style="display:none;"' : ''; tempDiv.innerHTML = `
${file.name}
每秒的次数:
标准频率A4=
分析声道:
Stereo L+R L-R L R
`; parent.AudioPlayer.name = file.name; const ui = tempDiv.firstElementChild; const close = () => ui.remove(); const checkboxSTFTGPU = ui.querySelector('#stft-gpu'); const checkboxCQT = ui.querySelector('#calc-cqt'); const checkboxGPU = ui.querySelector('#prefer-gpu'); checkboxCQT.onchange = () => { checkboxGPU.parentElement.style.display = checkboxCQT.checked ? 'block' : 'none'; }; const btns = ui.getElementsByTagName('button'); btns[0].onclick = () => { // 进度上传 const input = document.createElement("input"); input.type = "file"; input.onchange = () => { parent.io.projFile.parse(input.files[0]).then((data) => { if (parent.AudioPlayer.name != data[0].name && !confirm(`音频文件与进度(${data[0].name})不同,是否继续?`)) return; // 如果保存的是midi模式,则data[1]是都为undefined的数组 if (Array.isArray(data[1]) && data[1][0] === void 0) { parent.io.projFile.import(data); fakeInput().then(resolve).catch(reject); return; } // 再读取音频看看是否成功 loadAudio(true).then((audioBuffer) => { // 设置音频源 缓存到浏览器 parent.AudioPlayer.createAudio(audioBuffer).then(() => { parent.io.projFile.import(data); // 触发html中的iniEQUI parent.event.dispatchEvent(new CustomEvent('progress', { detail: -1 })); resolve(); }).catch((e) => { parent.event.dispatchEvent(new CustomEvent('fileerror', { detail: e })); console.error("AudioPlayer error", e); reject(e); }).finally(() => { close(); // 不管音频结果如何都要关闭UI parent.event.dispatchEvent(new Event('fileuiclose')); // 恢复drag功能 }); }); }).catch((e) => { // 进度文件错误,允许重试,不reject parent.event.dispatchEvent(new CustomEvent('fileerror', { detail: e })); }); }; input.click(); }; btns[1].onclick = () => { // 取消按钮 close(); parent.event.dispatchEvent(new Event('fileuiclose')); // 恢复drag功能 resolve(false); }; btns[2].onclick = () => { // 确认按钮 // 获取分析参数 const params = ui.querySelectorAll('[name="ui-ask"]'); // getElementsByName只能在document中用 let tNum = params[0].value; let A4 = params[1].value; let channel = 4; for (let i = 2; i < 7; i++) { if (params[i].checked) { channel = parseInt(params[i].value); break; } } close(); parent.midiMode = midimode; //==== midi模式 ====// if (midimode) { // 在Anaylse中的设置全局的 parent.dt = 1000 / tNum; parent.TperP = parent.dt / parent._width; parent.PperT = parent._width / parent.dt; if (parent.Keyboard.freqTable.A4 != A4) parent.Keyboard.freqTable.A4 = A4; fakeInput(0, tNum).then(resolve).catch(reject); parent.event.dispatchEvent(new Event('fileuiclose')); // 恢复drag功能 return; } //==== 音频文件分析 ====// // 打开另一个ui analyse加入回调以显示进度 let tempDiv = document.createElement('div'); tempDiv.innerHTML = `
00%
`; const progressUI = tempDiv.firstElementChild; const progress = progressUI.querySelector('.porgress-value'); const percent = progressUI.querySelector('span'); document.body.insertBefore(progressUI, document.body.firstChild); const onprogress = ({ detail }) => { if (detail < 0) { parent.event.removeEventListener('progress', onprogress); progress.style.width = '100%'; percent.textContent = '100%'; progressUI.style.opacity = 0; setTimeout(() => progressUI.remove(), 200); } else if (detail >= 1) { detail = 1; progress.style.width = '100%'; percent.textContent = "加载界面……"; } else { progress.style.width = (detail * 100) + '%'; percent.textContent = (detail * 100).toFixed(2) + '%'; } }; parent.event.addEventListener('progress', onprogress); // 读取文件 loadAudio(false).then((audioBuffer) => { let channels; // 解码音频文件为音频缓冲区 parent.audioContext.decodeAudioData(audioBuffer).then((decodedData) => { channels = parent.Analyser.selectChannel(decodedData, channel); return Promise.all([ parent.Analyser.stft(channels, tNum, A4, 8192, checkboxSTFTGPU.checked), parent.AudioPlayer.createAudio(URL.createObjectURL(file)) // fileReader.readAsDataURL(file) 将mov文件decode之后变成base64,audio无法播放 故不用 ]); }).then(([v, audio]) => { parent.Spectrogram.spectrogram = v; resolve(); // 后台执行CQT CQT的报错已经被拦截不会冒泡到下面的catch中 if (checkboxCQT.checked) parent.Analyser.cqt( channels, tNum, checkboxCQT.checked && checkboxGPU.checked ); }).catch((e) => { console.error(e); parent.event.dispatchEvent(new CustomEvent('fileerror', { detail: e })); reject(e); }).finally(() => { // 最终都要关闭进度条 parent.event.dispatchEvent(new CustomEvent('progress', { detail: -1 })); parent.event.dispatchEvent(new Event('fileuiclose')); // 恢复drag功能 }); }); }; document.body.insertBefore(ui, document.body.firstChild); // 插入body的最前面 ui.focus(); return donePromise; }; // 进度文件 this.projFile = { export() { if (!parent.Spectrogram._spectrogram) return null; const data = { midi: parent.MidiAction.midi, channel: parent.MidiAction.channelDiv.channel, beat: parent.BeatBar.beats, dt: parent.dt, A4: parent.Keyboard.freqTable.A4, name: parent.AudioPlayer.name }; if (parent.midiMode) return [data, { length: parent.Spectrogram._spectrogram.length }]; // midi模式不保存频谱 else return [data, parent.Spectrogram._spectrogram]; }, import(data) { // data: output of parse [obj, f32] const obj = data[0]; parent.MidiAction.midi = obj.midi; parent.MidiAction.selected = parent.MidiAction.midi.filter((obj) => obj.selected); parent.MidiAction.channelDiv.fromArray(obj.channel); parent.BeatBar.beats.copy(obj.beat); parent.dt = obj.dt; parent.TperP = parent.dt / parent._width; parent.PperT = parent._width / parent.dt; parent.Keyboard.freqTable.A4 = obj.A4; parent.Spectrogram.spectrogram = data[1]; parent.snapshot.save(); }, write(fileName = parent.AudioPlayer.name) { const data = this.export(); bSaver.saveArrayBuffer(bSaver.combineArrayBuffers([ bSaver.String2Buffer("noteDigger"), bSaver.Object2Buffer(data[0]), bSaver.Float32Mat2Buffer(data[1]) ]), fileName + '.nd'); }, parse(file) { return new Promise((resolve, reject) => { bSaver.readBinary(file, (b) => { let [name, o] = bSaver.Buffer2String(b, 0); if (name != "noteDigger") { reject(new Error("incompatible file!")); return; } let [obj, o1] = bSaver.Buffer2Object(b, o); let [f32, _] = bSaver.Buffer2Float32Mat(b, o1); resolve([obj, f32]); }); }); } }; // midi文件 this.midiFile = { export: { UI() { let tempDiv = document.createElement('div'); tempDiv.innerHTML = `
  • 对齐精度
`; const card = tempDiv.firstElementChild; const close = () => { card.remove(); }; const checkbox = card.querySelector('input[type="checkbox"]'); const btns = card.querySelectorAll('button'); btns[0].onclick = close; btns[1].onclick = () => {; const alignRate = parseInt(card.querySelector('input[type="number"]').value); const midi = this.beatAlign(checkbox.checked, alignRate); bSaver.saveArrayBuffer(midi.export(1), midi.name + '.mid'); close(); }; btns[2].onclick = () => { const midi = this.keepTime(checkbox.checked); bSaver.saveArrayBuffer(midi.export(1), midi.name + '.mid'); close(); }; document.body.insertBefore(card, document.body.firstChild); card.tabIndex = 0; card.focus(); }, /** * 100%听感还原扒谱结果,但节奏是乱的 */ keepTime(onlyVisible = false) { const accuracy = 10; const newMidi = new midi(60, [4, 4], Math.round(1000 * accuracy / parent.dt), [], parent.AudioPlayer.name); const mts = []; for (const ch of parent.synthesizer.channel) { let mt = newMidi.addTrack(); mt.addEvent(midiEvent.instrument(0, ch.instrument)); mt._volume = ch.volume; mts.push(mt); } for (const nt of parent.MidiAction.midi) { if (onlyVisible && !parent.MidiAction.channelDiv.channel[nt.ch].visible) continue; const midint = nt.y + 24; let v = mts[nt.ch]._volume; if (nt.v) v = Math.min(127, v * nt.v / 127); mts[nt.ch].addEvent(midiEvent.note(nt.x1 * accuracy, (nt.x2 - nt.x1) * accuracy, midint, v)); } return newMidi; }, beatAlign(onlyVisible = false, alignRate = 2) { alignRate = Math.max(Math.round(alignRate), 2); // 初始化midi let begin = parent.BeatBar.beats[0]; let lastbpm = begin.bpm; // 用于自适应bpm let lastPattern = `${begin.beatNum}/${begin.beatUnit}`; const newMidi = new midi(lastbpm, [begin.beatNum, begin.beatUnit], 480, [], parent.AudioPlayer.name); const mts = []; for (const ch of parent.synthesizer.channel) { let mt = newMidi.addTrack(); mt.addEvent(midiEvent.instrument(0, ch.instrument)); mt._volume = ch.volume; mts.push(mt); } // 将每个音符拆分为两个时刻 const Midis = parent.MidiAction.midi; const mlen = Midis.length << 1; const moment = new Array(mlen); for (let i = 0, j = 0; i < mlen; j++) { const nt = Midis[j]; let duration = nt.x2 - nt.x1; let midint = nt.y + 24; let v = mts[nt.ch]._volume; if (nt.v) v = Math.min(127, v * nt.v / 127); moment[i++] = new midiEvent({ _d: duration, ticks: nt.x1, code: 0x9, value: [midint, v], _ch: nt.ch }, true); moment[i++] = new midiEvent({ _d: duration, ticks: nt.x2, code: 0x9, value: [midint, 0], _ch: nt.ch }, true); } moment.sort((a, b) => a.ticks - b.ticks); // 对每个小节进行对齐 let m_i = 0; // moment的指针 let tickNow = 0; // 维护总时长 for (const measure of parent.BeatBar.beats) { if (m_i == mlen) break; //== 判断小节是否变化 假设小节之间bpm相关性很强 ==// const bpmnow = measure.bpm; if (Math.abs(bpmnow - lastbpm) > lastbpm * 0.065) { mts[0].events.push(midiEvent.tempo(tickNow, bpmnow * 4 / measure.beatUnit)); } lastbpm = bpmnow; const _ptn = `${measure.beatNum}/${measure.beatUnit}`; if (lastPattern !== _ptn) { mts[0].events.push(midiEvent.time_signature(tickNow, measure.beatNum, measure.beatUnit)); } lastPattern = _ptn; //== 对齐音符 ==// const begin = measure.start / parent.dt; // 转换为以“格”为单位 const end = (measure.interval + measure.start) / parent.dt; // 一个八音符的格数 const aot = measure.interval * measure.beatUnit / (measure.beatNum * 8 * parent.dt); while (m_i < mlen) { const n = moment[m_i]; if (n.ticks > end) break; // 给下一小节 m_i++; if (onlyVisible && !parent.MidiAction.channelDiv.channel[n._ch].visible) continue; const threshold = n._d / alignRate; let accuracy = aot; while (accuracy > threshold) accuracy /= 2; n.ticks = tickNow + ((Math.round((n.ticks - begin) / accuracy) * newMidi.tick * accuracy / aot) >> 1); mts[n._ch].events.push(n); } tickNow += newMidi.tick * measure.beatNum * 4 / measure.beatUnit; } return newMidi; } }, /* 由于小节的数据结构,变速只能发生在小节开头 如果考虑节奏,则需要将小节内变速全部忽略 */ import(file) { bSaver.readBinary(file, (data) => { let m; try { m = midi.import(new Uint8Array(data)).JSON(); } catch (error) { console.error("Error importing MIDI:", error); alert("导入MIDI文件时出错"); return; } const chdiv = parent.MidiAction.channelDiv; chdiv.switchUpdateMode(false); // 下面会一次性创建大量音符,所以先关闭更新 let tickTimeTable = m.header.tempos ?? [{ ticks: 0, bpm: 120 }]; if (confirm("是否使用该MIDI的节奏?")) { // 对齐变速和节奏 // 将节奏型和变速事件合并排序 let rhy = [{ticks: -1, timeSignature: [4, 4]}, ...tickTimeTable, ...m.header.timeSignatures]; rhy.sort((a, b) => a.ticks - b.ticks); rhy[0].ticks = 0; // 合并时间相同的 let combined = []; for (let i = 0; i < rhy.length; i++) { const t = rhy[i].ticks; let timeSignature = rhy[i].timeSignature; let bpm = rhy[i].bpm; let j = i + 1; while (j < rhy.length && rhy[j].ticks == t) { bpm = rhy[j].bpm ?? bpm; // 使用最新值 timeSignature = rhy[j].timeSignature ?? timeSignature; j++; } combined.push({ ticks: t, bpm: bpm, timeSignature: timeSignature }); i = j - 1; } // 为中间变速的情况创建小节并分配id combined[0].id = 0; for (let i = 1; i < combined.length; i++) { const c = combined[i]; let j = i - 1; let last = combined[j]; const ticksPerBar = m.header.tick * last.timeSignature[0] * 4 / last.timeSignature[1]; if (c.timeSignature) { // 理论上小节改变不会出现在小节中 但为了兼容奇怪的MIDI需要微调 // 四舍五入到最近的小节开始位置 const bars = Math.round((c.ticks - last.ticks) / ticksPerBar); c.id = bars + last.id; const dt = last.ticks + bars * ticksPerBar - c.ticks; if (dt === 0) continue; // 平移后面所有事件 for (const mt of m.tracks) { const notes = mt.notes; // 找到第一个ticks大于等于c.ticks的事件 let idx = notes.findIndex(ev => ev.ticks >= c.ticks); if (idx === -1) continue; for (let k = idx; k < notes.length; k++) notes[k].ticks += dt; } for (let k = i; k < combined.length; k++) combined[k].ticks += dt; } else { // 如果节奏改变出现在小节中: // 前1/2: 放到小节头; 后1/2: 放到下一个小节头 // 总是创建小节 while (c.ticks < last.ticks) last = combined[--j]; const bars = Math.floor((c.ticks - last.ticks) / ticksPerBar); const offset = c.ticks - last.ticks - bars * ticksPerBar; c.timeSignature = last.timeSignature; if (offset < (ticksPerBar >> 1)) { c.id = last.id + bars; c.ticks = last.ticks + bars * ticksPerBar; } else { c.id = last.id + bars + 1; c.ticks = last.ticks + (bars + 1) * ticksPerBar; } } } // 合并id相同的小节 rhy.length = 0; let lastbpm = 120, lastTimeSignature = [4, 4]; for (let i = 0; i < combined.length; i++) { const c = combined[i]; c.bpm ??= lastbpm; c.timeSignature ??= lastTimeSignature; let j = i + 1; while (j < combined.length && combined[j].id == c.id) { c.bpm = combined[j].bpm ?? c.bpm; c.timeSignature = combined[j].timeSignature ?? c.timeSignature; j++; } rhy.push(c); i = j - 1; lastbpm = c.bpm; lastTimeSignature = c.timeSignature; } tickTimeTable = rhy; // 设置节奏 const beats = parent.BeatBar.beats; beats.length = 0; for (const t of tickTimeTable) { const msPerMeasure = 240000 * t.timeSignature[0] / (t.timeSignature[1] * t.bpm); beats.push(new eMeasure( t.id, -1, t.timeSignature[0], t.timeSignature[1], msPerMeasure )); } beats.check(); } const chArray = []; let chArrayIndex = 0; for (const mt of m.tracks) { if (mt.notes.length == 0) continue; let tickTimeIdx = -1; let startTick = 0; let nexttickTimeChange = 0; let tickTime = 0; // 一个tick的毫秒数/parent.dt let msBefore = 0; // 用parent.dt归一化后的之前的时间 let _timeOffset = 0; const checkChange = (tick) => { while (tick >= nexttickTimeChange) { msBefore += (nexttickTimeChange - startTick) * tickTime; tickTimeIdx++; startTick = nexttickTimeChange; nexttickTimeChange = tickTimeTable[tickTimeIdx + 1]?.ticks ?? Infinity; tickTime = 60000 / (tickTimeTable[tickTimeIdx].bpm * m.header.tick * parent.dt); _timeOffset = msBefore - startTick * tickTime; } return tickTime; }; checkChange(1); const ch = chdiv.addChannel(); if (!ch) break; // 音轨已满,addChannel会返回undefined同时alert,所以只要break const chid = ch.index; ch.name = `导入音轨${chid}`; ch.ch.instrument = mt.instruments[0]?.number || 0; ch.instrument = TinySynth.instrument[ch.ch.instrument]; // 音符强度归一化到0-127 演奏和导出时用的是“通道音量*音符音量/127” let maxIntensity = mt.notes.reduce((a, b) => a.intensity > b.intensity ? a : b).intensity; ch.ch.volume = maxIntensity; chArray[chArrayIndex++] = mt.notes.map((nt) => { let t = checkChange(nt.ticks + 1); const start = _timeOffset + nt.ticks * t; const endTick = nt.ticks + nt.durationTicks; let end; if (endTick > nexttickTimeChange) { // 跨变速区间 // 暂存状态 const store = [tickTimeIdx, startTick, nexttickTimeChange, tickTime, msBefore, _timeOffset]; t = checkChange(nt.ticks + nt.durationTicks + 1); end = _timeOffset + endTick * t; // 恢复状态 [tickTimeIdx, startTick, nexttickTimeChange, tickTime, msBefore, _timeOffset] = store; } else end = _timeOffset + endTick * t; return { // 理应给x1和x2取整,但是为了尽量不损失信息就不取整了 不取整会导致导出midi时要取整 // x1: msBefore + (nt.ticks - startTick) * t, x1: start, x2: end, y: nt.midi - 24, ch: chid, selected: false, v: nt.intensity / maxIntensity * 127 }; }); } for (const ch of chArray) parent.MidiAction.midi.push(...ch); parent.MidiAction.midi.sort((a, b) => a.x1 - b.x1); chdiv.switchUpdateMode(true, true, 0b111); // 打开更新并一次性处理积压请求 }); }, } } ================================================ FILE: core/app_keyboard.js ================================================ /// /** * 左侧键盘 * 会使用 parent.keyboard 画布 * @param {App} parent */ function _Keyboard(parent) { /** * 选中了哪个音,音的编号以midi协议为准(C1序号为24) * 更新链: 'onmousemove' -> parent.mouseY setter -> this.highlight */ this.highlight = -1; this.harmonics = [0]; Object.defineProperty(this, 'Harmonics', { get() { return this.harmonics.length; }, set(n) {// 建议n<=6 n = Math.max(0, n | 0); if (n == this.Harmonics) return; this.harmonics = Array.from({ length: n }, (_, i) => Math.round(12 * Math.log2(i + 1))); } }); this.freqTable = new FreqTable(440); // 在parent.Analyser.stft中更新 // 以下为画键盘所需 const _idchange = new Int8Array([2, 2, 1, 2, 2, 2, -10, 2, 3, 2, 2, 2]); // id变化 const _ychange = new Float32Array(12); // 纵坐标变化,随this.height一起变化 this.setYchange = (h) => { // 需注册到parent.height setter中 且需要一次立即的更新(在parent中实现) _ychange.set([ -1.5 * h, -2 * h, -1.5 * h, -1.5 * h, -2 * h, -2 * h, -1.5 * h, -2 * h, -3 * h, -2 * h, -2 * h, -2 * h ]); }; /** * 仅当: 视野垂直变化 或 this.highlight 更改 时需要更新 * 是否更新的判断 交给parent完成 */ this.render = () => { // 绘制频谱区音符高亮 const actionCtx = parent.layers.action.ctx; actionCtx.fillStyle = "#ffffff4f"; for (let i = this.Harmonics - 1; i >= 0; i--) { let noteY = parent.layers.height - (this.highlight - 24 + this.harmonics[i]) * parent._height + parent.scrollY; if (noteY < 0) continue; actionCtx.fillRect(0, noteY, parent.layers.width, -parent._height); } const ctx = parent.keyboard.ctx; const w = parent.keyboard.width; const w2 = w * 0.618; ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, w, parent.keyboard.height); let noteID = parent.idYstart + 24; // 最下面对应的音的编号 const note = noteID % 12; // 一个八度中的第几个音 let baseY = parent.rectYstart + note * parent._height; // 这个八度左下角的y坐标 noteID -= note; // 这个八度C的编号 while (true) { ctx.beginPath(); // 必须写循环内 ctx.fillStyle = 'orange'; for (let i = 0, rectY = baseY, id = noteID; i < 7 & rectY > 0; i++) { // 画白键 let dy = _ychange[i]; if (this.highlight == id) ctx.fillRect(0, rectY, w, dy); // 被选中的 ctx.moveTo(0, rectY); // 画线即可 下划线 ctx.lineTo(w, rectY); rectY += dy; id += _idchange[i]; } ctx.stroke(); // 写音阶名 ctx.fillStyle = "black"; ctx.fillText(Math.floor(noteID / 12) - 1, w - parent._height * 0.75, baseY - parent._height * 0.3); baseY -= parent._height; noteID++; for (let i = 7; i < 12; i++) { if (this.highlight == noteID) { // 考虑到只要画一次高亮,不必每次都改fillStyle ctx.fillStyle = '#Ffa500ff'; ctx.fillRect(0, baseY, w2, -parent._height); ctx.fillStyle = 'black'; } else ctx.fillRect(0, baseY, w2, -parent._height); baseY += _ychange[i]; noteID += _idchange[i]; if (baseY < 0) return; } } }; // 鼠标点击后发声 this.mousedown = () => { let ch = parent.MidiAction.channelDiv.selected; if (!ch || ch.mute) return; ch = ch ? ch.ch : parent.synthesizer; let nt = ch.play({ f: this.freqTable[this.highlight - 24] }); let last = this.highlight; // 除颤 const tplay = parent.audioContext.currentTime; const move = () => { if (last === this.highlight) return; last = this.highlight; let dt = parent.audioContext.currentTime - tplay; parent.synthesizer.stop(nt, dt > 0.3 ? 0 : dt - 0.3); nt = ch.play({ f: this.freqTable[this.highlight - 24] }); }; document.addEventListener('mousemove', move); const up = () => { let dt = parent.audioContext.currentTime - tplay; parent.synthesizer.stop(nt, dt > 0.5 ? 0 : dt - 0.5); document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', up); }; document.addEventListener('mouseup', up); }; } ================================================ FILE: core/app_midiaction.js ================================================ /// /** * 管理用户在钢琴卷帘上的动作 * @param {App} parent */ function _MidiAction(parent) { this.clickX = 0; // 绝对坐标 单位像素 this.clickYid = 0; // 离散坐标 单位离散格 this.mode = 0; // 0: 笔模式 1: 选择模式 this.frameMode = 0; // 0: 框选 1: 列选 2: 行选 this.frameXid = -1; // 框选的终点的X序号(Y序号=this.Keyboard.highlight-24) 此变量便于绘制 如果是负数则不绘制 this.alphaIntensity = true; // 绘制音符时是否根据音量使用透明度 this.snapMode = 1; // 0: 不吸附 1: 吸附到网格线 -1: 吸附到小节线 /** * 根据snapMode吸附x坐标到不同的位置 * @param {number} x x是全局位置 单位:像素 * @returns [l, r] 除以 parent.width 后是相对于谱面起点的坐标,和最短的下一个位置 */ this.snapRound = (x) => { // 最短为一个像素 if (this.snapMode == 0) return [x / parent._width, (x + 1) / parent._width]; // 最短一格 if (this.snapMode == 1) { let i = x / parent._width | 0; return [i, i + 1]; } // 小节吸附 const m = parent.BeatBar.beats.getMeasure(Math.max(0, x * parent.TperP), true); const start = m.start * parent.PperT; const Interval = m.interval * parent.PperT; const dp = Interval / m.beatNum; // 没有细分 if (dp < parent.BeatBar.minInterval) return [start, start + Interval]; // 细分 和_BeatBar.render的逻辑一致 const noteNum = 1 << Math.log2(dp / parent.BeatBar.minInterval); const subDp = dp / noteNum; const n = ((x - start) / subDp | 0) * subDp + start; return [n / parent._width, (n + subDp) / parent._width]; }; /* 一个音符 = { y: 离散 和spectrum的y一致 x1: 离散 起点 x2: 离散 终点 ch: 音轨序号 selected: 是否选中 v: 音量,0~127,用户创建的音符无此选项,但导入的midi有 需要undefined兼容 } */ this.selected = []; // 选中的音符 无序即可 this.midi = []; // 所有音符 需要维护有序性 var _anyAction = false; // 用于在选中多个后判断松开鼠标时应该如何处理选中 if (!parent.synthesizer) throw new Error('MidiAction requires a synthesizer to be created.'); const cd = this.channelDiv = new ChannelList(document.getElementById('funcSider'), parent.synthesizer); // 导入midi时创建音轨不应该update,而是应该在音符全创建完成后存档 cd.updateCount = -1; // -1表示需要update 否则表示禁用更新但记录了请求次数 cd.switchUpdateMode = (state, forceUpdate = false, type = 0b11) => { // 控制音轨的更新 if (state) { // 切换回使能update if (cd.updateCount > 0 || forceUpdate) { // 如果期间有更新请求 this.updateView(); parent.snapshot.save(type); } cd.updateCount = -1; } else if (cd.updateCount < 0) { // 如果是从true切换为false cd.updateCount = 0; } } const updateOnReorder = () => { if (cd.updateCount < 0) { this.updateView(); parent.snapshot.save(0b11); } else cd.updateCount++; }; /** * 触发add和remove后也可能会触发reorder,取决于增删的是否是最后一项(见channelDiv.js) * 故不是总能触发reorder的更新存档功能updateOnReorder * 而更新与存档必须在reorder之后,因为reorder会重新映射channel * 为了避免重复存档,需要暂时屏蔽reorder的存档功能 * 等到reorder之后一定会发生的added和removed事件触发后再恢复 */ const resumeReroderCallback = () => { updateOnReorder(); // 稳定触发 cd.addEventListener('reorder', updateOnReorder); }; cd.addEventListener('reorder', ({ detail }) => { for (const nt of this.midi) nt.ch = detail[nt.ch]; }); // 重新映射音符 更新视图在updateOnReorder中 cd.addEventListener('reorder', updateOnReorder); cd.addEventListener('remove', ({ detail }) => { this.midi = this.midi.filter((nt) => nt.ch != detail.index); this.selected = this.selected.filter((nt) => nt.ch != detail.index); cd.removeEventListener('reorder', updateOnReorder); }); cd.addEventListener('removed', resumeReroderCallback); cd.addEventListener('add', () => { cd.removeEventListener('reorder', updateOnReorder); }); cd.addEventListener('added', resumeReroderCallback); const saveOnStateChange = () => { parent.snapshot.save(0b1); } cd.container.addEventListener('lock', ({ target }) => { this.selected = this.selected.filter((nt) => { if (nt.ch == target.index) return nt.selected = false; return true; }); }); cd.container.addEventListener('lock', saveOnStateChange); // cd.container.addEventListener('visible', saveOnStateChange); // visible会联动lock,因此无需存档 cd.container.addEventListener('mute', saveOnStateChange); cd.addEventListener('setted', saveOnStateChange); this.insight = []; // 二维数组,每个元素为一个音轨视野内的音符 音符拾取依赖此数组 /** * 更新this.MidiAction.insight * 步骤繁琐,不必每次更新。触发时机: * 1. channelDiv的reorder、added、removed,实际为updateOnReorder和switchUpdateMode * 2. midi的增加、移动、改变长度(用户操作)。由于都会调用且最后调用changeNoteY,所以只需要在changeNoteY中调用 * 3. scroll2 * 4. midi的删除(用户操作):deleteNote * 5. ctrlZ、ctrlY、ctrlV */ this.updateView = () => { const m = this.midi; const channel = Array.from(this.channelDiv.channel, () => []); this.insight = channel; // 原来用的二分有bug,所以干脆全部遍历 for (const nt of m) { if (nt.x1 >= parent.idXend) break; if (nt.x2 < parent.idXstart) continue; if (nt.y < parent.idYstart || nt.y >= parent.idYend) continue; channel[nt.ch].push(nt); } // midi模式下,视野要比音符宽一页,或超出视野半页 if (parent.midiMode) { const currentLen = parent.Spectrogram.spectrogram.length; const apage = parent.layers.width / parent._width; let minLen = (m.length ? m[m.length - 1].x2 : 0) + apage * 1.5 | 0; let viewLen = parent.idXstart + apage | 0; // 如果视野在很外面,需要保持视野 if (viewLen > minLen) minLen = viewLen; if (minLen != currentLen) parent.Spectrogram.spectrogram.length = minLen; // length触发audio.duration和this.xnum } parent.layers.action.dirty = true; }; this.render = () => { // 按照insight绘制音符 const m = this.insight; const s = parent.layers.action.ctx; const c = this.channelDiv.channel; for (let ch = m.length - 1; ch >= 0; ch--) { if (m[ch].length === 0 || !c[ch].visible) continue; let ntcolor = c[ch].color; if (c[ch].lock) s.setLineDash([5, 5]); for (const note of m[ch]) { const params = [note.x1 * parent._width - parent.scrollX, parent.layers.height - note.y * parent._height + parent.scrollY, (note.x2 - note.x1) * parent._width, -parent._height]; if (note.selected) { s.fillStyle = '#ffffff'; s.fillRect(...params); s.strokeStyle = ntcolor; s.strokeRect(...params); } else { if (this.alphaIntensity && note.v) { s.fillStyle = ntcolor + Math.round(note.v ** 2 * 0.01581).toString(16); // 平方律显示强度 } else s.fillStyle = ntcolor; s.fillRect(...params); s.strokeStyle = '#ffffff'; s.strokeRect(...params); } } s.setLineDash([]); } if (!this.mode || this.frameXid < 0) return; // 绘制框选动作 s.fillStyle = '#f0f0f088'; const clickXid = this.clickX / parent._width | 0; let [xmin, xmax] = clickXid <= this.frameXid ? [clickXid, this.frameXid + 1] : [this.frameXid, clickXid + 1]; const Y = parent.Keyboard.highlight - 24; let [ymin, ymax] = Y <= this.clickYid ? [Y, this.clickYid + 1] : [this.clickYid, Y + 1]; let x1, x2, y1, y2; if (this.frameMode == 1) { // 列选 x1 = xmin * parent._width - parent.scrollX; x2 = (xmax - xmin) * parent._width; y1 = 0; y2 = parent.layers.height; } else if (this.frameMode == 2) { // 行选 x1 = 0; x2 = parent.layers.width; y1 = parent.layers.height - ymax * parent._height + parent.scrollY; y2 = (ymax - ymin) * parent._height; } else { // 框选 x1 = xmin * parent._width - parent.scrollX; x2 = (xmax - xmin) * parent._width; y1 = parent.layers.height - ymax * parent._height + parent.scrollY; y2 = (ymax - ymin) * parent._height; } s.fillRect(x1, y1, x2, y2); }; /** * 删除选中的音符 触发updateView * @param {boolean} save 是否存档 */ this.deleteNote = (save = true) => { this.selected.forEach((v) => { let i = this.midi.indexOf(v); if (i != -1) this.midi.splice(i, 1); }); this.selected.length = 0; if (save) parent.snapshot.save(0b10); this.updateView(); }; this.clearSelected = () => { // 取消已选 this.selected.forEach(v => { v.selected = false; }); this.selected.length = 0; }; var _tempdy = 0; this.changeNoteY = () => { // 要求在trackMouse之后添加入spectrum的mousemoveEnent _anyAction = true; let dy = parent.Keyboard.highlight - 24 - this.clickYid; this.selected.forEach((v) => { v.y += dy - _tempdy; }); _tempdy = dy; this.updateView(); }; // 记录操作音符时之前的值 由于changeNoteX和changeNoteDuration 互斥,因此共用 var prevValue = null; /** * 改变选中的音符的时长 需要保证和changeNoteX同时只能使用一个 * @param {MouseEvent} e */ this.changeNoteDuration = (e) => { _anyAction = true; // 兼容窗口滑动,以绝对坐标进行运算 let dx = e.offsetX + parent.scrollX - this.clickX; // 此时prevValue存的是音符的v2*width值 for (let i = 0; i < prevValue.length; i++) { const v = this.selected[i]; const [l, r] = this.snapRound(prevValue[i] + dx); if (v.x1 >= r) { const [_, nr] = this.snapRound(v.x1 * parent._width); v.x2 = nr; } else v.x2 = r; } }; this.changeNoteX = (e) => { // 由this.onclick_L调用 _anyAction = true; let dx = e.offsetX + parent.scrollX - this.clickX; // 此时prevValue存的是音符的v1*width值 for (let i = 0; i < prevValue.length; i++) { const v = this.selected[i]; const d = v.x2 - v.x1; const [l, r] = this.snapRound(prevValue[i] + dx); v.x1 = Math.max(0, l); v.x2 = v.x1 + d; } }; // 封装事件管理 const startMove = () => { prevValue = this.selected.map(v => v.x1 * parent._width); parent.layerContainer.addEventListener('mousemove', this.changeNoteX); parent.layerContainer.addEventListener('mousemove', this.changeNoteY); const removeEvent = () => { parent.layerContainer.removeEventListener('mousemove', this.changeNoteX); parent.layerContainer.removeEventListener('mousemove', this.changeNoteY); document.removeEventListener('mouseup', removeEvent); this.midi.sort((a, b) => a.x1 - b.x1); // 排序非常重要 因为查找被点击的音符依赖顺序 // 鼠标松开则存档 if (_anyAction) parent.snapshot.save(0b10); }; document.addEventListener('mouseup', removeEvent); }; const startDurationChange = () => { prevValue = this.selected.map(v => v.x2 * parent._width); parent.layerContainer.addEventListener('mousemove', this.changeNoteDuration); parent.layerContainer.addEventListener('mousemove', this.changeNoteY); const removeEvent = () => { parent.layerContainer.removeEventListener('mousemove', this.changeNoteDuration); parent.layerContainer.removeEventListener('mousemove', this.changeNoteY); document.removeEventListener('mouseup', removeEvent); // 鼠标松开则存档 if (_anyAction) parent.snapshot.save(0b10); }; document.addEventListener('mouseup', removeEvent); }; /** * 框选音符的鼠标动作 由this.onclick_L调用 * 选中的标准:框住了音头 */ this.selectAction = (mode = 0) => { const clickXid = this.clickX / parent._width | 0; // 选择动作永远以格点为准 this.frameXid = clickXid; // 先置大于零,表示开始绘制 if (mode == 1) { // 列选 parent.layerContainer.addEventListener('mousemove', parent.trackMouseX); const up = () => { parent.layerContainer.removeEventListener('mousemove', parent.trackMouseX); document.removeEventListener('mouseup', up); let ch = this.channelDiv.selected; if (ch && !ch.lock) { ch = ch.index; let [xmin, xmax] = clickXid <= this.frameXid ? [clickXid, this.frameXid + 1] : [this.frameXid, clickXid + 1]; for (const nt of this.midi) nt.selected = (nt.x1 >= xmin && nt.x1 < xmax && nt.ch == ch); this.selected = this.midi.filter(v => v.selected); } this.frameXid = -1; }; document.addEventListener('mouseup', up); } else if (mode == 2) { // 行选 const up = () => { document.removeEventListener('mouseup', up); let ch = this.channelDiv.selected; if (ch && !ch.lock) { ch = ch.index; const Y = parent.Keyboard.highlight - 24; let [ymin, ymax] = Y <= this.clickYid ? [Y, this.clickYid + 1] : [this.clickYid, Y + 1]; for (const nt of this.midi) nt.selected = (nt.y >= ymin && nt.y < ymax && nt.ch == ch); this.selected = this.midi.filter(v => v.selected); } this.frameXid = -1; }; document.addEventListener('mouseup', up); } else { // 框选 parent.layerContainer.addEventListener('mousemove', parent.trackMouseX); const up = () => { parent.layerContainer.removeEventListener('mousemove', parent.trackMouseX); document.removeEventListener('mouseup', up); let ch = this.channelDiv.selected; if (ch && !ch.lock) { ch = ch.index; const Y = parent.Keyboard.highlight - 24; let [xmin, xmax] = clickXid <= this.frameXid ? [clickXid, this.frameXid + 1] : [this.frameXid, clickXid + 1]; let [ymin, ymax] = Y <= this.clickYid ? [Y, this.clickYid + 1] : [this.clickYid, Y + 1]; for (const nt of this.midi) nt.selected = (nt.x1 >= xmin && nt.x1 < xmax && nt.y >= ymin && nt.y < ymax && nt.ch == ch); this.selected = this.midi.filter(v => v.selected); } this.frameXid = -1; // 表示不在框选 }; document.addEventListener('mouseup', up); } }; /** * 添加音符的鼠标动作 由this.onclick_L调用 */ this.addNoteAction = () => { if (!this.channelDiv.selected && !this.channelDiv.selectChannel(0)) return; // 如果没有选中则默认第一个 if (this.channelDiv.selected.lock) return; // 锁定的音轨不能添加音符 // 取消已选 this.clearSelected(); // 添加新音符,设置已选 const [x1, x2] = this.snapRound(this.clickX); const note = { y: this.clickYid, x1, x2, ch: this.channelDiv.selected.index, selected: true }; this.selected.push(note); { // 二分插入 let l = 0, r = this.midi.length; while (l < r) { let mid = (l + r) >> 1; if (this.midi[mid].x1 < note.x1) l = mid + 1; else r = mid; } this.midi.splice(l, 0, note); } _anyAction = true; this.updateView(); startDurationChange(); }; /** * MidiAction所有鼠标操作都由此分配 */ this.onclick_L = (e) => { //== step 1: 判断是否点在了音符上 ==// _anyAction = false; // 为了支持在鼠标操作的时候能滑动,记录绝对位置 _tempdy = 0; const x = (this.clickX = e.offsetX + parent.scrollX) / parent._width; if (x >= parent._xnum) { // 越界 this.clearSelected(); return; } const y = this.clickYid = parent.Keyboard.highlight - 24; // 找到点击的最近的音符 由于点击不经常,所以用遍历足矣 只需要遍历insight的音符 let n = null; for (let ch_id = 0; ch_id < this.insight.length; ch_id++) { const chitem = this.channelDiv.channel[ch_id] // insight和channelDiv的顺序是一致的 if (!chitem.visible || chitem.lock) continue; // 隐藏、锁定的音轨选不中 const ch = this.insight[ch_id]; // 每层挑选左侧最靠近的(如果有多个) let distance = parent._width * parent._xnum; for (const nt of ch) { // 由于来自midi,因此每个音轨内部是有序的 let dis = x - nt.x1; if (dis < 0) break; if (y == nt.y && x < nt.x2) { if (dis < distance) { distance = dis; n = nt; } } } if (n) break; // 只找最上层的 } if (!n) { // 添加或框选音符 关于lock的处理在函数中 if (this.mode) this.selectAction(this.frameMode); else this.addNoteAction(); return; } this.channelDiv.selectChannel(n.ch); //== step 2: 如果点击到了音符,ctrl是否按下 ==/ if (e.ctrlKey) { // 有ctrl表示多选 if (n.selected) { // 已经选中了,取消选中 this.selected.splice(this.selected.indexOf(n), 1); n.selected = false; } else { // 没选中,添加选中 this.selected.push(n); n.selected = true; } return; } //== step 3: 单选时,是否选中了多个(事关什么时候取消选中) ==// if (this.selected.length > 1 && n.selected) { // 如果选择了多个,在松开鼠标的时候处理选中 const up = () => { if (!_anyAction) { // 没有任何拖拽动作,说明为了单选 this.selected.forEach(v => { v.selected = false; }); this.selected.length = 0; n.selected = true; this.selected.push(n); } document.removeEventListener('mouseup', up); }; document.addEventListener('mouseup', up); } else { // 只选一个 if (n.selected) { const up = () => { if (!_anyAction) { // 没有任何拖拽动作,说明为了取消选中 this.selected.forEach(v => { v.selected = false; }); this.selected.length = 0; } document.removeEventListener('mouseup', up); }; document.addEventListener('mouseup', up); } else { this.selected.forEach(v => { v.selected = false; }); this.selected.length = 0; n.selected = true; this.selected.push(n); } } //== step 4: 如果点击到了音符,添加移动事件 ==// if (((e.offsetX + parent.scrollX) << 1) > (n.x2 + n.x1) * parent._width) { // 靠近右侧,调整时长 startDurationChange(); } else { // 靠近左侧,调整位置 startMove(); } }; } ================================================ FILE: core/app_midiplayer.js ================================================ /** * 管理用户绘制的midi的播放 * @param {App} parent */ function _MidiPlayer(parent) { this.priorT = 1000 / 59; // 实际稳定在60帧,波动极小 this.realT = 1000 / 59; this._last = performance.now(); this.lastID = -1; this.restart = (onlyBeat = false) => { // 需要-1,防止当前时刻开始的音符不被播放 const msnow = parent.AudioPlayer.audio.currentTime * 1000; if (!onlyBeat) this.lastID = ((msnow / parent.dt) | 0) - 1; this._beatIter = parent.BeatBar.beats.iterator(msnow, true); const p = this._beatIter.next(); if (p.done === false) { const m = p.value; this._beatNowEnds = m.start + m.interval; } else { this._beatNowEnds = -1; } }; this.update = () => { // 一阶预测 let tnow = performance.now(); // 由于requestAnimationFrame在离开界面的时候会停止,所以要设置必要的限定 if (tnow - this._last < (this.priorT << 1)) this.realT = 0.2 * (tnow - this._last) + 0.8 * this.realT; // IIR低通滤波 this._last = tnow; if (parent.AudioPlayer.audio.paused) return; const dt = 1e-3 / parent.AudioPlayer.audio.playbackRate; const predictT = parent.time + 0.5 * (this.realT + this.priorT); // 先验和实测的加权和 const predictID = (predictT / parent.dt) | 0; // 寻找(mp.lastID, predictID]之间的音符 const m = parent.MidiAction.midi; if (m.length > 0) { // 二分查找要求长度大于0 let lastAt = m.length; { // 二分查找到第一个x1>mp.lastID的音符 let l = 0, r = lastAt - 1; while (l <= r) { let mid = (l + r) >> 1; if (m[mid].x1 > this.lastID) { r = mid - 1; lastAt = mid; } else l = mid + 1; } } for (; lastAt < m.length; lastAt++) { const nt = m[lastAt]; if (nt.x1 > predictID) break; if (parent.MidiAction.channelDiv.channel[nt.ch].mute) continue; parent.synthesizer.play({ id: nt.ch, f: parent.Keyboard.freqTable[nt.y], v: nt.v, // 用户创建的音符不可单独调整音量,为undefined,会使用默认值 t: (parent.time - nt.x1 * parent.dt) * dt, last: (nt.x2 - nt.x1) * parent.dt * dt }); } } // 节拍播放 if (this._ifBeat && this._beatNowEnds > 0) { const endms = this._beatNowEnds; // 较为宽裕的时间判断 if (endms < predictT + this.priorT) { this.playBeatSound(parent.audioContext.currentTime + (endms - parent.time) * dt); const p = this._beatIter.next(); if (p.done === false) { const m = p.value; this._beatNowEnds = m.start + m.interval; } else { this._beatNowEnds = -1; } } } this.lastID = predictID; }; // 播放节拍 this._ifBeat = false; this._beatIter = null; this._beatNowEnds = -1; this.switchBeatMode = (ifBeat) => { this._ifBeat = ifBeat; if (ifBeat === false) return; this.initBeatSound().then(() => { if (parent.AudioPlayer.audio.paused === false) this.restart(true); }); }; this.beatBuffer = null; this.initBeatSound = async () => { if (this.beatBuffer) return; try { // 利用 fetch 转换 Base64 为 ArrayBuffer const CLICK_SOUND_BASE64 = "data:audio/mpeg;base64,SUQzBAAAAAABRlRFTkMAAAAMAAADT3JpZ2luYXRvcgBUWFhYAAAAKgAAA29yaWdpbmF0b3JfcmVmZXJlbmNlAE9yaWdpbmF0b3JSZWZlcmVuY2UAVERSQwAAAAwAAAMyMDAwOjAwOjAwAFRYWFgAAAAeAAADY29kaW5nX2hpc3RvcnkAQ29kaW5nSGlzdG9yeQBUWFhYAAAAEgAAA3RpbWVfcmVmZXJlbmNlADAAVFNTRQAAAA4AAANMYXZmNjIuNC4xMDAAAAAAAAAAAAAAAP/7UMAAAAAAAAAAAAAAAAAAAAAAAEluZm8AAAAPAAAAAgAAAnEAqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv//////////////////////////////////////////////////////////////////AAAAAExhdmM2Mi4xMwAAAAAAAAAAAAAAACQEWgAAAAAAAAJxo1jtAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+1DEAAAJTFdXNBSAAZig7j8woAD1QEAAAIAJQAUExuAC/vf4Qyc5oyMVo9UFYJgmCYJhsnB8EDkH38QA+UBCJAQBAEHMg+D/wffg4GC4Pg+7+oHz5QEP+UDHOf4IAhl6hqZmRkhAAA2Gw2GAwIAmkAHzrD7iq7X2AqopRMhZ060gz1e2F2Ng2m1AtBbGIrF+IwgRk5RPyEesIcvUwet9xkRllReab+aw4cTGp5rf5EyEI9IGY3///RCJomX/8Akgk06BXPUgABsYAFWM2a0N//tSxAUDy817Jv2FAAgAADSAAAAET0ApeqwoITVM6TNhUkXiVM41cLoCkA0DURhcgUQKINoiiZ6mkI9HpykJKab6mmmmzjjWOOepptc447mm6HHHfzjv6///////6Hf//oc+v//1NNIRqkxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo="; const response = await fetch(CLICK_SOUND_BASE64); const arrayBuffer = await response.arrayBuffer(); this.beatBuffer = await parent.audioContext.decodeAudioData(arrayBuffer); } catch (e) { alert("节拍音频解码失败:", e); } }; this.playBeatSound = (time = 0) => { if (!this.beatBuffer) return; const source = parent.audioContext.createBufferSource(); source.buffer = this.beatBuffer; source.connect(parent.audioContext.destination); source.start(time); }; } ================================================ FILE: core/app_spectrogram.js ================================================ /** * 管理频谱显示 * 会使用 parent.layers.spectrum 画布 * @param {App} parent */ function _Spectrogram(parent) { this.colorStep1 = 90; this.colorStep2 = 240; this._multiple = parseFloat(document.getElementById('multiControl').value); // 幅度的倍数 Object.defineProperty(this, 'multiple', { get: function() { return this._multiple; }, set: function(m) { this._multiple = m; parent.layers.spectrum.dirty = true; } }); this._contrast = parseFloat(document.getElementById('contrastControl').value); // 对比度 Object.defineProperty(this, 'contrast', { get: function() { return this._contrast; }, set: function(c) { this._contrast = c; parent.layers.spectrum.dirty = true; } }); this._Hmultiple = 1; // 谐波的倍数 Object.defineProperty(this, 'Hmultiple', { get: function() { return this._Hmultiple; }, set: function(m) { this._Hmultiple = m; parent.layers.spectrum.dirty = true; } }); this._spectrogram = null; // .raw属性为底层一维buffer Object.defineProperty(this, 'spectrogram', { get: function() { return this._spectrogram; }, set: function(s) { if (!s) { this._spectrogram = this.harmonic = null; parent.xnum = 0; } else { if (s.raw != this._spectrogram?.raw) { this._spectrogram = s; this.harmonic = null; } parent.xnum = s.length; parent.scroll2(); } } }); this.harmonic = null; // 对谐波的估计 在parent.Analyser._reduceHarmonic中计算得到 this.getColor = (value) => { // 0-step1,是蓝色的亮度从0变为50%;step1-step2,是颜色由蓝色变为红色;step2-255,保持红色 value = value || 0; // 防NaN if (value < 0) value = 0; let hue = 0, lightness = 50; // Red hue if (value <= this.colorStep1) { hue = 240; // Blue hue lightness = (value / this.colorStep1) * 50; // Lightness from 0% to 50% } else if (value <= this.colorStep2) { hue = 240 - ((value - this.colorStep1) / (this.colorStep2 - this.colorStep1)) * 240; } return `hsl(${hue}, 100%, ${lightness}%)`; }; // 预计算颜色查找表 this.colorLUT = ((LUT_SIZE = 384) => { const c = new OffscreenCanvas(LUT_SIZE, 1); const ctx = c.getContext('2d', { alpha: false }); for (let i = 0; i < LUT_SIZE; i++) { const value = (i / (LUT_SIZE - 1)) * 255; ctx.fillStyle = this.getColor(value); ctx.fillRect(i, 0, 1, 1); } const data = ctx.getImageData(0, 0, LUT_SIZE, 1).data; // 检测平台字节序 const littleEndian = (function() { const buf = new ArrayBuffer(4); new DataView(buf).setUint32(0, 0x12345678, true); return new Uint8Array(buf)[0] === 0x78; })(); let u32 = new Uint32Array(LUT_SIZE); u32.scale = (LUT_SIZE - 1) / 255; for (let i = 0; i < LUT_SIZE; i++) { const idx = i << 2; const r = data[idx], g = data[idx + 1], b = data[idx + 2], a = 255; // 小端: ARGB 大端: RGBA u32[i] = littleEndian ? (a << 24) | (b << 16) | (g << 8) | r : (r << 24) | (g << 16) | (b << 8) | a; } return u32; })(); // 闭包存储 var imageData = null; var dataCanvas = null; this.onresize = () => { // 在parent.width / parent.height / parent.resize 中被调用 const canvas = parent.layers.spectrum; const ctx = canvas.ctx; // 实际视图的最大行列数 let cols = Math.ceil(canvas.width / parent._width) + 1, rows = Math.ceil(canvas.height / parent._height) + 1; // 频谱列主序 这里存转置后的 imageData = ctx.createImageData(rows, cols); ctx.imageSmoothingEnabled = parent._width < 1 || parent._height < 1; imageData.u32 = new Uint32Array(imageData.data.buffer); if (dataCanvas) { dataCanvas.width = rows; dataCanvas.height = cols; } else { dataCanvas = new OffscreenCanvas(rows, cols); dataCanvas.ctx = dataCanvas.getContext('2d', { alpha: false }); } ctx.strokeStyle = "#FFFFFF"; // 分界线颜色 ctx.fillStyle = '#25262d'; // 背景颜色 }; // 供外部调用的接口 返回一个可以用[][]访问的对象 值为最终计算结果 this.getCurrentSpectrum = () => { const _this = this; const view = { length: this._spectrogram.length, buffer: new Float32Array(this._spectrogram[0].length), currentFrame: -1 }; return new Proxy(view, { get(target, prop) { if (prop in target) return target[prop]; const frameID = parseInt(prop); if (isNaN(frameID) || frameID < 0 || frameID >= target.length) return undefined; const b = target.buffer; if (frameID === target.currentFrame) return b; const s = _this._spectrogram[frameID]; const h = _this.harmonic?.[frameID]; if (h) for (let i = 0; i < b.length; i++) { let amp = s[i] - h[i] * _this._Hmultiple; b[i] = Math.pow(Math.max(0, amp), _this._contrast) * _this._multiple; } else for (let i = 0; i < b.length; i++) { b[i] = Math.pow(Math.max(0, s[i]), _this._contrast) * _this._multiple; } target.currentFrame = frameID; return b; } }); }; this.renderSpectrum = (ctx) => { // 填充数据到imagerData 随spectrum的列主序 for (let frameID = parent.idXstart, x = 0, off = 0; frameID < parent.idXend; frameID++, x++, off += imageData.width) { const s = this._spectrogram[frameID]; const h = this.harmonic?.[frameID]; for (let y = parent.idYstart, j = off; y < parent.idYend; y++, j++) { let amp = s[y] - (h?.[y] ?? 0) * this._Hmultiple; amp = Math.pow(Math.max(0, amp), this._contrast) * this._multiple; const colorID = Math.min(this.colorLUT.length - 1, Math.round(amp * this.colorLUT.scale)); imageData.u32[j] = this.colorLUT[colorID]; } } dataCanvas.ctx.putImageData(imageData, 0, 0); // 把dataCanvas画到目标canvas上 drawImage 承担三个任务:旋转、缩放、偏移 ctx.save(); ctx.translate(0, 0); ctx.rotate(-Math.PI * 0.5); ctx.drawImage( dataCanvas, 0, 0, imageData.width, imageData.height, -parent.rectYstart, parent.rectXstart, imageData.width * parent._height, imageData.height * parent._width ); ctx.restore(); } this.render = ({ctx, width, height}) => { if (this._spectrogram) this.renderSpectrum(ctx); // 填涂剩余部分 let end = parent.idXend * parent._width - parent.scrollX; let w = width - end; if (w > 0) ctx.fillRect(end, 0, w, height); // 绘制分界线 ctx.beginPath(); for (let y = (((parent.idYstart / 12) | 0) + 1) * 12, rectY = height - parent._height * y + parent.scrollY, dy = -12 * parent._height; y < parent.idYend; y += 12, rectY += dy) { ctx.moveTo(0, rectY); ctx.lineTo(width, rectY); } ctx.stroke(); }; } ================================================ FILE: core/app_timebar.js ================================================ /// /** * 顶部时间轴 * @param {App} parent */ function _TimeBar(parent) { this.interval = 10; // 每个标注的间隔块数 在updateInterval中更新 // 重复区间参数 单位:毫秒 如果start>end则区间不起作用 this.repeatStart = -1; this.repeatEnd = -1; /** * 设置重复区间专用函数 便于统一管理行为副作用 * @param {number || null} start 单位:毫秒 * @param {number || null} end 单位:毫秒 */ this.setRepeat = (start = null, end = null) => { if (start !== null) this.repeatStart = start; if (end !== null) this.repeatEnd = end; }; /** * 毫秒转 分:秒:毫秒 * @param {number} ms 毫秒数 * @returns [分,秒,毫秒] */ this.msToClock = (ms) => { return [ Math.floor(ms / 60000), Math.floor((ms % 60000) / 1000), ms % 1000 | 0 ]; }; this.msToClockString = (ms) => { const t = this.msToClock(ms); return `${t[0].toString().padStart(2, "0")}:${t[1].toString().padStart(2, "0")}:${t[2].toString().padStart(3, "0")}`; }; // timeBar的上半部分画时间轴 并绘制工作区重复区间和时间指针 this.render = () => { const canvas = parent.timeBar; const ctx = parent.timeBar.ctx; let idstart = Math.ceil(parent.idXstart / this.interval - 0.1); // 画面中第一个时间点的序号 let dt = this.interval * parent.dt; // 时间的步长 let dp = parent.width * this.interval; // 像素的步长 let timeAt = dt * idstart; // 对应的毫秒 let p = idstart * dp - parent.scrollX; // 对应的像素 let h = canvas.height >> 1; // 上半部分 ctx.fillStyle = '#25262d'; ctx.fillRect(0, 0, canvas.width, h); ctx.fillStyle = '#8e95a6'; //== 画刻度 标时间 ==// ctx.strokeStyle = '#ff0000'; ctx.beginPath(); for (let endPix = canvas.width + (dp >> 1); p < endPix; p += dp, timeAt += dt) { ctx.moveTo(p, 0); ctx.lineTo(p, h); ctx.fillText(this.msToClockString(timeAt), p - 28, 16); } ctx.stroke(); //== 画重复区间 ==// let begin = parent._width * this.repeatStart / parent.dt - parent.scrollX; // 单位:像素 let end = parent._width * this.repeatEnd / parent.dt - parent.scrollX; const spectrum = parent.layers.action.ctx; const spectrumHeight = parent.layers.height; // 画线 if (begin >= 0 && begin < canvas.width) { // 画左边 ctx.beginPath(); spectrum.beginPath(); ctx.strokeStyle = spectrum.strokeStyle = '#20ff20'; ctx.moveTo(begin, 0); ctx.lineTo(begin, canvas.height); spectrum.moveTo(begin, 0); spectrum.lineTo(begin, spectrumHeight); ctx.stroke(); spectrum.stroke(); } if (end >= 0 && end < canvas.width) { // 画右边 ctx.beginPath(); spectrum.beginPath(); ctx.strokeStyle = spectrum.strokeStyle = '#ff2020'; ctx.moveTo(end, 0); ctx.lineTo(end, canvas.height); spectrum.moveTo(end, 0); spectrum.lineTo(end, spectrumHeight); ctx.stroke(); spectrum.stroke(); } // 画区间 如果begin>end则区间不起作用,不绘制 if (begin < end) { begin = Math.max(begin + 1, 0); end = Math.min(end - 1, canvas.width); ctx.fillStyle = spectrum.fillStyle = '#80808044'; ctx.fillRect(begin, 0, end - begin, canvas.height); spectrum.fillRect(begin, 0, end - begin, spectrumHeight); } //== 画当前时间指针 ==// spectrum.strokeStyle = 'white'; begin = parent.time / parent.dt * parent._width - parent.scrollX; if (begin >= 0 && begin < canvas.width) { spectrum.beginPath(); spectrum.moveTo(begin, 0); spectrum.lineTo(begin, spectrumHeight); spectrum.stroke(); } }; this.updateInterval = () => { // 根据parent.width改变 在width的setter中调用 const fontWidth = parent.timeBar.ctx.measureText('00:00:000').width * 1.2; // 如果间距小于fontWidth则细分 this.interval = Math.max(1, Math.ceil(fontWidth / parent._width)); }; this.contextMenu = new ContextMenu([ { name: "设置重复区间开始位置", callback: (e_father, e_self) => { this.setRepeat((e_father.offsetX + parent.scrollX) * parent.TperP, null); } }, { name: "设置重复区间结束位置", callback: (e_father, e_self) => { this.setRepeat(null, (e_father.offsetX + parent.scrollX) * parent.TperP); } }, { name: '取消重复区间', onshow: () => this.repeatStart >= 0 || this.repeatEnd >= 0, callback: () => { this.setRepeat(-1, -1); } }, { name: "从此处播放", callback: (e_father, e_self) => { parent.AudioPlayer.stop(); parent.AudioPlayer.start((e_father.offsetX + parent.scrollX) * parent.TperP); } } ]); } ================================================ FILE: dataProcess/AI/AIEntrance.js ================================================ var AI = { combineChannels: (audioChannel) => { const wav = new Float32Array(audioChannel.getChannelData(0)); // 求和。不求平均是因为模型内部有归一化 if (audioChannel.numberOfChannels !== 1) { const len = wav.length; for (let i = 1; i < audioChannel.numberOfChannels; i++) { const cData = audioChannel.getChannelData(i); for (let j = 0; j < len; j++) wav[j] += cData[j]; } } return wav; }, basicamt: (audioChannel) => { const timeDomain = AI.combineChannels(audioChannel); return new Promise((resolve, reject) => { const basicamtWorker = new Worker("./dataProcess/AI/basicamt_worker.js"); basicamtWorker.onmessage = ({data}) => { if (data.type === 'error') { console.error(data.message); reject("疑似因为音频过长导致内存不足!"); basicamtWorker.terminate(); } resolve(data); // 返回的是音符事件 basicamtWorker.terminate(); }; basicamtWorker.onerror = (e) => { console.error(e.message); reject(e); basicamtWorker.terminate(); }; basicamtWorker.postMessage(timeDomain, [timeDomain.buffer]); }); }, septimbre: (audioChannel, k) => { const timeDomain = AI.combineChannels(audioChannel); return new Promise((resolve, reject) => { const septimbreWorker = new Worker("./dataProcess/AI/septimbre_worker.js"); septimbreWorker.onmessage = ({data}) => { if (data.type === 'error') { console.error(data.message); reject("疑似因为音频过长导致内存不足!"); septimbreWorker.terminate(); } resolve(data); septimbreWorker.terminate(); }; septimbreWorker.onerror = (e) => { console.error(e.message); reject(e); septimbreWorker.terminate(); }; septimbreWorker.postMessage(k); septimbreWorker.postMessage(timeDomain, [timeDomain.buffer]); }); } }; ================================================ FILE: dataProcess/AI/SpectralClustering.js ================================================ /** * 谱聚类算法 * @param {Array} feats * @param {number} numClusters */ function SpectralClustering(feats, numClusters, affinityFunc) { // 1. 计算修改后的归一化拉普拉斯矩阵 Lsym = I + D^(-1/2) * W * D^(-1/2) const L = TriangleMatrix.Lsym(feats, affinityFunc); // 2. 使用正交迭代法计算前k个特征向量 const U = TriangleMatrix.orthogonalIteration(L, numClusters); // console.log(U); // 3. 转置并归一化 const { flatMatrix, n, k } = transposeAndNormalize(U); // 4. 基于 Pivoted QR 选择聚类中心 return clusterQR(flatMatrix, n, k); } /** * 转置并归一化 (Transpose & Normalize) * 优化点: * 1. 预计算范数:利用原始数据的内存布局(顺序读取)计算模长;乘法代替除法:预先计算 1/norm * 2. 分块写入 (Tiling):将转置过程分块,确保写入 `flat` 数组时命中缓存 * 3. 减少重复计算:提前解构引用,避免在循环内多次查找 `eigenVectors[r]` * 4. 手动维护索引,消除循环内的乘法运算 * @param {Array} eigenVectors 大小为 k 的数组,每个元素长 n * @param {number} BLOCK_SIZE L1 缓存分块大小 * @returns {{flatMatrix: Float32Array, n: number, k: number}} */ function transposeAndNormalize(eigenVectors, BLOCK_SIZE = 1024) { const k = eigenVectors.length; const n = eigenVectors[0].length; const flat = new Float32Array(n * k); // normSq[i] 存储第 i 个数据点(即第 i 行)的模长平方 const normSq = new Float32Array(n); // 1. 预计算模长 (保持不变,因为这是最高效的) for (let r = 0; r < k; r++) { const vec = eigenVectors[r]; for (let i = 0; i < n; i++) { normSq[i] += vec[i] * vec[i]; } } // 归一化系数 for (let i = 0; i < n; i++) normSq[i] = 1.0 / Math.sqrt(normSq[i] + 1e-10); // 2. 分块转置 // 由于 k 很小,一行的数据量很小 (20 bytes)。 // 我们可以适当增大 BLOCK_SIZE,比如 1024 或 2048 // 提前解构引用,避免在循环里查找 eigenVectors[r] const vecs = Array.from({ length: k }, (_, i) => eigenVectors[i]); for (let iBase = 0; iBase < n; iBase += BLOCK_SIZE) { // 确定当前块的边界 const iLimit = (iBase + BLOCK_SIZE < n) ? (iBase + BLOCK_SIZE) : n; for (let r = 0; r < k; r++) { const vec = vecs[r]; // 手动维护索引,消除循环内的 (i * k) 乘法 // 初始索引:当前块起始行(iBase) * k + 当前列(r) let flatIndex = iBase * k + r; for (let i = iBase; i < iLimit; i++) { // 直接使用指针 flat[flatIndex] = vec[i] * normSq[i]; // 步进为 k,因为 flat 是行优先存储, // 同一列的下一个元素在 flat 中相隔 k 个位置 flatIndex += k; } } } return { flatMatrix: flat, n, k }; } /** * 完整的 Cluster QR 聚类 * 包含:中心点选择 + 标签分配 * * @param {Float32Array} flatMatrix (n * k) 归一化后的特征矩阵 (只读) * @param {number} n 点的数量 * @param {number} k 聚类数量 * @returns {Int32Array} 长度为 n 的数组,labels[i] 表示第 i 个点属于第几类 (0 到 k-1) */ function clusterQR(flatMatrix, n, k) { // --- 阶段 1: 准备工作 --- // 1. 必须复制一份数据用于 QR 分解的残差计算 // 因为 MGS 算法会破坏性地修改数据,而我们最后分配时需要原始数据 // 这里的内存开销是必要的 (n * k * 4 bytes) const residualsMatrix = flatMatrix.slice(); const centroidIndices = new Int32Array(k); const residualNorms = new Float32Array(n); // 初始化残差模长 (由于输入已归一化,初始全为 1.0) // 但为了保险,还是算一下,或者直接 fill(1.0) 如果上一步很自信 residualNorms.fill(1.0); const currentPivot = new Float32Array(k); // --- 阶段 2: 选择中心点 (Pivot Selection) --- for (let step = 0; step < k; step++) { // 2.1 寻找残差最大的点 let maxNorm = -1.0; let pivotIdx = -1; for (let i = 0; i < n; i++) { if (residualNorms[i] > maxNorm) { maxNorm = residualNorms[i]; pivotIdx = i; } } // 记录中心点索引 centroidIndices[step] = pivotIdx; if (maxNorm < 1e-6) break; // 剩余点都几乎为0了 // 2.2 提取 pivot 向量 (从残差矩阵中提取) const pivotOffset = pivotIdx * k; const pivotScale = 1.0 / Math.sqrt(maxNorm); for (let j = 0; j < k; j++) { currentPivot[j] = residualsMatrix[pivotOffset + j] * pivotScale; } // 2.3 正交化 (更新残差矩阵) for (let i = 0; i < n; i++) { if (residualNorms[i] < 0) continue; // 已选过的跳过 if (i === pivotIdx) { residualNorms[i] = -1.0; continue; } const offset = i * k; // dot = let dot = 0.0; for (let j = 0; j < k; j++) { dot += residualsMatrix[offset + j] * currentPivot[j]; } // residual_i = residual_i - dot * pivot let newNorm = 0.0; for (let j = 0; j < k; j++) { const val = residualsMatrix[offset + j] - dot * currentPivot[j]; residualsMatrix[offset + j] = val; newNorm += val * val; } residualNorms[i] = newNorm; } } // --- 阶段 3: 分配标签 (Label Assignment) --- // 既然数据已经归一化,欧氏距离最近等价于余弦相似度最大 (Dot Product Largest) const labels = new Int32Array(n); // 为了极致性能,先将 k 个中心点的原始向量提取到连续内存中 // 这样在遍历 n 个点时,中心点数据能更好地待在 Cache 里 const centerVectors = new Float32Array(k * k); for (let c = 0; c < k; c++) { const centerIdx = centroidIndices[c]; const srcOffset = centerIdx * k; const destOffset = c * k; for(let j=0; j maxSim) { maxSim = dot; bestCluster = c; } } labels[i] = bestCluster; } return labels; } class TriangleMatrix { constructor(size) { this.size = size; this.data = new Float32Array((size * (size + 1)) / 2); } // 发现效果比exp(cos-1)好 static cosineAffinityExp(featureA, featureB) { let dot = 0; for (let i = 0; i < featureA.length; i++) { dot += featureA[i] * featureB[i]; } return Math.exp(dot); } /** * 直接计算归一化拉普拉斯矩阵 * 但是正交迭代法求的是绝对值最大特征值对应的特征向量,而需要的是最小特征值对应的特征向量 * 因此将本来的"I-"换成了"I+",此时特征向量不变,特征值变为原来的2-λ * @param {Array} features * @param {Function(Float32Array, Float32Array): number} func W(i, j) = func(features[i], features[j]) * @returns {TriangleMatrix} D^(-1/2) * W * D^(-1/2) + I */ static Lsym(features, func = TriangleMatrix.cosineAffinityExp) { const size = features.length; const affine = new TriangleMatrix(size); const rowSums = new Float32Array(size); const data = affine.data; // 不算自环,直接跳过第一个 for (let j = 1, idx = 1; j < size; j++, idx++) { // col const colFeature = features[j]; for (let i = 0; i < j; i++, idx++) { // row const affi = func(colFeature, features[i]); data[idx] = affi; rowSums[i] += affi; rowSums[j] += affi; } } // 此时对角线元素均为0 // 归一化 for (let j = 0, idx = 0; j < size; j++, idx++) { for (let i = 0; i < j; i++, idx++) { // 本应是i <= j,但是对角线元素单独处理,所以将最后一个idx++放在外层 const div = Math.sqrt(rowSums[i] * rowSums[j]); if (div > 1e-10) data[idx] = data[idx] / div; else data[idx] = 0; } // 对角线元素设为1 data[idx] = 1; } return affine; } _index(i, j) { // 内联优化建议:在热路径中尽量手动计算,减少函数调用开销 if (i > j) return (i * (i + 1)) / 2 + j; return (j * (j + 1)) / 2 + i; } /** * 优化的矩阵乘法 Z = A * Q * @param {Array} Q_in 输入向量组 (k个) * @param {Array} Z_out 输出向量组 (k个,预分配好) */ mult_mat_optimized(Q_in, Z_out) { const size = this.size; const k = Q_in.length; const data = this.data; // 清空输出 buffer for (let r = 0; r < k; r++) Z_out[r].fill(0); for (let j = 0, idx = 0; j < size; j++) { for (let i = 0; i <= j; i++, idx++) { const val = data[idx]; for (let r = 0; r < k; r++) { const vecIn = Q_in[r]; const vecOut = Z_out[r]; vecOut[i] += val * vecIn[j]; if (i !== j) vecOut[j] += val * vecIn[i]; } } } } /** * 正交迭代法 求前k个绝对值最大的特征值对应的特征向量 * @param {TriangleMatrix} A 建议是 I + D^{-0.5}WD^{-0.5} * @param {number} numVectors 需要的特征向量数量 * @param {number} numIterations 迭代次数 * @return {Array} 特征向量矩阵 size * numVectors */ static orthogonalIteration(A, numVectors, numIterations = 30) { const size = A.size; // 双缓冲 let Q = Array.from({ length: numVectors }, () => new Float32Array(size)); let Z = Array.from({ length: numVectors }, () => new Float32Array(size)); // 初始化 Q 为随机并正交化 for (let r = 0; r < numVectors; r++) { for (let i = 0; i < size; i++) Q[r][i] = Math.random(); } SchmidtInPlace(Q); // 原地正交化 // 迭代 for (let iter = 0; iter < numIterations; iter++) { // Z = A * Q (写入 Z buffer) A.mult_mat_optimized(Q, Z); // Q = Schmidt(Z) (原地正交化 Z,结果仍在 Z buffer 中) SchmidtInPlace(Z); // 交换 buffer:Z 变成了下一次的 Q,原来的 Q 变成下一次的废弃 buffer (Z) const temp = Q; Q = Z; Z = temp; } return Q; } } /** * 施密特正交化 (原地修改版 / In-Place MGS) * 没有任何内存分配,速度极快 * @param {Array} V 向量组 */ function SchmidtInPlace(V) { const k = V.length; const n = V[0].length; for (let i = 0; i < k; i++) { const qi = V[i]; // 归一化当前向量 let dot = 0.0; for (let x = 0; x < n; x++) dot += qi[x] * qi[x]; const norm = Math.sqrt(dot); const scale = norm < 1e-10 ? 0 : 1.0 / norm; for (let x = 0; x < n; x++) qi[x] *= scale; // 正交化后续向量 (MGS) for (let j = i + 1; j < k; j++) { const vj = V[j]; // 计算投影 proj = let proj = 0.0; for (let x = 0; x < n; x++) proj += vj[x] * qi[x]; // 减去投影 vj = vj - proj * qi for (let x = 0; x < n; x++) vj[x] -= proj * qi[x]; } } } ================================================ FILE: dataProcess/AI/basicamt_worker.js ================================================ // const ort_folder = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/'; // self.importScripts(ort_folder + 'ort.wasm.min.js'); // ort.env.wasm.wasmPaths = ort_folder; self.importScripts('./postprocess.js'); self.importScripts('./dist/bundle.min.js') ort.env.wasm.wasmPaths = './dist/' const model = ort.InferenceSession.create( './basicamt_44100.onnx', { executionProviders: ['wasm'] } ); self.onmessage = function ({data}) { const tensorInput = new ort.Tensor('float32', data, [1, 1, data.length]); model.then((m) => { return m.run({ audio: tensorInput }); }).then((results) => { const note_events = createNotes( results.onset, results.frame, 0.22, 0.38 ); self.postMessage(note_events); }).catch((e) => { // promise中的报错不会触发worker.onerror回调,即使这里throw了。所以只能用onmessage self.postMessage({ type: 'error', message: e.message }); }); }; ================================================ FILE: dataProcess/AI/dist/ort-wasm-simd.wasm ================================================ [File too large to display: 10.1 MB] ================================================ FILE: dataProcess/AI/postprocess.js ================================================ function createNotes( onsetTensor, frameTensor, frame_thresh = 0.22, onset_thresh = 0.38, min_note_len = 6, energy_tol = 10, midi_offset = 24 ) { // 模型中已经对onset和frame进行归一化了 const raw_frameData = frameTensor.cpuData; const frameDim = frameTensor.dims; // [1, 84, frames] const raw_onsetData = onsetTensor.cpuData; const onsetDim = onsetTensor.dims; // [1, 84, frames] // 两个dim应该一样 if (frameDim[1] !== onsetDim[1] || frameDim[2] !== onsetDim[2]) { throw new Error("frameDim[1] !== onsetDim[1] || frameDim[2] !== onsetDim[2]"); } const frameNum = frameDim[2]; const noteNum = frameDim[1]; const frameData = Array(noteNum); const onsetData = Array(noteNum); for (let i = 0; i < noteNum; i++) { // 和raw共享内存 frameData[i] = new Float32Array(raw_frameData.buffer, i * frameNum * 4, frameNum); onsetData[i] = new Float32Array(raw_onsetData.buffer, i * frameNum * 4, frameNum); } get_infered_onsets(onsetData, frameData, 3); const peaks = findPeak(onsetData, onset_thresh); peaks.sort((a, b) => b[0] - a[0]); // 按照时间反过来排序 const remaining_energy = Array(noteNum); // 复制一份frameData,用于修改数据 for (let i = 0; i < noteNum; i++) remaining_energy[i] = new Float32Array(frameData[i]); const note_events = []; for (const [note_start_idx, freq_idx] of peaks) { // 如果剩下的距离不够放一个最短的音符,就跳过 if (note_start_idx >= frameNum - min_note_len) continue; let note_end_idx = note_start_idx + 1; let k = 0; // 连续k个小于frame_thresh的帧 const freqArray = remaining_energy[freq_idx]; // 向后搜索,连续energy_tol帧小于frame_thresh(或者到达最后一帧),就认为这个音符结束。目的是将分散的frames合并 while (note_end_idx < frameNum && k < energy_tol) { if (freqArray[note_end_idx] < frame_thresh) k++; else k = 0; note_end_idx++; } note_end_idx -= k; // 回到音符结尾 if (note_end_idx - note_start_idx < min_note_len) continue; // 跳过短音符 freqArray.fill(0, note_start_idx, note_end_idx); // 将这个音符的frame清零 // 认为半音不会同时出现,因为不能构成和弦 if (freq_idx < noteNum - 1) remaining_energy[freq_idx + 1].fill(0, note_start_idx, note_end_idx); if (freq_idx > 0) remaining_energy[freq_idx - 1].fill(0, note_start_idx, note_end_idx); // 对frameData在start和end中间的求平均 let sum = 0; for (let i = note_start_idx; i < note_end_idx; i++) sum += frameData[freq_idx][i]; note_events.push({ onset: note_start_idx, offset: note_end_idx, note: freq_idx + midi_offset, velocity: sum / (note_end_idx - note_start_idx) }); } // 不依赖onset,根据frames中的极大值找额外的音符 const maxes = []; for (let n = 0; n < noteNum; n++) { const thisNote = frameData[n]; for (let t = 1; t < frameNum; t++) { if (thisNote[t] > frame_thresh) maxes.push([thisNote[t], n, t]); } } maxes.sort((a, b) => b[0] - a[0]); // 按照能量从大到小排序 for (const [_, n, t] of maxes) { // 可能被前面的循环置零了 if (remaining_energy[n][t] < frame_thresh) continue; // 后向搜索 let note_end_idx = t + 1; let k = 0; const freqArray = remaining_energy[n]; while (note_end_idx < frameNum && k < energy_tol) { if (freqArray[note_end_idx] < frame_thresh) k++; else k = 0; note_end_idx++; } note_end_idx -= k; // 前向搜索 let note_start_idx = t - 1; k = 0; while (note_start_idx > 0 && k < energy_tol) { if (freqArray[note_start_idx] < frame_thresh) k++; else k = 0; note_start_idx--; } note_start_idx += (k + 1); // 之前多减了1,而fill是左闭右开 // 不管长度符不符合,都置零 freqArray.fill(0, note_start_idx, note_end_idx); if (n < noteNum - 1) remaining_energy[n + 1].fill(0, note_start_idx, note_end_idx); if (n > 0) remaining_energy[n - 1].fill(0, note_start_idx, note_end_idx); if (note_end_idx - note_start_idx < min_note_len) continue; let sum = 0; for (let i = note_start_idx; i < note_end_idx; i++) sum += frameData[n][i]; note_events.push({ onset: note_start_idx, offset: note_end_idx, note: n + midi_offset, velocity: sum / (note_end_idx - note_start_idx) }); } return note_events; } /** * 从frame中推断新的onset 会修改传入的的onsets * @param {Array} onsets * @param {Array} frames * @param {number} n_diff */ function get_infered_onsets(onsets, frames, n_diff = 2) { const frameNum = frames[0].length; const noteNum = frames.length; const inffered_onsets = Array(noteNum); let infered_max = -1e10; // 用于归一化 for (let n = 0; n < noteNum; n++) { const notetime = new Float32Array(frameNum); const thisFrame = frames[n]; for (let t = n_diff; t < frameNum; t++) { let min_diff = 1e10; // 对每个时间点求最小的差值 for (let k = 1; k <= n_diff; k++) { let diff = thisFrame[t] - thisFrame[t - k]; if (diff < min_diff) min_diff = diff; } if (min_diff > infered_max) infered_max = min_diff; notetime[t] = min_diff; } inffered_onsets[n] = notetime } // 归一化 由于onset在模型内部已经归一化了,所以onset的最大值就是1 for (let n = 0; n < noteNum; n++) { for (let t = 0; t < frameNum; t++) { let temp = inffered_onsets[n][t] / infered_max; if (temp > onsets[n][t]) onsets[n][t] = temp; } } } function findPeak(x2d, threshold = 0) { const H = x2d.length; const W = x2d[0].length - 1; let peak = []; for (let h = 0; h < H; h++) { const row = x2d[h]; let last_is_up = true; // 由于模型用的是sigmoid,所以全部大于零,所以第一个之前的导数一定大于零 for (let w = 0; w < W; w++) { if (row[w] < threshold) continue; if (last_is_up) { if (row[w] > row[w + 1]) { // 下一个小于当前,说明当前是峰值 peak.push([w, h]); last_is_up = false; } else if (row[w] == row[w + 1]) { let _w = w + 1; // 下一个等于当前,要看后面第一个非零导数是否小于零 while (_w < W) { if (row[_w] == row[_w + 1]) _w++; else if (row[_w] < row[_w + 1]) break; else { // 后面变小了,说明当前是峰值 last_is_up = false; peak.push([w, h]); w = _w; break; } } } } else { last_is_up = (row[w] < row[w + 1]); } } } return peak; } ================================================ FILE: dataProcess/AI/septimbre_44100.onnx ================================================  pytorch 2.9.0+cu128:*  audioval_0 node_Shape_0"Shape* end* startJ namespacew_empty_nn_module_stack_from_metadata_hook: _empty_nn_module_stack_from_metadata_hook/sym_size_int_85: aten.sym_size.intJd pkg.torch.onnx.class_hierarchyB['_empty_nn_module_stack_from_metadata_hook', 'aten.sym_size.int']J pkg.torch.onnx.fx_nodeq%sym_size_int_85 : [num_users=1] = call_function[target=torch.ops.aten.sym_size.int](args = (%x, 2), kwargs = {})J^ pkg.torch.onnx.name_scopes@['_empty_nn_module_stack_from_metadata_hook', 'sym_size_int_85']Js pkg.torch.onnx.stack_traceUFile "torch/fx/passes/runtime_assert.py", line 24, in insert_deferred_runtime_asserts  val_0sym_size_int_85node_sym_size_int_85"SqueezeJ namespacew_empty_nn_module_stack_from_metadata_hook: _empty_nn_module_stack_from_metadata_hook/sym_size_int_85: aten.sym_size.intJd pkg.torch.onnx.class_hierarchyB['_empty_nn_module_stack_from_metadata_hook', 'aten.sym_size.int']J pkg.torch.onnx.fx_nodeq%sym_size_int_85 : [num_users=1] = call_function[target=torch.ops.aten.sym_size.int](args = (%x, 2), kwargs = {})J^ pkg.torch.onnx.name_scopes@['_empty_nn_module_stack_from_metadata_hook', 'sym_size_int_85']Js pkg.torch.onnx.stack_traceUFile "torch/fx/passes/runtime_assert.py", line 24, in insert_deferred_runtime_asserts  audio septimbre_amt.cqt.filtfilt.firconv1dnode_Conv_1554"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d val_9 val_10 val_9 val_9flip node_flip"SliceJu namespaceh: septimbre.SepTimbreAMT_44100/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip: aten.flip.defaultJp pkg.torch.onnx.class_hierarchyN['septimbre.SepTimbreAMT_44100', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noden%flip : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d, [-1]), kwargs = {})JH pkg.torch.onnx.name_scopes*['', 'septimbre_amt.cqt.filtfilt', 'flip']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 190, in forward x = self.septimbre_amt.cqt.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip septimbre_amt.cqt.filtfilt.firconv1d_1node_Conv_1555"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_1 val_9 val_10 val_9 val_9flip_1 node_flip_1"SliceJw namespacej: septimbre.SepTimbreAMT_44100/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_1: aten.flip.defaultJp pkg.torch.onnx.class_hierarchyN['septimbre.SepTimbreAMT_44100', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noder%flip_1 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_1, [-1]), kwargs = {})JJ pkg.torch.onnx.name_scopes,['', 'septimbre_amt.cqt.filtfilt', 'flip_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 190, in forward x = self.septimbre_amt.cqt.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_1 val_25 val_29 val_33 val_33slice_1 node_slice_1"SliceJF namespace9: septimbre.SepTimbreAMT_44100/slice_1: aten.slice.TensorJW pkg.torch.onnx.class_hierarchy5['septimbre.SepTimbreAMT_44100', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_1 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat, 2, 0, 9223372036854775807, 2), kwargs = {})J- pkg.torch.onnx.name_scopes['', 'slice_1']J pkg.torch.onnx.stack_trace{File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 190, in forward x = self.septimbre_amt.cqt.down2sample(x)  slice_1 septimbre_amt.cqt.cqt_kernelsconv1d_2node_Conv_1556"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_2 val_47view node_view"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_nodez%view : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_2, [1, 2, 36, -1]), kwargs = {})JP pkg.torch.onnx.name_scopes2['', 'septimbre_amt', 'septimbre_amt.cqt', 'view']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 321, in forward CQT_results = [firstOctave.view(firstOctave.size(0), 2, self.bins_per_octave, -1)]  slice_1 septimbre_amt.cqt.filtfilt.firconv1d_3node_Conv_1557"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_3 val_9 val_10 val_9 val_9flip_2 node_flip_2"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_2: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noder%flip_2 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_3, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_2 septimbre_amt.cqt.filtfilt.firconv1d_4node_Conv_1558"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_4 val_9 val_10 val_9 val_9flip_3 node_flip_3"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_3: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noder%flip_3 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_4, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_3 val_25 val_29 val_33 val_33slice_2 node_slice_2"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_2: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_2 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_1, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_2 septimbre_amt.cqt.cqt_kernelsconv1d_5node_Conv_1559"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_5 val_47view_1 node_view_1"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_1: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node|%view_1 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_5, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  slice_2 septimbre_amt.cqt.filtfilt.firconv1d_6node_Conv_1560"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_6 val_9 val_10 val_9 val_9flip_4 node_flip_4"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_4: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noder%flip_4 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_6, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_4 septimbre_amt.cqt.filtfilt.firconv1d_7node_Conv_1561"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_7 val_9 val_10 val_9 val_9flip_5 node_flip_5"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_5: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noder%flip_5 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_7, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_5']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_5 val_25 val_29 val_33 val_33slice_3 node_slice_3"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_3: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_3 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_2, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_3 septimbre_amt.cqt.cqt_kernelsconv1d_8node_Conv_1562"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@@  conv1d_8 val_47view_2 node_view_2"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_2: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node|%view_2 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_8, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  slice_3 septimbre_amt.cqt.filtfilt.firconv1d_9node_Conv_1563"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_9 val_9 val_10 val_9 val_9flip_6 node_flip_6"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_6: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_noder%flip_6 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_9, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_6 septimbre_amt.cqt.filtfilt.fir conv1d_10node_Conv_1564"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_10 val_9 val_10 val_9 val_9flip_7 node_flip_7"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_7: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodes%flip_7 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_10, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_7 val_25 val_29 val_33 val_33slice_4 node_slice_4"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_4: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_4 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_3, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_4 septimbre_amt.cqt.cqt_kernels conv1d_11node_Conv_1565"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@   conv1d_11 val_47view_3 node_view_3"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_3: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node}%view_3 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_11, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  slice_4 septimbre_amt.cqt.filtfilt.fir conv1d_12node_Conv_1566"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_12 val_9 val_10 val_9 val_9flip_8 node_flip_8"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_8: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodes%flip_8 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_12, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_8']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_8 septimbre_amt.cqt.filtfilt.fir conv1d_13node_Conv_1567"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_13 val_9 val_10 val_9 val_9flip_9 node_flip_9"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_9: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodes%flip_9 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_13, [-1]), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_9 val_25 val_29 val_33 val_33slice_5 node_slice_5"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_5: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_5 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_4, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_5']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_5 septimbre_amt.cqt.cqt_kernels conv1d_14node_Conv_1568"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_14 val_47view_4 node_view_4"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_4: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node}%view_4 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_14, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  slice_5 septimbre_amt.cqt.filtfilt.fir conv1d_15node_Conv_1569"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_15 val_9 val_10 val_9 val_9flip_10 node_flip_10"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_10: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodet%flip_10 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_15, [-1]), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_10 septimbre_amt.cqt.filtfilt.fir conv1d_16node_Conv_1570"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_16 val_9 val_10 val_9 val_9flip_11 node_flip_11"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_11: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodet%flip_11 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_16, [-1]), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_11']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_11 val_25 val_29 val_33 val_33slice_6 node_slice_6"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_6: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_6 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_5, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_6 septimbre_amt.cqt.cqt_kernels conv1d_17node_Conv_1571"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_17 val_47view_5 node_view_5"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_5: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node}%view_5 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_17, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_5']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  slice_6 septimbre_amt.cqt.filtfilt.fir conv1d_18node_Conv_1572"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_18 val_9 val_10 val_9 val_9flip_12 node_flip_12"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_12: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodet%flip_12 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_18, [-1]), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_12 septimbre_amt.cqt.filtfilt.fir conv1d_19node_Conv_1573"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_19 val_9 val_10 val_9 val_9flip_13 node_flip_13"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_13: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodet%flip_13 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_19, [-1]), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_13 val_25 val_29 val_33 val_33slice_7 node_slice_7"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_7: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_7 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_6, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_7 septimbre_amt.cqt.cqt_kernels conv1d_20node_Conv_1574"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_20 val_47view_6 node_view_6"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_6: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node}%view_6 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_20, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  slice_7 septimbre_amt.cqt.filtfilt.fir conv1d_21node_Conv_1575"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_21 val_9 val_10 val_9 val_9flip_14 node_flip_14"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_14: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodet%flip_14 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_21, [-1]), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_14']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_14 septimbre_amt.cqt.filtfilt.fir conv1d_22node_Conv_1576"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@ conv1d_22 val_9 val_10 val_9 val_9flip_15 node_flip_15"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/septimbre_amt.cqt.filtfilt: model.CQT.FIRfiltfilt/flip_15: aten.flip.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'model.CQT.FIRfiltfilt', 'aten.flip.default']J pkg.torch.onnx.fx_nodet%flip_15 : [num_users=1] = call_function[target=torch.ops.aten.flip.default](args = (%conv1d_22, [-1]), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.cqt', 'septimbre_amt.cqt.filtfilt', 'flip_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 210, in forward channels = [self.filtfilt(x[:, i:i+1]) for i in range(x.size(1))]  flip_15 val_25 val_29 val_33 val_33slice_8 node_slice_8"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/slice_8: aten.slice.TensorJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_8 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%cat_7, 2, 0, 9223372036854775807, 2), kwargs = {})JS pkg.torch.onnx.name_scopes5['', 'septimbre_amt', 'septimbre_amt.cqt', 'slice_8']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 324, in forward x = self.down2sample(x)  slice_8 septimbre_amt.cqt.cqt_kernels conv1d_23node_Conv_1577"Conv* auto_pad"NOTSET* dilations@* group* pads@@* strides@  conv1d_23 val_47view_7 node_view_7"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/view_7: aten.view.defaultJ pkg.torch.onnx.class_hierarchyi['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.view.default']J pkg.torch.onnx.fx_node}%view_7 : [num_users=1] = call_function[target=torch.ops.aten.view.default](args = (%conv1d_23, [1, 2, 36, -1]), kwargs = {})JR pkg.torch.onnx.name_scopes4['', 'septimbre_amt', 'septimbre_amt.cqt', 'view_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 326, in forward CQT_results.append(CQT_result.view(CQT_result.size(0), 2, self.bins_per_octave, -1))  view_7 view_6 view_5 view_4 view_3 view_2 view_1 viewcat_8 node_cat_8"Concat* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.cqt: model.CQT.CQTsmall_fir/cat_8: aten.cat.defaultJ pkg.torch.onnx.class_hierarchyh['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'model.CQT.CQTsmall_fir', 'aten.cat.default']J pkg.torch.onnx.fx_node%cat_8 : [num_users=1] = call_function[target=torch.ops.aten.cat.default](args = ([%view_7, %view_6, %view_5, %view_4, %view_3, %view_2, %view_1, %view], 2), kwargs = {})JQ pkg.torch.onnx.name_scopes3['', 'septimbre_amt', 'septimbre_amt.cqt', 'cat_8']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 137, in forward x = self.cqt(x) File "/home/liruigang/timbreAMT/septimbre/../model/CQT.py", line 328, in forward return torch.cat(CQT_results, dim=2) cat_8 val_349pow_1 node_pow_1"PowJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/pow_1: aten.pow.Tensor_ScalarJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.pow.Tensor_Scalar']J pkg.torch.onnx.fx_nodep%pow_1 : [num_users=1] = call_function[target=torch.ops.aten.pow.Tensor_Scalar](args = (%cat_8, 2), kwargs = {})Jl pkg.torch.onnx.name_scopesN['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'pow_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 236, in forward eng = torch.sum(x.pow(2), dim=1, keepdim=True) pow_1 val_353sum_1 node_sum_1" ReduceSum* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/sum_1: aten.sum.dim_IntListJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.sum.dim_IntList']J pkg.torch.onnx.fx_nodev%sum_1 : [num_users=2] = call_function[target=torch.ops.aten.sum.dim_IntList](args = (%pow_1, [1], True), kwargs = {})Jl pkg.torch.onnx.name_scopesN['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'sum_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 236, in forward eng = torch.sum(x.pow(2), dim=1, keepdim=True) sum_1 val_33sum_2 node_sum_2" ReduceSum* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/sum_2: aten.sum.dim_IntListJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.sum.dim_IntList']J pkg.torch.onnx.fx_nodev%sum_2 : [num_users=1] = call_function[target=torch.ops.aten.sum.dim_IntList](args = (%sum_1, [2], True), kwargs = {})Jl pkg.torch.onnx.name_scopesN['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'sum_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 238, in forward eng_per_frame = torch.sum(eng, dim=2, keepdim=True) sum_2 val_632val_359node_ReduceMean_359" ReduceMean* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) sum_2 val_359val_360 node_Sub_360"SubJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_360 val_360val_361 node_Mul_361"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_361 val_632val_362node_ReduceMean_362" ReduceMean* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) sum_2val_363node_Shape_363"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_363 val_632val_364node_Gather_364"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_364val_365node_ReduceProd_365" ReduceProd* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) 3 val_365val_366node_Cast_1438"Cast* to val_362 val_366val_367 node_Mul_367"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_366 val_369val_370 node_Sub_370"SubJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_367 val_370varnode_var"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/var: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.var.default']J pkg.torch.onnx.fx_nodep%var : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%sum_2, [3], 1.0), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'var']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) var val_379val_380node_Reshape_380"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/broadcast_in_dim: prims.broadcast_in_dim.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'prims.broadcast_in_dim.default']J pkg.torch.onnx.fx_node%broadcast_in_dim : [num_users=1] = call_function[target=torch.ops.prims.broadcast_in_dim.default](args = (%var, [1, 1, 1, 1], [0, 1, 2]), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'broadcast_in_dim']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) val_380sqrt node_sqrt"SqrtJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/sqrt: aten.sqrt.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.sqrt.default']J pkg.torch.onnx.fx_nodes%sqrt : [num_users=1] = call_function[target=torch.ops.aten.sqrt.default](args = (%broadcast_in_dim,), kwargs = {})Jk pkg.torch.onnx.name_scopesM['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'sqrt']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 241, in forward std = torch.std(eng_per_frame, dim=3, keepdim=True, unbiased=True) sum_1 val_382add_607 node_add_607"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/add_607: aten.add.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.add.Tensor']J pkg.torch.onnx.fx_noder%add_607 : [num_users=1] = call_function[target=torch.ops.aten.add.Tensor](args = (%sum_1, 1.01e-08), kwargs = {})Jn pkg.torch.onnx.name_scopesP['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'add_607']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 249, in forward return torch.log(eng + 1.01e-8) - torch.log(std)  add_607lognode_log"LogJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/log: aten.log.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.log.default']J pkg.torch.onnx.fx_nodeh%log : [num_users=1] = call_function[target=torch.ops.aten.log.default](args = (%add_607,), kwargs = {})Jj pkg.torch.onnx.name_scopesL['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'log']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 249, in forward return torch.log(eng + 1.01e-8) - torch.log(std)  sqrtlog_1 node_log_1"LogJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/log_1: aten.log.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.log.default']J pkg.torch.onnx.fx_nodeg%log_1 : [num_users=1] = call_function[target=torch.ops.aten.log.default](args = (%sqrt,), kwargs = {})Jl pkg.torch.onnx.name_scopesN['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'log_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 249, in forward return torch.log(eng + 1.01e-8) - torch.log(std) log log_1sub_94 node_sub_94"SubJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.eng: model.layers.EnergyNorm/sub_94: aten.sub.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.EnergyNorm', 'aten.sub.Tensor']J pkg.torch.onnx.fx_nodem%sub_94 : [num_users=8] = call_function[target=torch.ops.aten.sub.Tensor](args = (%log, %log_1), kwargs = {})Jm pkg.torch.onnx.name_scopesO['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.eng', 'sub_94']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 20, in forward eng = self.eng(x) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 249, in forward return torch.log(eng + 1.01e-8) - torch.log(std) val_383 sym_size_int_85add_617 node_add_617"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_617: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodeh%add_617 : [num_users=1] = call_function[target=operator.add](args = (1, %sym_size_int_85), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_617']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_617 val_30 floordiv_359node_floordiv_359"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_359: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_359 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_617, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_359']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_359add_618 node_add_618"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_618: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_618 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_359), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_618']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_618 val_30 floordiv_360node_floordiv_360"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_360: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_360 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_618, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_360']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_360add_619 node_add_619"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_619: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_619 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_360), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_619']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_619 val_30 floordiv_361node_floordiv_361"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_361: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_361 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_619, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_361']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_361add_620 node_add_620"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_620: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_620 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_361), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_620']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_620 val_30 floordiv_362node_floordiv_362"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_362: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_362 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_620, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_362']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_362add_621 node_add_621"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_621: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_621 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_362), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_621']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_621 val_30 floordiv_363node_floordiv_363"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_363: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_363 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_621, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_363']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_363add_622 node_add_622"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_622: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_622 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_363), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_622']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_622 val_30 floordiv_364node_floordiv_364"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_364: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_364 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_622, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_364']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_364add_623 node_add_623"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_623: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_623 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_364), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_623']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_623 val_30 floordiv_365node_floordiv_365"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_365: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_365 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_623, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_365']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_365add_624 node_add_624"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_624: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_624 : [num_users=1] = call_function[target=operator.add](args = (1, %floordiv_365), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_624']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_624 val_30 floordiv_366node_floordiv_366"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_366: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_366 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_624, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_366']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_384 floordiv_366add_625 node_add_625"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_625: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodef%add_625 : [num_users=1] = call_function[target=operator.add](args = (-1, %floordiv_366), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_625']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_625 val_30 floordiv_367node_floordiv_367"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/floordiv_367: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodej%floordiv_367 : [num_users=1] = call_function[target=operator.floordiv](args = (%add_625, 2), kwargs = {})Jt pkg.torch.onnx.name_scopesV['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'floordiv_367']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_383 floordiv_367add_626 node_add_626"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/add_626: J pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', '']J pkg.torch.onnx.fx_nodee%add_626 : [num_users=2] = call_function[target=operator.add](args = (1, %floordiv_367), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'add_626']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) add_626 val_9val_390node_Reshape_390"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/zeros: aten.zeros.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.zeros.default']J pkg.torch.onnx.fx_node%zeros : [num_users=3] = call_function[target=torch.ops.aten.zeros.default](args = ([1, 8, 252, %add_626],), kwargs = {dtype: torch.float32, device: cpu, pin_memory: False})Jm pkg.torch.onnx.name_scopesO['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'zeros']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_353 val_1177 val_484 val_390val_391node_Concat_391"Concat* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/zeros: aten.zeros.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.zeros.default']J pkg.torch.onnx.fx_node%zeros : [num_users=3] = call_function[target=torch.ops.aten.zeros.default](args = ([1, 8, 252, %add_626],), kwargs = {dtype: torch.float32, device: cpu, pin_memory: False})Jm pkg.torch.onnx.name_scopesO['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'zeros']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) val_385 val_391zeros node_zeros"ExpandJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/zeros: aten.zeros.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.zeros.default']J pkg.torch.onnx.fx_node%zeros : [num_users=3] = call_function[target=torch.ops.aten.zeros.default](args = ([1, 8, 252, %add_626],), kwargs = {dtype: torch.float32, device: cpu, pin_memory: False})Jm pkg.torch.onnx.name_scopesO['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'zeros']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 26, in forward shifted = torch.zeros((batch_size, channels * len(self.shifts), self.output_bins, length), device=x.device, dtype=x.dtype) sub_94 val_25 val_398 val_33 val_353slice_9 node_slice_9"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_9: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodev%slice_9 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 0, 216), kwargs = {})Jo pkg.torch.onnx.name_scopesQ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] zeros val_25 val_353 val_353 val_353slice_14 node_slice_14"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_14: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodet%slice_14 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%zeros, 1, 0, 1), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_14']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] slice_9val_476node_Transpose_476" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_15, %copy, 3, 0, 9223372036854775807), kwargs = {})Ju pkg.torch.onnx.name_scopesW['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] 0 val_476val_478node_Identity_1615"Identity slice_14val_480node_Shape_480"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_480 val_30val_481node_Gather_481"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_22 val_481 val_383val_482node_Range_482"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_482 val_483 val_484 val_25 val_353val_486node_Slice_486"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_486 val_9val_487node_Unsqueeze_487" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] E val_478val_488node_Transpose_1580" Transpose* perm@@@@ slice_14val_489node_Transpose_489" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_489 val_487 val_488val_490node_ScatterND_490" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_1: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_1 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_14, %slice_scatter, 2, 36, 252), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] zerosval_492node_Shape_492"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_492 val_383val_493node_Gather_493"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_22 val_493 val_383val_494node_Range_494"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_494 val_25 val_353 val_25 val_353val_498node_Slice_498"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_498 val_9val_499node_Unsqueeze_499" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] E val_490val_500node_Transpose_1581" Transpose* perm@@@@ zerosval_501node_Transpose_501" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_501 val_499 val_500val_502node_ScatterND_502" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] val_502slice_scatter_2node_slice_scatter_2" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_2: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_2 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%zeros, %slice_scatter_1, 1, 0, 1), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 30, in forward shifted[:, i*channels:(i+1)*channels, -shift:self.output_bins, :] = x[:, :, :self.output_bins+shift, :] sub_94 val_25 val_484 val_33 val_353slice_19 node_slice_19"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_19: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodew%slice_19 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 0, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_19val_562node_Transpose_562" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_3: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_3 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_25, %copy_1, 3, 0, 9223372036854775807), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 0 val_562val_564node_Identity_1616"Identity slice_scatter_2val_566node_Shape_566"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_566 val_383val_567node_Gather_567"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_567 val_383val_568node_Range_568"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_568 val_353 val_33 val_25 val_353val_572node_Slice_572"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_572 val_9val_573node_Unsqueeze_573" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_564val_574node_Transpose_1584" Transpose* perm@@@@ slice_scatter_2val_575node_Transpose_575" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_575 val_573 val_574val_576node_ScatterND_576" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_576slice_scatter_4node_slice_scatter_4" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_4: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_4 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_2, %slice_scatter_3, 1, 1, 2), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] sub_94 val_483 val_484 val_33 val_353slice_28 node_slice_28"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_28: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodex%slice_28 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 36, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_28']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_4 val_33 val_632 val_353 val_353slice_36 node_slice_36"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_36: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node~%slice_36 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%slice_scatter_4, 1, 2, 3), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_36']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_28val_656node_Transpose_656" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_5: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_5 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_37, %copy_2, 3, 0, 9223372036854775807), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_5']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 0 val_656val_658node_Identity_1617"Identity slice_36val_660node_Shape_660"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_660 val_30val_661node_Gather_661"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_661 val_383val_662node_Range_662"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_662 val_25 val_398 val_25 val_353val_666node_Slice_666"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_666 val_9val_667node_Unsqueeze_667" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_658val_668node_Transpose_1587" Transpose* perm@@@@ slice_36val_669node_Transpose_669" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_669 val_667 val_668val_670node_ScatterND_670" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_6: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_6 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_36, %slice_scatter_5, 2, 0, 216), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_4val_672node_Shape_672"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_672 val_383val_673node_Gather_673"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_673 val_383val_674node_Range_674"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_674 val_33 val_632 val_25 val_353val_678node_Slice_678"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_678 val_9val_679node_Unsqueeze_679" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_670val_680node_Transpose_1588" Transpose* perm@@@@ slice_scatter_4val_681node_Transpose_681" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_681 val_679 val_680val_682node_ScatterND_682" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_682slice_scatter_7node_slice_scatter_7" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_7: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_7 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_4, %slice_scatter_6, 1, 2, 3), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_7']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] sub_94 val_686 val_484 val_33 val_353slice_41 node_slice_41"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_41: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodex%slice_41 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 57, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_41']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_7 val_632 val_741 val_353 val_353slice_49 node_slice_49"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_49: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node~%slice_49 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%slice_scatter_7, 1, 3, 4), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_49']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_41val_765node_Transpose_765" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_8: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_8 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_50, %copy_3, 3, 0, 9223372036854775807), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_8']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 0 val_765val_767node_Identity_1618"Identity slice_49val_769node_Shape_769"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_769 val_30val_770node_Gather_770"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_770 val_383val_771node_Range_771"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_771 val_25 val_773 val_25 val_353val_775node_Slice_775"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_775 val_9val_776node_Unsqueeze_776" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_767val_777node_Transpose_1591" Transpose* perm@@@@ slice_49val_778node_Transpose_778" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_778 val_776 val_777val_779node_ScatterND_779" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_9: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_9 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_49, %slice_scatter_8, 2, 0, 195), kwargs = {})Jw pkg.torch.onnx.name_scopesY['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_9']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_7val_781node_Shape_781"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_781 val_383val_782node_Gather_782"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_782 val_383val_783node_Range_783"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_783 val_632 val_741 val_25 val_353val_787node_Slice_787"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_787 val_9val_788node_Unsqueeze_788" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_779val_789node_Transpose_1592" Transpose* perm@@@@ slice_scatter_7val_790node_Transpose_790" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_790 val_788 val_789val_791node_ScatterND_791" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_791slice_scatter_10node_slice_scatter_10" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_10: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_10 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_7, %slice_scatter_9, 1, 3, 4), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_10']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] sub_94 val_795 val_484 val_33 val_353slice_54 node_slice_54"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_54: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodex%slice_54 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 72, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_54']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_10 val_741 val_850 val_353 val_353slice_62 node_slice_62"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_62: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_62 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%slice_scatter_10, 1, 4, 5), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_62']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_54val_874node_Transpose_874" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_11: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_11 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_63, %copy_4, 3, 0, 9223372036854775807), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_11']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 0 val_874val_876node_Identity_1619"Identity slice_62val_878node_Shape_878"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_878 val_30val_879node_Gather_879"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_879 val_383val_880node_Range_880"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_880 val_25 val_882 val_25 val_353val_884node_Slice_884"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_884 val_9val_885node_Unsqueeze_885" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_876val_886node_Transpose_1595" Transpose* perm@@@@ slice_62val_887node_Transpose_887" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_887 val_885 val_886val_888node_ScatterND_888" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_12: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_12 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_62, %slice_scatter_11, 2, 0, 180), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_12']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_10val_890node_Shape_890"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_890 val_383val_891node_Gather_891"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_891 val_383val_892node_Range_892"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_892 val_741 val_850 val_25 val_353val_896node_Slice_896"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_896 val_9val_897node_Unsqueeze_897" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_888val_898node_Transpose_1596" Transpose* perm@@@@ slice_scatter_10val_899node_Transpose_899" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_899 val_897 val_898val_900node_ScatterND_900" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_900slice_scatter_13node_slice_scatter_13" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_13: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_13 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_10, %slice_scatter_12, 1, 4, 5), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_13']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] sub_94 val_904 val_484 val_33 val_353slice_67 node_slice_67"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_67: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodex%slice_67 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 84, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_67']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_13 val_850 val_959 val_353 val_353slice_75 node_slice_75"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_75: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_75 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%slice_scatter_13, 1, 5, 6), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_75']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_67val_983node_Transpose_983" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_14: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_14 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_76, %copy_5, 3, 0, 9223372036854775807), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_14']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 0 val_983val_985node_Identity_1620"Identity slice_75val_987node_Shape_987"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_987 val_30val_988node_Gather_988"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_988 val_383val_989node_Range_989"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_989 val_25 val_991 val_25 val_353val_993node_Slice_993"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_993 val_9val_994node_Unsqueeze_994" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] E val_985val_995node_Transpose_1599" Transpose* perm@@@@ slice_75val_996node_Transpose_996" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_996 val_994 val_995val_997node_ScatterND_997" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_15: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_15 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_75, %slice_scatter_14, 2, 0, 168), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_15']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_13val_999node_Shape_999"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_999 val_383val_1000node_Gather_1000"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_1000 val_383val_1001node_Range_1001"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1001 val_850 val_959 val_25 val_353val_1005node_Slice_1005"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1005 val_9val_1006node_Unsqueeze_1006" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] F val_997val_1007node_Transpose_1600" Transpose* perm@@@@ slice_scatter_13val_1008node_Transpose_1008" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1008 val_1006 val_1007val_1009node_ScatterND_1009" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1009slice_scatter_16node_slice_scatter_16" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_16: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_16 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_13, %slice_scatter_15, 1, 5, 6), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_16']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] sub_94 val_1013 val_484 val_33 val_353slice_80 node_slice_80"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_80: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodex%slice_80 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 93, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_80']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_16 val_959 val_1068 val_353 val_353slice_88 node_slice_88"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_88: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_88 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%slice_scatter_16, 1, 6, 7), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_88']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_80val_1092node_Transpose_1092" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_17: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_17 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_89, %copy_6, 3, 0, 9223372036854775807), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_17']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 2 val_1092val_1094node_Identity_1621"Identity slice_88val_1096node_Shape_1096"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1096 val_30val_1097node_Gather_1097"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_1097 val_383val_1098node_Range_1098"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1098 val_25 val_1100 val_25 val_353val_1102node_Slice_1102"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1102 val_9val_1103node_Unsqueeze_1103" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] G val_1094val_1104node_Transpose_1603" Transpose* perm@@@@ slice_88val_1105node_Transpose_1105" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1105 val_1103 val_1104val_1106node_ScatterND_1106" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_18: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_18 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_88, %slice_scatter_17, 2, 0, 159), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_18']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_16val_1108node_Shape_1108"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1108 val_383val_1109node_Gather_1109"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_1109 val_383val_1110node_Range_1110"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1110 val_959 val_1068 val_25 val_353val_1114node_Slice_1114"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1114 val_9val_1115node_Unsqueeze_1115" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] G val_1106val_1116node_Transpose_1604" Transpose* perm@@@@ slice_scatter_16val_1117node_Transpose_1117" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1117 val_1115 val_1116val_1118node_ScatterND_1118" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1118slice_scatter_19node_slice_scatter_19" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_19: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_19 : [num_users=3] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_16, %slice_scatter_18, 1, 6, 7), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_19']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] sub_94 val_1122 val_484 val_33 val_353slice_93 node_slice_93"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_93: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_nodey%slice_93 : [num_users=1] = call_function[target=torch.ops.aten.slice.Tensor](args = (%sub_94, 2, 101, 252), kwargs = {})Jp pkg.torch.onnx.name_scopesR['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_93']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_19 val_1068 val_1177 val_353 val_353 slice_101node_slice_101"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_101: aten.slice.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice.Tensor']J pkg.torch.onnx.fx_node%slice_101 : [num_users=2] = call_function[target=torch.ops.aten.slice.Tensor](args = (%slice_scatter_19, 1, 7, 8), kwargs = {})Jq pkg.torch.onnx.name_scopesS['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_101']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_93val_1201node_Transpose_1201" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_20: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_20 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_102, %copy_7, 3, 0, 9223372036854775807), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_20']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] 2 val_1201val_1203node_Identity_1622"Identity slice_101val_1205node_Shape_1205"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1205 val_30val_1206node_Gather_1206"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_1206 val_383val_1207node_Range_1207"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1207 val_25 val_1209 val_25 val_353val_1211node_Slice_1211"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1211 val_9val_1212node_Unsqueeze_1212" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] G val_1203val_1213node_Transpose_1607" Transpose* perm@@@@ slice_101val_1214node_Transpose_1214" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1214 val_1212 val_1213val_1215node_ScatterND_1215" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_21: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_21 : [num_users=1] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_101, %slice_scatter_20, 2, 0, 151), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_21']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] slice_scatter_19val_1217node_Shape_1217"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1217 val_383val_1218node_Gather_1218"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_22 val_1218 val_383val_1219node_Range_1219"RangeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1219 val_1068 val_1177 val_25 val_353val_1223node_Slice_1223"SliceJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1223 val_9val_1224node_Unsqueeze_1224" UnsqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] G val_1215val_1225node_Transpose_1608" Transpose* perm@@@@ slice_scatter_19val_1226node_Transpose_1226" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1226 val_1224 val_1225val_1227node_ScatterND_1227" ScatterND* reduction"noneJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :] val_1227slice_scatter_22node_slice_scatter_22" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.hcqt: septimbre.HCQTpreprocess/septimbre_amt.hcqt.HCQT: model.layers.HarmonicaStacking/slice_scatter_22: aten.slice_scatter.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.HCQTpreprocess', 'model.layers.HarmonicaStacking', 'aten.slice_scatter.default']J pkg.torch.onnx.fx_node%slice_scatter_22 : [num_users=2] = call_function[target=torch.ops.aten.slice_scatter.default](args = (%slice_scatter_19, %slice_scatter_21, 1, 7, 8), kwargs = {})Jx pkg.torch.onnx.name_scopesZ['', 'septimbre_amt', 'septimbre_amt.hcqt', 'septimbre_amt.hcqt.HCQT', 'slice_scatter_22']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 138, in forward x = self.hcqt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 22, in forward stacked = self.HCQT(eng) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 32, in forward shifted[:, i*channels:(i+1)*channels, :self.output_bins-shift, :] = x[:, :, shift:self.output_bins, :]  slice_scatter_22 septimbre_amt.note_branch.kmul_595 node_mul_595"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/mul_595: aten.mul.TensorJ pkg.torch.onnx.class_hierarchyl['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'aten.mul.Tensor']J pkg.torch.onnx.fx_node%mul_595 : [num_users=1] = call_function[target=torch.ops.aten.mul.Tensor](args = (%slice_scatter_22, %p_septimbre_amt_note_branch_k), kwargs = {})J[ pkg.torch.onnx.name_scopes=['', 'septimbre_amt', 'septimbre_amt.note_branch', 'mul_595']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 49, in forward x = x * self.k + self.b  mul_595 septimbre_amt.note_branch.badd_824 node_add_824"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/add_824: aten.add.TensorJ pkg.torch.onnx.class_hierarchyl['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'aten.add.Tensor']J pkg.torch.onnx.fx_node%add_824 : [num_users=2] = call_function[target=torch.ops.aten.add.Tensor](args = (%mul_595, %p_septimbre_amt_note_branch_b), kwargs = {})J[ pkg.torch.onnx.name_scopes=['', 'septimbre_amt', 'septimbre_amt.note_branch', 'add_824']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 49, in forward x = x * self.k + self.b  add_824 2septimbre_amt.note_branch.early_conv.0.conv.weight add_824_biasgetitemnode_Conv_1609"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@  getitem leaky_relunode_leaky_relu" LeakyRelu* alpha #<J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.note_branch.early_conv.0: model.layers.CBLR/septimbre_amt.note_branch.early_conv.0.act: torch.nn.modules.activation.LeakyReLU/leaky_relu: aten.leaky_relu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'torch.nn.modules.container.Sequential', 'model.layers.CBLR', 'torch.nn.modules.activation.LeakyReLU', 'aten.leaky_relu.default']J pkg.torch.onnx.fx_nodev%leaky_relu : [num_users=1] = call_function[target=torch.ops.aten.leaky_relu.default](args = (%getitem,), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.early_conv', 'septimbre_amt.note_branch.early_conv.0', 'septimbre_amt.note_branch.early_conv.0.act', 'leaky_relu']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 51, in forward early_conv = self.early_conv(x) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 215, in forward x = self.act(x) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 922, in forward return F.leaky_relu(input, self.negative_slope, self.inplace)  leaky_relu -septimbre_amt.note_branch.early_conv.1.weight +septimbre_amt.note_branch.early_conv.1.bias getitem_3node_Conv_1610"Conv* auto_pad"NOTSET* dilations@@* group* pads@$@@$@* strides@@  getitem_3 add_824add_856 node_add_856"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/add_856: aten.add.TensorJ pkg.torch.onnx.class_hierarchyl['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'aten.add.Tensor']J pkg.torch.onnx.fx_nodev%add_856 : [num_users=1] = call_function[target=torch.ops.aten.add.Tensor](args = (%getitem_3, %add_824), kwargs = {})J[ pkg.torch.onnx.name_scopes=['', 'septimbre_amt', 'septimbre_amt.note_branch', 'add_856']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 54, in forward res = self.res(early_conv + x) add_856relu node_relu"ReluJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.res: torch.nn.modules.activation.ReLU/relu: aten.relu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'torch.nn.modules.activation.ReLU', 'aten.relu.default']J pkg.torch.onnx.fx_nodej%relu : [num_users=1] = call_function[target=torch.ops.aten.relu.default](args = (%add_856,), kwargs = {})Jy pkg.torch.onnx.name_scopes[['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.res', 'relu']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 54, in forward res = self.res(early_conv + x) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 144, in forward return F.relu(input, inplace=self.inplace)  relu *septimbre_amt.note_branch.neck.conv.weight relu_bias getitem_6node_Conv_1611"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@ getitem_6relu_1 node_relu_1"ReluJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.neck: model.layers.CBR/septimbre_amt.note_branch.neck.act: torch.nn.modules.activation.ReLU/relu_1: aten.relu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'model.layers.CBR', 'torch.nn.modules.activation.ReLU', 'aten.relu.default']J pkg.torch.onnx.fx_noden%relu_1 : [num_users=2] = call_function[target=torch.ops.aten.relu.default](args = (%getitem_6,), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.neck', 'septimbre_amt.note_branch.neck.act', 'relu_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 55, in forward neck = self.neck(res) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 193, in forward x = self.act(x) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 144, in forward return F.relu(input, inplace=self.inplace)  relu_1 *septimbre_amt.note_branch.conv_yn.0.weight (septimbre_amt.note_branch.conv_yn.0.biasconv2d_1 node_conv2d_1"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.conv_yn: torch.nn.modules.container.Sequential/septimbre_amt.note_branch.conv_yn.0: torch.nn.modules.conv.Conv2d/conv2d_1: aten.conv2d.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.conv2d.default']J pkg.torch.onnx.fx_node%conv2d_1 : [num_users=1] = call_function[target=torch.ops.aten.conv2d.default](args = (%relu_1, %p_septimbre_amt_note_branch_conv_yn_0_weight, %p_septimbre_amt_note_branch_conv_yn_0_bias, [3, 1], [1, 2]), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.conv_yn', 'septimbre_amt.note_branch.conv_yn.0', 'conv2d_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 58, in forward yn = self.conv_yn(neck) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias) conv2d_1sigmoid node_sigmoid"SigmoidJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.conv_yn: torch.nn.modules.container.Sequential/septimbre_amt.note_branch.conv_yn.1: torch.nn.modules.activation.Sigmoid/sigmoid: aten.sigmoid.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.activation.Sigmoid', 'aten.sigmoid.default']J pkg.torch.onnx.fx_nodeq%sigmoid : [num_users=2] = call_function[target=torch.ops.aten.sigmoid.default](args = (%conv2d_1,), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.conv_yn', 'septimbre_amt.note_branch.conv_yn.1', 'sigmoid']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 58, in forward yn = self.conv_yn(neck) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 359, in forward return torch.sigmoid(input)  relu_1 .septimbre_amt.note_branch.conv_yo1.conv.weight relu_1_bias getitem_9node_Conv_1613"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@ getitem_9relu_2 node_relu_2"ReluJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.conv_yo1: model.layers.CBR/septimbre_amt.note_branch.conv_yo1.act: torch.nn.modules.activation.ReLU/relu_2: aten.relu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'model.layers.CBR', 'torch.nn.modules.activation.ReLU', 'aten.relu.default']J pkg.torch.onnx.fx_noden%relu_2 : [num_users=1] = call_function[target=torch.ops.aten.relu.default](args = (%getitem_9,), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.conv_yo1', 'septimbre_amt.note_branch.conv_yo1.act', 'relu_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 61, in forward _yo = self.conv_yo1(neck) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 193, in forward x = self.act(x) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 144, in forward return F.relu(input, inplace=self.inplace)  sigmoid relu_2concat node_concat"Concat* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/concat: aten.concat.defaultJ pkg.torch.onnx.class_hierarchyp['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'aten.concat.default']J pkg.torch.onnx.fx_node{%concat : [num_users=1] = call_function[target=torch.ops.aten.concat.default](args = ([%sigmoid, %relu_2], 1), kwargs = {})JZ pkg.torch.onnx.name_scopes<['', 'septimbre_amt', 'septimbre_amt.note_branch', 'concat']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 63, in forward yo = torch.concat((yn, _yo), dim=1)  concat +septimbre_amt.note_branch.conv_yo2.0.weight )septimbre_amt.note_branch.conv_yo2.0.bias convolution_2node_convolution_2"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.conv_yo2: torch.nn.modules.container.Sequential/septimbre_amt.note_branch.conv_yo2.0: torch.nn.modules.conv.Conv2d/convolution_2: aten.convolution.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.convolution.default']J pkg.torch.onnx.fx_node%convolution_2 : [num_users=1] = call_function[target=torch.ops.aten.convolution.default](args = (%concat, %p_septimbre_amt_note_branch_conv_yo2_0_weight, %p_septimbre_amt_note_branch_conv_yo2_0_bias, [1, 1], [1, 2], [1, 1], False, [0, 0], 1), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.conv_yo2', 'septimbre_amt.note_branch.conv_yo2.0', 'convolution_2']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 65, in forward yo = self.conv_yo2(yo) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias) convolution_2 sigmoid_1node_sigmoid_1"SigmoidJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/septimbre_amt.note_branch.conv_yo2: torch.nn.modules.container.Sequential/septimbre_amt.note_branch.conv_yo2.1: torch.nn.modules.activation.Sigmoid/sigmoid_1: aten.sigmoid.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.activation.Sigmoid', 'aten.sigmoid.default']J pkg.torch.onnx.fx_nodex%sigmoid_1 : [num_users=1] = call_function[target=torch.ops.aten.sigmoid.default](args = (%convolution_2,), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.note_branch', 'septimbre_amt.note_branch.conv_yo2', 'septimbre_amt.note_branch.conv_yo2.1', 'sigmoid_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 65, in forward yo = self.conv_yo2(yo) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 359, in forward return torch.sigmoid(input)  sigmoid_1 val_353squeeze node_squeeze"SqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/squeeze: aten.squeeze.dimJ pkg.torch.onnx.class_hierarchym['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'aten.squeeze.dim']J pkg.torch.onnx.fx_nodep%squeeze : [num_users=2] = call_function[target=torch.ops.aten.squeeze.dim](args = (%sigmoid_1, 1), kwargs = {})J[ pkg.torch.onnx.name_scopes=['', 'septimbre_amt', 'septimbre_amt.note_branch', 'squeeze']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 67, in forward return yo.squeeze(1), yn.squeeze(1) # (batch, 7*12, len), (batch, 7*12, len)  sigmoid val_353 squeeze_1node_squeeze_1"SqueezeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.note_branch: septimbre.NotePredictBranch/squeeze_1: aten.squeeze.dimJ pkg.torch.onnx.class_hierarchym['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.NotePredictBranch', 'aten.squeeze.dim']J pkg.torch.onnx.fx_nodep%squeeze_1 : [num_users=2] = call_function[target=torch.ops.aten.squeeze.dim](args = (%sigmoid, 1), kwargs = {})J] pkg.torch.onnx.name_scopes?['', 'septimbre_amt', 'septimbre_amt.note_branch', 'squeeze_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 144, in forward note_onset, note_pred = self.note_branch(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 67, in forward return yo.squeeze(1), yn.squeeze(1) # (batch, 7*12, len), (batch, 7*12, len)  slice_scatter_22 septimbre_amt.encoder.kmul_740 node_mul_740"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/mul_740: aten.mul.TensorJ pkg.torch.onnx.class_hierarchyb['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'aten.mul.Tensor']J pkg.torch.onnx.fx_node%mul_740 : [num_users=1] = call_function[target=torch.ops.aten.mul.Tensor](args = (%slice_scatter_22, %p_septimbre_amt_encoder_k), kwargs = {})JW pkg.torch.onnx.name_scopes9['', 'septimbre_amt', 'septimbre_amt.encoder', 'mul_740']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 109, in forward x = x * self.k + self.b  mul_740 septimbre_amt.encoder.badd_927 node_add_927"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/add_927: aten.add.TensorJ pkg.torch.onnx.class_hierarchyb['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'aten.add.Tensor']J pkg.torch.onnx.fx_node%add_927 : [num_users=2] = call_function[target=torch.ops.aten.add.Tensor](args = (%mul_740, %p_septimbre_amt_encoder_b), kwargs = {})JW pkg.torch.onnx.name_scopes9['', 'septimbre_amt', 'septimbre_amt.encoder', 'add_927']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 109, in forward x = x * self.k + self.b  add_927 )septimbre_amt.encoder.early_conv.0.weight 'septimbre_amt.encoder.early_conv.0.bias convolution_3node_convolution_3"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.0: torch.nn.modules.conv.Conv2d/convolution_3: aten.convolution.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.convolution.default']J pkg.torch.onnx.fx_node%convolution_3 : [num_users=1] = call_function[target=torch.ops.aten.convolution.default](args = (%add_927, %p_septimbre_amt_encoder_early_conv_0_weight, %p_septimbre_amt_encoder_early_conv_0_bias, [1, 1], [2, 2], [1, 1], False, [0, 0], 1), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.0', 'convolution_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias) convolution_3 val_1253val_1254node_Reshape_1254"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.1: torch.nn.modules.normalization.GroupNorm/group_norm: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%convolution_3, 4, %p_septimbre_amt_encoder_early_conv_1_weight, %p_septimbre_amt_encoder_early_conv_1_bias), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.1', 'group_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps)  val_1254 val_1257 val_1260val_1261node_InstanceNormalization_1261"InstanceNormalization* epsilon'7J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.1: torch.nn.modules.normalization.GroupNorm/group_norm: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%convolution_3, 4, %p_septimbre_amt_encoder_early_conv_1_weight, %p_septimbre_amt_encoder_early_conv_1_bias), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.1', 'group_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) convolution_3val_1262node_Shape_1262"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.1: torch.nn.modules.normalization.GroupNorm/group_norm: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%convolution_3, 4, %p_septimbre_amt_encoder_early_conv_1_weight, %p_septimbre_amt_encoder_early_conv_1_bias), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.1', 'group_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1261 val_1262val_1263node_Reshape_1263"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.1: torch.nn.modules.normalization.GroupNorm/group_norm: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%convolution_3, 4, %p_septimbre_amt_encoder_early_conv_1_weight, %p_septimbre_amt_encoder_early_conv_1_bias), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.1', 'group_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1263 val_1269val_1270 node_Mul_1270"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.1: torch.nn.modules.normalization.GroupNorm/group_norm: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%convolution_3, 4, %p_septimbre_amt_encoder_early_conv_1_weight, %p_septimbre_amt_encoder_early_conv_1_bias), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.1', 'group_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1270 val_1271 group_normnode_group_norm"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.1: torch.nn.modules.normalization.GroupNorm/group_norm: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%convolution_3, 4, %p_septimbre_amt_encoder_early_conv_1_weight, %p_septimbre_amt_encoder_early_conv_1_bias), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.1', 'group_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) group_norm leaky_relu_1node_leaky_relu_1" LeakyRelu* alpha #<J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.2: torch.nn.modules.activation.LeakyReLU/leaky_relu_1: aten.leaky_relu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.activation.LeakyReLU', 'aten.leaky_relu.default']J pkg.torch.onnx.fx_node{%leaky_relu_1 : [num_users=1] = call_function[target=torch.ops.aten.leaky_relu.default](args = (%group_norm,), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.2', 'leaky_relu_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 922, in forward return F.leaky_relu(input, self.negative_slope, self.inplace)  leaky_relu_1 )septimbre_amt.encoder.early_conv.3.weight 'septimbre_amt.encoder.early_conv.3.biasconv2d_3 node_conv2d_3"Conv* auto_pad"NOTSET* dilations@@* group* pads@$@@$@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.early_conv: torch.nn.modules.container.Sequential/septimbre_amt.encoder.early_conv.3: torch.nn.modules.conv.Conv2d/conv2d_3: aten.conv2d.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.conv2d.default']J pkg.torch.onnx.fx_node%conv2d_3 : [num_users=1] = call_function[target=torch.ops.aten.conv2d.default](args = (%leaky_relu_1, %p_septimbre_amt_encoder_early_conv_3_weight, %p_septimbre_amt_encoder_early_conv_3_bias, [1, 1], [36, 1], [3, 1]), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.early_conv', 'septimbre_amt.encoder.early_conv.3', 'conv2d_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias)  conv2d_3 add_927add_955 node_add_955"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/add_955: aten.add.TensorJ pkg.torch.onnx.class_hierarchyb['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'aten.add.Tensor']J pkg.torch.onnx.fx_nodeu%add_955 : [num_users=1] = call_function[target=torch.ops.aten.add.Tensor](args = (%conv2d_3, %add_927), kwargs = {})JW pkg.torch.onnx.name_scopes9['', 'septimbre_amt', 'septimbre_amt.encoder', 'add_955']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 111, in forward x = self.early_conv(x) + x add_955 val_1275val_1276node_Reshape_1276"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.0: torch.nn.modules.normalization.GroupNorm/group_norm_1: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm_1 : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%add_955, 2, %p_septimbre_amt_encoder_neck_0_weight, %p_septimbre_amt_encoder_neck_0_bias), kwargs = {})J pkg.torch.onnx.name_scopes|['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.0', 'group_norm_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1276 val_1279 val_1282val_1283node_InstanceNormalization_1283"InstanceNormalization* epsilon'7J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.0: torch.nn.modules.normalization.GroupNorm/group_norm_1: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm_1 : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%add_955, 2, %p_septimbre_amt_encoder_neck_0_weight, %p_septimbre_amt_encoder_neck_0_bias), kwargs = {})J pkg.torch.onnx.name_scopes|['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.0', 'group_norm_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) add_955val_1284node_Shape_1284"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.0: torch.nn.modules.normalization.GroupNorm/group_norm_1: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm_1 : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%add_955, 2, %p_septimbre_amt_encoder_neck_0_weight, %p_septimbre_amt_encoder_neck_0_bias), kwargs = {})J pkg.torch.onnx.name_scopes|['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.0', 'group_norm_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1283 val_1284val_1285node_Reshape_1285"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.0: torch.nn.modules.normalization.GroupNorm/group_norm_1: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm_1 : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%add_955, 2, %p_septimbre_amt_encoder_neck_0_weight, %p_septimbre_amt_encoder_neck_0_bias), kwargs = {})J pkg.torch.onnx.name_scopes|['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.0', 'group_norm_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1285 val_1291val_1292 node_Mul_1292"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.0: torch.nn.modules.normalization.GroupNorm/group_norm_1: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm_1 : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%add_955, 2, %p_septimbre_amt_encoder_neck_0_weight, %p_septimbre_amt_encoder_neck_0_bias), kwargs = {})J pkg.torch.onnx.name_scopes|['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.0', 'group_norm_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps) val_1292 val_1293 group_norm_1node_group_norm_1"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.0: torch.nn.modules.normalization.GroupNorm/group_norm_1: aten.group_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.normalization.GroupNorm', 'aten.group_norm.default']J pkg.torch.onnx.fx_node%group_norm_1 : [num_users=1] = call_function[target=torch.ops.aten.group_norm.default](args = (%add_955, 2, %p_septimbre_amt_encoder_neck_0_weight, %p_septimbre_amt_encoder_neck_0_bias), kwargs = {})J pkg.torch.onnx.name_scopes|['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.0', 'group_norm_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 325, in forward return F.group_norm(input, self.num_groups, self.weight, self.bias, self.eps)  group_norm_1 #septimbre_amt.encoder.neck.1.weight !septimbre_amt.encoder.neck.1.bias convolution_4node_convolution_4"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.1: torch.nn.modules.conv.Conv2d/convolution_4: aten.convolution.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.convolution.default']J pkg.torch.onnx.fx_node%convolution_4 : [num_users=1] = call_function[target=torch.ops.aten.convolution.default](args = (%group_norm_1, %p_septimbre_amt_encoder_neck_1_weight, %p_septimbre_amt_encoder_neck_1_bias, [1, 1], [2, 2], [1, 1], False, [0, 0], 1), kwargs = {})J pkg.torch.onnx.name_scopes}['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.1', 'convolution_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias) convolution_4 val_1295prelu node_prelu"PReluJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.neck: torch.nn.modules.container.Sequential/septimbre_amt.encoder.neck.2: torch.nn.modules.activation.PReLU/prelu: aten.prelu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.activation.PReLU', 'aten.prelu.default']J pkg.torch.onnx.fx_node%prelu : [num_users=2] = call_function[target=torch.ops.aten.prelu.default](args = (%convolution_4, %p_septimbre_amt_encoder_neck_2_weight), kwargs = {})J pkg.torch.onnx.name_scopesu['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.neck', 'septimbre_amt.encoder.neck.2', 'prelu']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 112, in forward emb = self.neck(x) # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 1638, in forward return F.prelu(input, self.weight) prelupermute node_permute" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.res1: torch.nn.modules.container.Sequential/septimbre_amt.encoder.res1.0: model.layers.LayerNorm2d/permute: aten.permute.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.LayerNorm2d', 'aten.permute.default']J pkg.torch.onnx.fx_node{%permute : [num_users=1] = call_function[target=torch.ops.aten.permute.default](args = (%prelu, [0, 2, 3, 1]), kwargs = {})J pkg.torch.onnx.name_scopesw['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.res1', 'septimbre_amt.encoder.res1.0', 'permute']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 113, in forward x = x.permute(0, 2, 3, 1) # (batch, n_bins, len, channel)  permute .septimbre_amt.encoder.res1.0.layer_norm.weight ,septimbre_amt.encoder.res1.0.layer_norm.bias layer_normnode_layer_norm"LayerNormalization* axis* epsilonE-2* stash_typeJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.res1: torch.nn.modules.container.Sequential/septimbre_amt.encoder.res1.0: model.layers.LayerNorm2d/septimbre_amt.encoder.res1.0.layer_norm: torch.nn.modules.normalization.LayerNorm/layer_norm: aten.layer_norm.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.LayerNorm2d', 'torch.nn.modules.normalization.LayerNorm', 'aten.layer_norm.default']J pkg.torch.onnx.fx_node%layer_norm : [num_users=1] = call_function[target=torch.ops.aten.layer_norm.default](args = (%permute, [16], %p_septimbre_amt_encoder_res1_0_layer_norm_weight, %p_septimbre_amt_encoder_res1_0_layer_norm_bias, 1.01e-08), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.res1', 'septimbre_amt.encoder.res1.0', 'septimbre_amt.encoder.res1.0.layer_norm', 'layer_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 114, in forward x = self.layer_norm(x) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/normalization.py", line 229, in forward return F.layer_norm( layer_norm permute_1node_permute_1" Transpose* perm@@@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.res1: torch.nn.modules.container.Sequential/septimbre_amt.encoder.res1.0: model.layers.LayerNorm2d/permute_1: aten.permute.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.LayerNorm2d', 'aten.permute.default']J pkg.torch.onnx.fx_node%permute_1 : [num_users=1] = call_function[target=torch.ops.aten.permute.default](args = (%layer_norm, [0, 3, 1, 2]), kwargs = {})J pkg.torch.onnx.name_scopesy['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.res1', 'septimbre_amt.encoder.res1.0', 'permute_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 115, in forward x = x.permute(0, 3, 1, 2) # (batch, channel, n_bins, len)  permute_1 #septimbre_amt.encoder.res1.1.weight !septimbre_amt.encoder.res1.1.bias convolution_5node_convolution_5"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.res1: torch.nn.modules.container.Sequential/septimbre_amt.encoder.res1.1: torch.nn.modules.conv.Conv2d/convolution_5: aten.convolution.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.convolution.default']J pkg.torch.onnx.fx_node%convolution_5 : [num_users=1] = call_function[target=torch.ops.aten.convolution.default](args = (%permute_1, %p_septimbre_amt_encoder_res1_1_weight, %p_septimbre_amt_encoder_res1_1_bias, [1, 1], [1, 1], [1, 1], False, [0, 0], 1), kwargs = {})J pkg.torch.onnx.name_scopes}['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.res1', 'septimbre_amt.encoder.res1.1', 'convolution_5']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias) convolution_5relu_3 node_relu_3"ReluJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.res1: torch.nn.modules.container.Sequential/septimbre_amt.encoder.res1.2: torch.nn.modules.activation.ReLU/relu_3: aten.relu.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.activation.ReLU', 'aten.relu.default']J pkg.torch.onnx.fx_noder%relu_3 : [num_users=1] = call_function[target=torch.ops.aten.relu.default](args = (%convolution_5,), kwargs = {})J pkg.torch.onnx.name_scopesv['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.res1', 'septimbre_amt.encoder.res1.2', 'relu_3']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/activation.py", line 144, in forward return F.relu(input, inplace=self.inplace)  relu_3 #septimbre_amt.encoder.res1.3.weight !septimbre_amt.encoder.res1.3.bias convolution_6node_convolution_6"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.res1: torch.nn.modules.container.Sequential/septimbre_amt.encoder.res1.3: torch.nn.modules.conv.Conv2d/convolution_6: aten.convolution.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.convolution.default']J pkg.torch.onnx.fx_node%convolution_6 : [num_users=1] = call_function[target=torch.ops.aten.convolution.default](args = (%relu_3, %p_septimbre_amt_encoder_res1_3_weight, %p_septimbre_amt_encoder_res1_3_bias, [1, 1], [1, 1], [1, 1], False, [0, 0], 1), kwargs = {})J pkg.torch.onnx.name_scopes}['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.res1', 'septimbre_amt.encoder.res1.3', 'convolution_6']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias)  convolution_6 preluadd_995 node_add_995"AddJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/add_995: aten.add.TensorJ pkg.torch.onnx.class_hierarchyb['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'aten.add.Tensor']J pkg.torch.onnx.fx_nodex%add_995 : [num_users=3] = call_function[target=torch.ops.aten.add.Tensor](args = (%convolution_6, %prelu), kwargs = {})JW pkg.torch.onnx.name_scopes9['', 'septimbre_amt', 'septimbre_amt.encoder', 'add_995']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 113, in forward emb = self.res1(emb) + emb # (B, 16, 84, T) add_995 val_1300mean node_mean" ReduceMean* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/mean: aten.mean.dimJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'aten.mean.dim']J pkg.torch.onnx.fx_nodeu%mean : [num_users=1] = call_function[target=torch.ops.aten.mean.dim](args = (%add_995, [-1, -2], True), kwargs = {})J pkg.torch.onnx.name_scopesr['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'mean']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k add_995 val_1301val_1302node_ReduceMean_1300" ReduceMean* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k add_995 val_1302val_1303 node_Sub_1301"SubJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1303 val_1303val_1304 node_Mul_1302"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1304 val_1301val_1305node_ReduceMean_1303" ReduceMean* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k add_995val_1306node_Shape_1304"Shape* startJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1306 val_1301val_1307node_Gather_1305"Gather* axisJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1307val_1308node_ReduceProd_1306" ReduceProd* keepdims* noop_with_empty_axesJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k 5 val_1308val_1309node_Cast_1548"Cast* to val_1305 val_1309val_1310 node_Mul_1308"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1309 val_369val_1312 node_Sub_1310"SubJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1310 val_1312var_1 node_var_1"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/var_1: prims.var.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.var.default']J pkg.torch.onnx.fx_nodew%var_1 : [num_users=1] = call_function[target=torch.ops.prims.var.default](args = (%add_995, [3, 2], 1.0), kwargs = {})J pkg.torch.onnx.name_scopess['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'var_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k var_1 val_1320val_1321node_Reshape_1319"Reshape* allowzeroJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/broadcast_in_dim_1: prims.broadcast_in_dim.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'prims.broadcast_in_dim.default']J pkg.torch.onnx.fx_node%broadcast_in_dim_1 : [num_users=1] = call_function[target=torch.ops.prims.broadcast_in_dim.default](args = (%var_1, [1, 16, 1, 1], [0, 1]), kwargs = {})J pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'broadcast_in_dim_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k val_1321sqrt_1 node_sqrt_1"SqrtJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/sqrt_1: aten.sqrt.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'aten.sqrt.default']J pkg.torch.onnx.fx_nodew%sqrt_1 : [num_users=1] = call_function[target=torch.ops.aten.sqrt.default](args = (%broadcast_in_dim_1,), kwargs = {})J pkg.torch.onnx.name_scopest['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'sqrt_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k add_995 meansub_205 node_sub_205"SubJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/sub_205: aten.sub.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'aten.sub.Tensor']J pkg.torch.onnx.fx_nodeq%sub_205 : [num_users=1] = call_function[target=torch.ops.aten.sub.Tensor](args = (%add_995, %mean), kwargs = {})J pkg.torch.onnx.name_scopesu['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'sub_205']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k sub_205 sqrt_1divnode_div"DivJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/div: aten.div.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'aten.div.Tensor']J pkg.torch.onnx.fx_nodeq%div : [num_users=1] = call_function[target=torch.ops.aten.div.Tensor](args = (%sub_205, %add_1002), kwargs = {})J pkg.torch.onnx.name_scopesq['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'div']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k div septimbre_amt.encoder.emb.0.kmul_863 node_mul_863"MulJ namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.0: model.layers.CenterNorm2d/mul_863: aten.mul.TensorJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'model.layers.CenterNorm2d', 'aten.mul.Tensor']J pkg.torch.onnx.fx_node%mul_863 : [num_users=1] = call_function[target=torch.ops.aten.mul.Tensor](args = (%div, %p_septimbre_amt_encoder_emb_0_k), kwargs = {})J pkg.torch.onnx.name_scopesu['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.0', 'mul_863']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/septimbre/../model/layers.py", line 126, in forward return self.center_norm(x, self.eps) * self.k  mul_863 "septimbre_amt.encoder.emb.1.weight septimbre_amt.encoder.emb.1.biasconv2d_4 node_conv2d_4"Conv* auto_pad"NOTSET* dilations@@* group* pads@@@@* strides@@J namespace: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/septimbre_amt.encoder: septimbre.Encoder/septimbre_amt.encoder.emb: torch.nn.modules.container.Sequential/septimbre_amt.encoder.emb.1: torch.nn.modules.conv.Conv2d/conv2d_4: aten.conv2d.defaultJ pkg.torch.onnx.class_hierarchy['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'septimbre.Encoder', 'torch.nn.modules.container.Sequential', 'torch.nn.modules.conv.Conv2d', 'aten.conv2d.default']J pkg.torch.onnx.fx_node%conv2d_4 : [num_users=2] = call_function[target=torch.ops.aten.conv2d.default](args = (%mul_863, %p_septimbre_amt_encoder_emb_1_weight, %p_septimbre_amt_encoder_emb_1_bias, [3, 1], [1, 2]), kwargs = {})J pkg.torch.onnx.name_scopesv['', 'septimbre_amt', 'septimbre_amt.encoder', 'septimbre_amt.encoder.emb', 'septimbre_amt.encoder.emb.1', 'conv2d_4']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 146, in forward emb = self.encoder(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 114, in forward emb = self.emb(emb) # (B, emb_dims, 84, T) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/container.py", line 250, in forward input = module(input) File "/home/liruigang/timbreAMT/.venv/lib/python3.12/site-packages/torch/nn/modules/conv.py", line 548, in forward return self._conv_forward(input, self.weight, self.bias)  conv2d_4 val_353linalg_vector_normnode_linalg_vector_norm"ReduceL2* keepdims* noop_with_empty_axesJ namespacex: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/linalg_vector_norm: aten.linalg_vector_norm.defaultJ pkg.torch.onnx.class_hierarchy]['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'aten.linalg_vector_norm.default']J pkg.torch.onnx.fx_node%linalg_vector_norm : [num_users=1] = call_function[target=torch.ops.aten.linalg_vector_norm.default](args = (%conv2d_4, 2, [1], True), kwargs = {})JI pkg.torch.onnx.name_scopes+['', 'septimbre_amt', 'linalg_vector_norm']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 151, in forward emb = nn.functional.normalize(emb, p=2, dim=1)  linalg_vector_norm val_1327 clamp_minnode_clamp_min"ClipJs namespacef: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/clamp_min: aten.clamp_min.defaultJv pkg.torch.onnx.class_hierarchyT['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'aten.clamp_min.default']J pkg.torch.onnx.fx_node%clamp_min : [num_users=1] = call_function[target=torch.ops.aten.clamp_min.default](args = (%linalg_vector_norm, 1e-12), kwargs = {})J@ pkg.torch.onnx.name_scopes"['', 'septimbre_amt', 'clamp_min']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 151, in forward emb = nn.functional.normalize(emb, p=2, dim=1)  val_353 val_1330 val_904 val_390val_1333node_Concat_1331"Concat* axisJm namespace`: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/expand: aten.expand.defaultJs pkg.torch.onnx.class_hierarchyQ['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'aten.expand.default']J pkg.torch.onnx.fx_node%expand : [num_users=1] = call_function[target=torch.ops.aten.expand.default](args = (%clamp_min, [1, 12, 84, %add_626]), kwargs = {})J= pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'expand']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 151, in forward emb = nn.functional.normalize(emb, p=2, dim=1)  clamp_min val_1333expand node_expand"ExpandJm namespace`: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/expand: aten.expand.defaultJs pkg.torch.onnx.class_hierarchyQ['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'aten.expand.default']J pkg.torch.onnx.fx_node%expand : [num_users=1] = call_function[target=torch.ops.aten.expand.default](args = (%clamp_min, [1, 12, 84, %add_626]), kwargs = {})J= pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'expand']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 151, in forward emb = nn.functional.normalize(emb, p=2, dim=1)  conv2d_4 expand embedding node_div_1"DivJh namespace[: septimbre.SepTimbreAMT_44100/septimbre_amt: septimbre.SepTimbreAMT/div_1: aten.div.TensorJo pkg.torch.onnx.class_hierarchyM['septimbre.SepTimbreAMT_44100', 'septimbre.SepTimbreAMT', 'aten.div.Tensor']J pkg.torch.onnx.fx_noder%div_1 : [num_users=1] = call_function[target=torch.ops.aten.div.Tensor](args = (%conv2d_4, %expand), kwargs = {})J< pkg.torch.onnx.name_scopes['', 'septimbre_amt', 'div_1']J pkg.torch.onnx.stack_traceFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 191, in forward onset, note, emb = self.septimbre_amt(x) File "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 151, in forward emb = nn.functional.normalize(emb, p=2, dim=1)  squeezemax_1 node_max_1" ReduceMax* keepdims* noop_with_empty_axesJC namespace6: septimbre.SepTimbreAMT_44100/max_1: aten.max.defaultJV pkg.torch.onnx.class_hierarchy4['septimbre.SepTimbreAMT_44100', 'aten.max.default']J pkg.torch.onnx.fx_nodej%max_1 : [num_users=1] = call_function[target=torch.ops.aten.max.default](args = (%squeeze,), kwargs = {})J+ pkg.torch.onnx.name_scopes ['', 'max_1']J pkg.torch.onnx.stack_tracefFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 192, in forward onset /= onset.max()  squeeze max_1div_2 node_div_2"DivJB namespace5: septimbre.SepTimbreAMT_44100/div_2: aten.div.TensorJU pkg.torch.onnx.class_hierarchy3['septimbre.SepTimbreAMT_44100', 'aten.div.Tensor']J pkg.torch.onnx.fx_nodep%div_2 : [num_users=1] = call_function[target=torch.ops.aten.div.Tensor](args = (%squeeze, %max_1), kwargs = {})J+ pkg.torch.onnx.name_scopes ['', 'div_2']J pkg.torch.onnx.stack_tracefFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 192, in forward onset /= onset.max()  div_2 val_353 unsqueezenode_unsqueeze" UnsqueezeJM namespace@: septimbre.SepTimbreAMT_44100/unsqueeze: aten.unsqueeze.defaultJ\ pkg.torch.onnx.class_hierarchy:['septimbre.SepTimbreAMT_44100', 'aten.unsqueeze.default']J pkg.torch.onnx.fx_nodet%unsqueeze : [num_users=1] = call_function[target=torch.ops.aten.unsqueeze.default](args = (%div_2, 1), kwargs = {})J/ pkg.torch.onnx.name_scopes['', 'unsqueeze']J pkg.torch.onnx.stack_tracefFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 192, in forward onset /= onset.max()  unsqueeze val_353onsetnode_squeeze_2"SqueezeJG namespace:: septimbre.SepTimbreAMT_44100/squeeze_2: aten.squeeze.dimJV pkg.torch.onnx.class_hierarchy4['septimbre.SepTimbreAMT_44100', 'aten.squeeze.dim']J pkg.torch.onnx.fx_noder%squeeze_2 : [num_users=1] = call_function[target=torch.ops.aten.squeeze.dim](args = (%unsqueeze, 1), kwargs = {})J/ pkg.torch.onnx.name_scopes['', 'squeeze_2']J pkg.torch.onnx.stack_tracefFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 192, in forward onset /= onset.max()  squeeze_1max_2 node_max_2" ReduceMax* keepdims* noop_with_empty_axesJC namespace6: septimbre.SepTimbreAMT_44100/max_2: aten.max.defaultJV pkg.torch.onnx.class_hierarchy4['septimbre.SepTimbreAMT_44100', 'aten.max.default']J pkg.torch.onnx.fx_nodel%max_2 : [num_users=1] = call_function[target=torch.ops.aten.max.default](args = (%squeeze_1,), kwargs = {})J+ pkg.torch.onnx.name_scopes ['', 'max_2']J pkg.torch.onnx.stack_tracedFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 193, in forward note /= note.max()  squeeze_1 max_2div_3 node_div_3"DivJB namespace5: septimbre.SepTimbreAMT_44100/div_3: aten.div.TensorJU pkg.torch.onnx.class_hierarchy3['septimbre.SepTimbreAMT_44100', 'aten.div.Tensor']J pkg.torch.onnx.fx_noder%div_3 : [num_users=1] = call_function[target=torch.ops.aten.div.Tensor](args = (%squeeze_1, %max_2), kwargs = {})J+ pkg.torch.onnx.name_scopes ['', 'div_3']J pkg.torch.onnx.stack_tracedFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 193, in forward note /= note.max()  div_3 val_353 unsqueeze_1node_unsqueeze_1" UnsqueezeJO namespaceB: septimbre.SepTimbreAMT_44100/unsqueeze_1: aten.unsqueeze.defaultJ\ pkg.torch.onnx.class_hierarchy:['septimbre.SepTimbreAMT_44100', 'aten.unsqueeze.default']J pkg.torch.onnx.fx_nodev%unsqueeze_1 : [num_users=1] = call_function[target=torch.ops.aten.unsqueeze.default](args = (%div_3, 1), kwargs = {})J1 pkg.torch.onnx.name_scopes['', 'unsqueeze_1']J pkg.torch.onnx.stack_tracedFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 193, in forward note /= note.max()  unsqueeze_1 val_353framenode_squeeze_3"SqueezeJG namespace:: septimbre.SepTimbreAMT_44100/squeeze_3: aten.squeeze.dimJV pkg.torch.onnx.class_hierarchy4['septimbre.SepTimbreAMT_44100', 'aten.squeeze.dim']J pkg.torch.onnx.fx_nodet%squeeze_3 : [num_users=1] = call_function[target=torch.ops.aten.squeeze.dim](args = (%unsqueeze_1, 1), kwargs = {})J/ pkg.torch.onnx.name_scopes['', 'squeeze_3']J pkg.torch.onnx.stack_tracedFile "/home/liruigang/timbreAMT/septimbre/septimbre.py", line 193, in forward note /= note.max() main_graph*HBseptimbre_amt.cqt.cqt_kernelsJN6Cߴ+[5gI5œ4Fel56&6\׶W@K777yj"zܰ7:8WcK7,Dne!728Rr8Pg ̺8%Q9/c@=Iv989X8Pa)2559d 90[*dx9_:`)8# U{9]:c9'[::JZ~J;og:I:Pb9/ĺ5к9;p':),PL&;|#;8QSP^;S\;8j;:V>;&;Q;;q2i`⻶d?;k;ᆍ:xh׻ϻC:/<';3q4;9;y|%Up~(;;:;j8S\;P^;D><;;z;.J9k_3ќ:\;.Z l77ؙ6>3÷۷Jv7N187_}z㸶8#8xyLu89bi;KZ8g958z"Vl8̺9x9"JKB:]: >r&:BD{ :MX:+)8ngG9_:B9 @8:d:'QemU:ʽ:uX[ :/;}9-b1:d_;E:$jsIz;2SB;.XȺ^2t;Zn;K"OZiA;G;:"%"R:; b;ꌻuyj1;;z+wOSH;HE;\4KP%Y;<_,;8/:]:KB:J"x9̺9Vl8"z58g9Z8Ki;b궻9u8xyL#88z㸶_}7N18Jv7۷>3÷ؙ67 l7.Z <>E*6e6õ+qGh5)5%1-|cN"A 5M5˔4%>15+676Zm_ 5$67<; " <ې. Z;|i<¬:ٜiȻ{A2;; .;ARл‹:3;k;U-ɻf;J;$619݌;"X;m՞@B G;v;Dx@D:̠c; :b;:2/:և;;;}:)8 ;9=;흖:S򺮳޸T:ە:0cĿۀ魋:Y܄:m, qH*:W:::B Fb 8sp\;;Z:{~x9;B@;v(cr9qS;bQz;ۋ̷;;h;R zOջ<#F;վ;,[?T;f?;-]F~U;=J<8?X ej;<鮸;$;z<*H:L9a;Z':u4;N9OguhK:R;E192ی\.:a:u9S.9a:99]3h WT9k:Ñ9'R+z8'(!:g93-7:9sk9V}Y)89r&9jL[N ÷9*8yo@:캷&;88Ecٷf9Ê&8PD8`)<,G)n7pn7vnN&c[!R6J6P~ùHϵر55 ɲ @;ʹ)\ܴz/55wH"zIȮv6 g6V;2'C77Fd-hUl7u)8[ Gzq8%8nj8QZ8 9 5,M D9Fg9X ͝9N99_L%V9:wU AVB<:8:ZMù` 4ʇ:Oz:G_:Oۼ: :U`륹:\:bS#'x&;z;u˺.?Mk璹pT;;!{W?Pq";l4;+/Ö͂h;L;8V g~ 9Z;yc;;1ɻ9;8v; ⻣<:D;;u .:$ <ۆ;λQ:<6;滈w V;š#<;;TcL;&+<;2?P=;1<n;) :\X;3<3X;AMo;1<>;BRc;-< &!;Xȷ;Y%<;+oʉ;@ A:1m绖|;׻;K93lϻ$Jj;;9s]fS;;/gj2UT2:;6B;]X ! ;];^rVpպ;.;Y󭹱V+1\f:-;He)Cb:3:~_ɺQ:Ԑ::#ѹE:J:cg!Oidž ::)32c u"%F9j9MC[ y~97Y9CNc}IB9 87j"Ʒ788 _60bC88 ̆+k78 8lլ8緜[.D9T 9_X]Qx9F964b69|9_ 8r%:n9,29s:x9(sX:kr:8'zd4:(7:>O3I:w;Ik+i8;';YV;cR';a>dJ;f&;ZN=eE:Z;,>;mҡ6: ;:wyjN;M;G:-gMQ,;Z;9Fw;;Z;eE:=ZNf&;J;>dacR';V;Y';8;ik+Iw;I:O3>(7:d4:'z8kr::X(sx9s:29,n9r%: 8_|99b664F9x9QX]_T 9D9.[lլ8 8 򅸼 >8jB7`57713\ 6q76Kq,vc55KW47"d41R㚴s5F5lz3=76H~`b]6}7R6շl7IN8'/u_88s8](k:Cķx9w 8}]H8l<9.8jq+)9N9^86s[p9":n<nPzyI:iE:>ٓC[:sG:(et9>:n:gʺ#:V3;Fn$7k(lJ ;T.;}k_^ɑYR W;k-;?F_9!; ;(s틻w:4; :ٮ#Fm;;/m޻]i:@;ҭ;;c ;~;. 8:9:t9e(sG:[:Cٓ>iE:yI:znPn<":[p9s6^8N9)9q+j.8l<9H8}]w 8x9Cķk:](s888u_/'IN8l7շR6}7b]6`H~6=7z3lF5s5㚴1R"d4[&(gf<559p㭵'6F6ѶxTW$6}77QӷϷ7y?8ⷩ8q8;`p>6$98@&R5 8ߌ9w632cZ9RF9sG; )q:L9ݱ1ơ9u:8ù)b:4:۹@wɺY=:.Q:ǧLa :;0::WRq:6;\I{,T;B*;:C:Ε;):)opw6; ;+큪;;̅Rxܻe,i9u;M5P;qȻ̻(&e;B<}A9ܮ ՁY;h;>k/(>Rl<㖩;Xbc;n-T6t6{ =615?#C4 [@O454sql)T6M6m"g957i"7"޷}߷7J8&)l__8 8Cpg=859 %7X08S9#~9B#69^F9ݹ;9U.+:rVEu_:oJ*:?9e7!91:0S9R#úfɫ:,:#Q ;;0:y2 >: E;9<չeZ9^;*;P@*偁 :͜;ZP:#?;b<;Ҏ5ȻL!M;1@;ijo;Y;DM 3٭';Wg;zj4C ;b<:4 ̷#;J <q,{8,: y20:;;  #Q,:ɫ:fR#ú0S91:7!9e?9oJ*:_:EurVU.+:;9ݹ^F996#B#~98S90X %759g=8pC 8_8l_&)J87}߷"޷i"77"g95mM6T6ql)s45O4@ [K^n35s5~hdk1 6 7ߦt0:7Ч-79 9g~7N8Tt[A85A8޸Pָ8 09\it_9g9D5Ov9԰9.øU*:9o'%MI098~:,Bn怹И:K:A]:nq:Ʌ! ;r:*2:\TM;+ i4bh;!;Bjx%u:^;}zHᬻW庅W;u;oC";(;m18>X2/C;;(Z+;<&;L,Y˻ŭ<;Xm18(;;"oCu;W;W庖ᬻ}zH^;%u:jxB!;h;4bi+ \TM;2:*r:;! Ʌnq:A]:K:И:n怹,B8~:9MI0o'%9U*:ø.԰9v9OD5g9_9it\ 098Pָ޸5A8[A8tTN8g~7 99Ч-77:t0ߦ 71 6dk~hs55n3K^ME2M5s5& QY66@Zv+o!77KȆ8B,8dwO=q7&8DFb7' @Yu c 9JT8quNъ869܀Ʒw"ﻸ*969չ9z%:WLiVf(z:~B9ÃH@s::\6Տ˺l9}:N9h|^ ;:ݺY" :L;hgYggԛm; ;X]&;Њ;ͰQc_;;⳻ʘ;;܊R{%:=s<-:Jq,9;; ^;B<z>@0,<;} S ;֝!<)(  <ٷb;Vܽb;9;, xrwf:3+<4ޤ:?H)JY;;wk ;;lmw6;I.;g b-;`Fy;sssW;U:E,꺺n: ;yE 9k;F9ٺ!D$:a:N09 :U i+j34:9y !܌9W9]ϸ:9͹SܷjѢ98ag899L\ w7kY87P&J8S8շT"7?7Unv+57"6萶Po\kl5:95ih @ ´<5 5|kZP6\6I_f5>76e*t.! 8)8m2 ݀pr'8y8t۷A ;FKh19BX8S g9`9agJf89uh94g?9s00:Dw9A>C:d+I:H.I%E:n: N_غ`:5@:?Aa: 4;źL,*:CQ;l mg\+({;:w< A^;u;-(:(;h/[ѻر9;T;ǻ;;Іy;U<1d92p*}A<;{vی:;Y<Ӕn/L;a < `d:(P>;I%@;̦;ݩ]λ[;;gǺTٻ6;T:r(5?;6h;f]ELr:.;543:zꔓD];놉:I6кW ;h:ar4M:>;Dp,<]:- :v+=bY:S:~R9@: K#\3Ը8U:EK9hp{Uz939Sm t8H9Rf 8{A80oQP [08I=8bbc67QS15~^ӀE='7qE6|䣶MP5Q5IU9dU4}57t@5&5 ҿ}gZ6IL7Q;{p-675)&)A8;7NvFF-88^C(9۔849 aos79VH.8+t>99zѹҟ9:БM:м9̓:$`Y#ꢶca:9кt2::#ߺֺt:6;&3?3GM}:eU;ٹs-A;`: `;O;FXb;-;}/̻_:;hX煖.,ຆ9:˯ŭasK:sD9C`F&:H-:fh99FtҹffB8R99t#7~L9G8;㱾8ȧ8xfNF7De8wI*K5#7iV6L< .79-6PMb6`55GB'ZJ4E.$R5̀5&? .]{67ҮrsA67{oj5g[86K[sT8/8&Z19X8}2;hF9l9PxUAL9A927E8>:cXf򐸸D:9  |߫:C:{pVώ:x:Zºw:s;yK8[:7X;0w Z9[;*9٠;ec:[4;s;tϚ;;^];QOݻ'o;m;79 z:-<>! H&<;(>"t[&< ;f 4޻ux;%JEm:\;2Hw|(f:;,"DB9ԯ;8W3;ߘ:4ݻ:;c$;Vv;i;* ע< D;![6޻;c(;e ; <6PԻ3($3;_4<}̨*?r;XH<cOeB%;U<Ⱥ~_X:zyY<:~_XȺUeIq";#::gߣ:[!e̚^:!N:}Mg$5P1:Oth:˻0Ki9/:BGq199ٸP ̹k859KPw5iH9πM7)w$t8֏7 pa8ٕ7ڹr7!67pl76ɀJ'?5i5#*s-9"'g5 |5̢ClH6]86.vGy7#7UԷKwr8 H58aNVPU8m8<m8Z#9 GWT+J9h9vzTS9լ9= 39,:R:~:0UvJ:q:Feպi::l{ԟ:y&;6n>:vX;NMκHt:3N;/:Y;溻;;G ߻b ;W;H\;, 6ny&;ԟ:{l:i:պFeq:vJ:U0~::R,: 39 =լ9TS9vzh9T+J9GW Z#9m8;J7o;v"CdBQA;;:L/;_M:!"cl1;:=5:>q8J]O8.Ƞ:}9( ~9,S:5%?9,R9U9v9eK>"IB99)8C8ַΌ8dI7lFm89ħJc/K5WA7Ķt5`h&623Cx4\ f8X5 3ܑL"e5"7vh!77ƠM8$8N8|g8C18)FxL9%(6k+A8o9 J+sϹwp9e9ù:X:K>Ly&:Z 9"n:l*%9 ;8oUO:F;c'ʃ1;k;@c;ƺ:N8+;&bʻ:];2* ڻč;Y;Sǻ?;ݮ;G><؟2#a@;!<{H ;E;λM;"Ƈ;㻝O1~);:yԻ8n.;]BOe&:;H q7;<;u) *;":&$e9;<9ȷ:[m9hI: `:!!:3jڹs:9/DY9Ds\8`@63k9}BY+YO8q8l3Z F8Oc<88"ѷ+7M7Q rK7R5c׶)"496n_4Pjbv35t=#nn6 6Id8vU7GQ7H\g8$78냸i68Q9Qqy9H8׹[4 :i&M99:2O>9jc:,:v:}_:j;9I9&y;#a^k:;qxR;j:^E=;OtZ:;$jL/OH;M;D˻L^;D:C υ8c<Uݘ;G<}P<;*E5c:J<6:T~7;R<ͱcC :F#r;9K9:@ I=:P*z:Q" N:G993<:P$8/9F#p-9'9(|497TȸFQX8BI3Q77loTO.7o6%жUA6D4܁[ 4fpo5P5{g N@O6e6ZfXa൛7%5ٶCE7F8o[|TI8#8>}P9)/99 zϮ9Y9 *x 8̐Q:Sh..:sb:뢎<~4:y9RwB5u9U;kM.z:a;6Hm.n;h9$T:7#;n;^n;Ĥ_;bV9 s:;·%;í;=<-+9 :(`ζ9NmH9gq9P1A878})q8,E7h?}:8QҲ67\陶[w,6!T5['Ip\55/2571Pxsk77 |N38(6$S88ĸ=98Biae9(aܹs9*l9!yTc:4f=jF9K:L5l):9g]$97);l?;J:Y%q;o\*;_y;>N!#);$:Oܻ:I;K9;\;e<\m;;M%uE<@ 4LK;K4N_y;*;o\q;%YJ:?;l7);$9g]9):5lLK:F9=j4fTc:y!*l9s9aܹ(e9iaB8=9ĸ8S8$(6N38| 7k7xs1P572/5\5p'I JLDT6 o67WO8 x75n87j8S Sy81W70!8{ZO9AG|39={8fn99Q :ӻ칬yN:hI9NS9YG:#[jcj):49l9;0Ⱥ!0;:lԓ9b;`q^q(;9:. 9*;_Oj};:P;6݅8` <q;P;'m @}6<^!sM<::4dK;]K@<;HO"n; <8%ɲr 8:yHAB:y:≺+SƯ:Fyu:&9Gl:;Qt[; !e)[VG;; :I;@VmIcE@;c9I仑;:U;6MPXɲk9_\8b%V8t A9" Rs9ʷz;f87NF6$7*o[{0I775j¶O55N5Ej`6~jI6Q6167`w=y8ރ巷h 84*8|<̢8JJ9yt19As̹߭ :\9Iz9~7:W;v::?m:\9Z;[:P:m1H0Y; 5!(;_8wpJ;ʯU;ú#9Wx;#*ȅk;̮e {;;%u:UI<2Nn@<@]Q[8<;s^2;>Lw<mQXpGwL<2;s^;;&3:D> ;&h;;Ļp:;sջ,湦;ϻߤ=b|eJn<:qg~X:#8:2pK8Y:m8 >S:v ]9:9|z9W68DQ9QVQ_69θZԷ8ʉ"3cַ(83:%{7t%Dն=zx64#f35,؂1%6ִNܶ+7g65鸷-77a$H88M88R879s8y9j98;:F#@@Jfy:N<Vj:4?;n|6|\8;<º7{bo;J9@ؓ;Ɔ6E6;Ry~;D2:6t;Z ;؃;l6~;p/;U;F(7;2<_Xo;a-< b3}:R:j0;l:i>WDΗ:Ʊ`!X:*B(;g;r_;KXq?Ґ;ȝ{Uƌ;Oź};&UG<λ/.<黚]f8< P< !|g<2D|:VT:M)p=; i9,tU;VA ;!)}wN;B'gKx <߻`Ӻc<53 :r 1$&::f:9=}:Լf8CGP@:︛":G)VuU9g5tD/9~Ӹn˓8vJ6Q8S6?(7 .6K5rԵC5h g$N6w˴ݧP7R7d7]lZ:87 Xg9Ta369MSx9ЁŹC%\3:BL#9V:=P1<:<: D:h9u_4;U*Q{;HκL;@7:8;Fڻ&;*[; ;=;+M;5 !2h#S; :s1;"t;jO8̴jg;mTi<:P9h+;7u:Le;@x7e;;':'p;16^l;ؔ: u1<,vAF<;Eb;x<6xB<wMRh5[;]8}L ;+ρ\:qf9f:|mh&:ԔƹD9 59jIj9ֽ]8ѝY8ٸ8at#8Yԛ̥e" 76ض6N4e=53b3]XWI 5'6k5X7ӿو$7s72>G6hs*N7L7-6  6alQ88 'n8t8>*8>59x8 #ŁZb7N9Y9dT9wL9bu7ٹ(>R9):΢9jF64Q: E:Cӑ AA:ԥ:d9,`i9b:5ԃ:e:;KjҺm:;;L^: ?<ߏ9AZ;;0׺xAXwI;u;/T_H^ $:U>;1 ;rc;wL; ϻ;Dh;;J:aʻ؀:;i;)Z;;պe |=9;<# ;Κ[+:<t;??";X<1&ܻJȉ;{$ $_H^;T;/8uXwIA:x;0:AZߏ?<; ;L^;m:j;K9e麭9;:5ԃbܺi,`::dԥ AA::Cӑ9 EQ648F:j9΢)(>R99buwL۹9dT99YNbŁZ9 #9x>5*89>7tn7'8 8alQ  8 7-̶LӷNs*76h72>G6s$و5ӿ6X76k޵' I5]XW53b=pt4[{~{ӻ5oW!6c|V~jy6P7EE6?+p4u6\7{7͜H[T¶2858a?$8;8o 6Q`e͸>8BH495΃8x%U7m9J@9b/ p|799 ޸ +D9.':@`81."9u:H9'jB Ҟ7:po:r$jƺW:BK:KcU)` :;w9 , ?4:m;;S:YLWs-R;1; g'n̺caJ;*; oMP;ܩ;|:X{:;-`;/;lϻ ;}f;e.];T;hތ9_e)V; < C;ջGD:w<;헻&<<[4&{|R;:X<ٿ:m+:R;+(<;P(P(<;+(R+:e8Q`8o ;Ǹ$88a?752T6H[8͜7{\·4u+p7?7EEPjy6V~6c|4oW!{ӻ~5[{54pt?B4QIZ46$ñ5c"(..$3%7l6Dζuy9be77*]x 8D84#`5R8;8L%7-̸08&/9̩a84^+G[8%f9Z%9@ a4!|s6a9I9Qx q鸣e :* :hJwbO*:5^:踓ĉ*9:P:91Ԓ-: : : ɺ N:9;,:T7ֺ| yO7A0;0:zȺ# Sd.4E;8>;Ad$ӺL;z; jV17p?;6};V{ :);D;~:Oڌ:;%5`;o|7y;3;&(ٺ;c;6p-|h;g}5:Œ:f8n !6M9Y:!y9؎s8:a9&zJ~T90u9"њzq}[9<9&#yNkB7/869t9ݸm!PL8^86<_ ,7ځ&827l!·u86>7$g6[w> Gڳx6']60.9`5uO5U\^)O 5n/#]5ۑ'6XlFKBB 6F!7S1ƒ%[!U/{77jߵ(A̷%7="a8 6뎸]HJ88f7Śظ?8?<94)8#^H+C 898s8WP9=9ֹg#9 0:ƨ9JF8w: :u9'$98kf: HZ:6bFɺ&L::<8;5:pq/ٰ!f%;;w]|A;mN;eqVUjպv[;Y;j~Ap;%;;]8QP};;-T`лLR#;;/1:UqF{;<=!:%nʻ[j;<0 ; +yL;`[<`bG;@'-$;y#4M(3W 5Z6C5Gq(l"B6M7U6MS|P=776]v֊7.Y8T7Z_l88Q68>67J¸28639zG7iT/9/9Ƥ7 =p&99s8[`9(:AI! :=n:ʻ^ڏ `:9:1ƺXL:%:I}zs: ;s/x--W;w-;:M[ 7;[S;r$cúf;z;𶺐6TԺa;);amR4O޺;Gk;ݻYb;#;?Clnٺ;Rr;V{gT` _Ⱥ<;#ˮ <;,AlE<;03&C=!<;n )Nɹ3~'<";Tͻ*n*<=;0ػ'm9*Y:*:> =9~&o*::48.t/%V:AX:t 8V5۹E9/:Og6$r 9!]9Yd? *-9dk9\Gø E8&L 9˝L>JPA}8P8>y̷88{oT-﷊0Vrz7ny71=>]&v;6X6nN?6X4g5Og5_Y/5T[ 866B/˼}5?7c618F6U7-7R 7f l8lG7;2lqO8W8x{P6} ﳸ8i 89tk希Wd9f9ѸWWȹz8E99v&:9fW(8~~:- :P\ꎉ9: : ॺ׽-$:{:59pQ̺L:;9|*YٺJ:,@;|P¹aP1Ѻ8;M];Re3G;o;=91| @H;r;WBI9;b;=ϻW:X;H;;xȻ*Ի1;o<:|taλ;F< )'::; _qSY1չI<:g: YC%ٺQMce:?:ú8:%; 4:`:L;Ҟb R:;`;PE%y ;(V;M$;`D9]۷;X$;2Q;;:ӻ(3;H;[ѣK;;dxJ _q9S|C ,c:@U: щ?F9r96H`*9@q9wsW+~B8z9f8,3tf89S7㸾Lvs88V{:/:z8B2==]m::ҹd}h:9VE_G)US9`&:$8+gk99޻jU݁9R$9„*?%86&9Q8bg88%-8+897r뷵6jO7R6;q%6x16D2#l&{5n5x6y 5"ߴC[4 {1695J)^6/7$l"-vc7ۑ7߷17z8{A26,K(B8^8Dil17WJ9Џ8\=|:9/ݞ9N2Թ 9&9Թ'z9C:Q8e`9S:b:O[^6m%7aޕNm7ii7=57Sa^8sp6N&68 8b 9)%91Ty%†89|t7Tjȹ)9>L9ʹj& z9>:׍Ҹαj8%F: :{v>Z:J:)i⺼ 8$; :w:] ;܀'91/5:ĉ\;]i91m=ĺJf;,5;C#;{;˱Tu]|;B;x%z;%t;/3i886SdD6[6Ʀ1*e?55<EFh4Z`6T5pj64?aZ6o.7# ,7u67.׷+8?H8"12O~8<88| g ϷC98 _m-Fh9M9fORGʹU9]: Bx# 6r::~9oDh"w<:mq:f919@:_3=溿?::1fyٺ:;4E? ,:g1a;~t39vM虺B|;j;m5bH;?; 龴El:;i$:lԻU;=ȇ;S;j;؂@v> kn: @»@$o: ;]3:Dj:6ֺɹ0:':BK 60:lU:ȹ{K$9(3:I 8rV!t99i9e{(A99z9Ÿ\m7/@39ă7߱y'Id8GN8izII77P,8Z'67Ew56m`uȽQK;ܽ;LMڻ:;9_G5F6<+;aeý <\Q$<`k3o;:<U9TQL1<49;"Y <;PIbl;;t=;;G*9MBp ::pc^'V99fi 7s958Ngn zL-98H츗)8 8O+A7G8϶Fee76Vi6}6kx=5j5۴9?4uGOy-5*6BF긗6+77P"poL67a~J89d̺8L7P83%m8 Ƹ}C&969k=h`z8M9 Ȝ9PX{ҹZrB9 :b+_8gR:G27zzUi.:%h9P99:Yil:K(:Є:i- :y (;1(HE?b:ah;gCP;8:Q h}x;;^S[;~*;YɡSi;;Y5-IU;s<sz:I;Wy;o<Ȼy&Е;v+W!9]h9Jٯe[K|9eRU9-<18e9i)8\8oد6T[836}﶑7J6e]lJcǶm7 m6x{A5t5= A55#Hb,5`,6_ja627!-RT7s7-9ġ78H+>67W9䠈/H6Bd9b27E>y9z8Jk ˞:[9k"鈡=:94Z v:Hy8E9b2BdHݶ/9䠈7W>6H+87ġ98-7sRT-7!72aʶ6_j6`,,b5#H55TR+~w66Fs7n7ԗ_:ԭ7e7[A68JFY8bz.>+8y8ܸ n9E <94oua9ԝ9>يVȹȨ9;9ʹ9A?:c +hXj$::>V=X:E#:)8tR纮ۈ: ;c:2;'V=:Xj$+h:c :A?:9;ȨV9>ي9ԝaou949E +.8bz8JFY68[A8eȷԭ:7ԗ_7ns6F6w+~5TR54.e^6f6)v)746(jH70tM7>5287ؼ ͺ9Q70ƷLi9z7`%Bf9xRh7e}:l|;8ބb:$t3ے|%9Vx:]^绺Ӑ::*_1]: ;hrwX:<2;v׺]D ;aW;[Ej:8;,|;ZXks_z;%";A攻31;ҏ;ɷ잻?;ѡ;[U;5;[GB~<#; <ĕN)580tMHj7(74ɶ))v66f^5.e5/4~)65)sǶⴵKB70\5ٟt5t8̶ԃDrz78MDm}Z8A8$A 999I/Y;9 t9ҥùQ:Մ9.)x{V:'L9;K[s:{95.9:+˹ 50:;y";ɽ:=*;+Q.3V#;)7;L7 y;0; 2X#i;| ;AŻz&;“:) Fֹs<Vr η:͚<="hm;e<\g>;2#<۫ƚ <;f;5ʺuC);2:Ȃ >6A ;d>9˥t<:JM[9w:y`{yl}9;:M`Cu9oj9lJtv9v4e9T' p098 SpR88ASzm8G56`#C۵h7r>Հ=55 7Vӵ\55&HCV.4km6 YC;6k7eֶ>w6F7 ]϶wo7{7^kJ80859]>8D8.훷زl9O8L89@3f<9:9r9Qz-::>l.`:2q9^:jM? -:;x팺y: ;YJ; ;w| U;@:'ތe;9Dѻ}:;VٻH;Je;4iʻ;`;OMky%<;[4Q= <@#<) %46:Bf98::޶Mݶ:_7㷏P:sZ;~].;H;7$캅m;:Qi iŧ;*}y;~9;A@;A;⻬0YI 7; ;k68;Å;յ";:֫?w9!;*r|8:zC;<g #;h:;o7%89@:u(4>BHK:zL:ǀRetE:.l9l+E =< :ҙ\ҹ;9I9 ,>q;(948{X2*LdE8]7:6Ac8s[ y7=y7QS 7?6'Œh5oh#Y5|64}yx6 7n_6#~5))8f72Q8*JS8蓕 F873O7+j9|x=t9I9˹OSf:872?$9_:?Hi>d:Q:̫ +:8 m:;&Qh{0;ӷ:4S;(d+:T@;Oɕ;F;H ͻ忶k;A*Q;;-˻q;w[;ѝWCغM ;J'9s:(Mb;)ZO#;I:(&b;5I i:% :we{:o :p5x7YU:Ꞹ5%K n9KB95ԙ})u&99h)EQ9D)k8Fɲ8~Ҫ9;[8w7?!h71 [66q+0浍5Y4m(|U5Ek"l;6954$s7ɛF,7&[7Bc8\֣w89cT q9i86ؿ89փڹH99C_~:̅ǎ#C:5:0!:j:8$1B:aY;yM9;:+rt &r8;v޺: Ue;CW;1ݺ;-໹OS;|;BOGϖj<:qط:޼6nk I7GΆ77/ai|8Y÷3ĸλ8C863_9vR9JE&98/N:A4xt]:L@9#9:Uu:.*9+:/:c v[;! 9 e/;s);*;; t;:9;:rx;%h><.;';<#-û4<8:D~;IP")9)m;;U=-Q%<4_Bk;/Ɨ;Ho W;-tC;6;O^':ڜ;/5߫;u;F:kl㵄:a-;.';7.i:v:٨S칼-: Vv:bn:?2ݺ :=役Qؚ9+9bI9jR7V9kȸ߸Y8277g:[8Lꬷ75}.6$6̗L⵵I 6GRm|5XεڏX6l5P6n77&8=2gW;f8>>80J^+70!9aA9t7ÚBT99_N3[s7:OۖD8n/T:989pz:8o_;/^Lnn:::@GFwe; H@;܂;`:;;hC;Իy;op;Q /:B>W;fg8=27&777nP7l寵ڏX5X5|.5yڠn>SI6c{ʶ*X7u65@ͷ:(7V7-Z4Ƨ8>Oi:nJ;_)Nw޻Ж;xju;l:Eϻ͂;:;ͻ>#<XY<;'&;<&F<1*E<:vaj;A<`˨tt;;:굻͂E;ljux;:Жw޻:_)N;nJi>O;g ;Tk:zI: =:y]~Z4:`5DN:}8Er0O9N9i4ܹLf<9h"([P9=7iL<8>8Ƨ-Z8V׷:(@7u6*X{6c6SIn>4yڠ5. q=5/6/ݶ=6`I7:ʉv8 {&~8,"<6,۸β8{8|G:8 q9˹]9T@{ӹ:HY8R::w6Z9:P;Y#Z;dz9(HX;K ;>~#:;7q͋9d;)e;|9:󻊄;; 9=:^-V<%;I[;p+o)8K;Fn:(g.:@˷:H0riv: ' (n:v=T09B0t9@ub|99TMv\Dm9׌ʸFK׸MH9wfVʛP8ƙ75?J7m7LѨbw'7ؒOk6n6(92-g|fx5i^R6~KHf#s7Ƶ ׷Ow7z7NځQ88Kkz79P*p쌸91~g9u :H9EkR :*0:Kd'r9(:ԹY ;t#ƾ9;.);7?L;]3:8ӉC?1;Lm+;XzD:0;#w;6Ӄh6 < U P8*و Xi)"9*A)9HZa96k89- 9bf 9.:~vB9t:o˺A;f庺J29;Aۺo;⡜n~Qy;=;JS;0:(:һ);d; uH;;sy[: < غV3F\`KH<5;::d5O%7Y趶/;7Ny,D(6Ŵ"{UA5}UɇB6s"̶RE7 ݬ@08r\iT8%T) ~9l6d?n9}8Oȹ979|"D99v 999:H9":)99:m 81;RG7(u;tPС;T_XV`|;z}\w6;HCB? ;Dq:M;D Y;ù;zH/̔V<~=2D<»̦(<&߻S<4<7;YѻC9:U;!!v ;; 8;!O:sQEl;<9 f_:) d72:י蹾@Z:v 3: عhBڻ9ɞ'k5P(\9^L86H868]82\7(7)557Ѐ5gYm46d?(d59͵#X5 u6 #fo7֬68 va8~{-JB9Nf釸 m9؅4jQ8Y9F'99`%Y:B9ź:ʹcI#;duP;8$5k;NIg::X;\`Ż~;j;U滬;|:N<0βh7<]><%BfX;B$'<]rt;~;7CK<:Wu<* {л];D6WpsFﶊ7v&8.J,8!+8$9Mi4}j95>6i9I-9 X9^]s:e-=H:ߺ59I:6=} ;8@9RE;$%\;:Kx;@V;7@[B"嶸9j4}9Mi8$9!+J,.8&v67F6Wps5>D5{*!Bseptimbre_amt.cqt.filtfilt.firJn桰r8%"!};i  #<^mB|#DO=/śȽ#á>A.?á>#Ƚ/śDO=|#^mB< #i !};8%"rn*%Bseptimbre_amt.note_branch.kJ>*%Bseptimbre_amt.note_branch.bJ\>*dB2septimbre_amt.note_branch.early_conv.0.conv.weightJd6=rԽR=w >w#>D = Ƚv =([>F>>ߓ>㽩Z5 n(\perlDT/^==0x=jܽ䉾P>>>H->L#>~=4(>{6< 9&9=~T = >>6<<9E >=Ũ컶B#==rM8==n_kVQrշ=>"jӼXP=~@+G{r} \<ܪ>v<6WBwBр[ 2%>?Gv*$(>H=>ěV==g #{$EW= 7>'-=սK#<v=9mH=V=EPE>3u=#,>h%OrXLdý6=?E>Y>u:EvCSG.>q)v>3}>sLy>#)AB1z>Oc>D$TG'#k>mv>$>|(;{?ὥ ?Y*>jh¾=G?{>ڇ=bE?>b>>>eI2~=S>Dǧ=hо]L>H>O">8?p<=T>8U>lo>z̪=< >'v\>?a>H<<c+ DeJ> rZ?>6=&'?#*rݽ)=>T*>V=rϝ>`x ^*=:p]K>MQY$$=5!L>R 9ZeX=>(N=GFG> >YQoȽ&OF ?rpGRDAݻ>L3񼃔>匔>2>5F̸cf >o=]\ ѼVy>;c>M%= gؼ| K=KC=ҍb=vQe>TB> 9&浓Y=K>$?m5кo'>?[2>~XPQs;j3>>σ>"A1xj== =`+>8;a2?*>u*?^Ht /L=BH!Y==E>>Bk~Q==C=ٵ=(μ=5I]kz=$==6=S署zW>2*3=(X%1|<= I >8D0>d=z:=<ʍ sReT>ɽuV=:%P)>Nla!>}=vZ=D5=cֽ3<̽2>(8MeX>qy=P?=!J=W%<VZ>꘡,=Ԉ&B Rj.ZG=*<=uB>>µ(==ra`=Q¡켢pY=g4=J-@,gnj>OK߽`FY`1Խulp?8>bc =#2>jou/,l=EMP#>=.=ȺfʔQktO>N=>=S׿=EF\G!V>,=@s=WI=?>9P4J,0Eh/-hrn(5ӡ(e뼑<܁}K;f8=V?>^>i>>9>>Un>->>a:>'$<dWスr܎@w<:=F8> =ǫst>|>Xl'>O(Scļ.A`5=ԼLQ=*mH=բ ʽqͽl=L"LH:˽ lɽn>᪷{|>} n< =>{|G>kV >=_a>%mc½&^=T>Oȼc>R=G=i>>|?6(=n >> mv ?x=_"dWɞP M~*yξ|w=D>)b>?Ό>1=3=N>I>_# !Eվd=ATD=]u}=AK%; >q>p/>]=5=%>I><>:ˀ ?| >}ݽztB] <57 X>DSQ[=->0=/=*>庽{=X.kOd#$=to~0=*>=Fq{<~w=Eؽ[>l=\4=KMIm5<[ K=IzA= ?)F. >-]'jSD2>8=V>9^=r2>Q*&Ǽl;:C{E/sN-_==6>v4ڽ&\<>[[>a=6>i<>">V:=5 =榳r %(=>{;9Y= Žu|K=_<>c*Ok>8*!><_&>/>ٽ@>~5IGv\>!>x-%[>+.>V Vl4.x> l} tS?m8'=  >?F>h>h~>"(WH>!8r>˽BHPlm>N+L> 4>`e@{=븾w?>'e>/ZX>T⽈<{> 2,LO5b==G=a.;4x@>> *3><Ծs>0 =bzB>>cXEbt>J=;==i$㇍>MH ߱>} U=bþq=al>ǽ7s=T2>>kM>%0= =m=l/p>y>>">[GB>c:&>ŽoZ='aN>> +g>ۛq ^=>2c1=?>M⬾j-=ž&=>=q<ͅL( =Rs*J=A<[>>׈>y>'=ft==N>?ϺDgE4ܾ'OHEk>=5\>}94b(2P<BB>u6> S>2 2#>Կ>\^n>BՋ><ľnVP >29>)(> Mn𽉾%ʫ"uӻO#1=-C}=3|Ԙ=^=$y>; ; <3ս?Wh=ٽ6|?̋AS>Ѻ>U =3}J2>.>ED23>=]0>a轁g=99>.>K>>W1> >w*X=* >*Žb =pz=/>J=T&}=VC=%>F=4*>ŐM= =b=+66la>j%=>޽u>+g;~==ʻ=3>Ȩ/>=ҽ=&<3.OzgnO*ͼ=IeFS \!^y8=Z7[=4O>el>:>:_;m3=-=:2>C> L=~>hH䙾;I;ȍ@C>n=#> >%>6=J>&o>>M= =S==8><;W ?4%===;&L=~1}]IG=贪RF-Ѕ>_>ys=\> +>R=X;`(8W6 8n)罡C=c@ݽn+>Oyk>9> >པ=o=νBsy^=q:/6=,5=<+|=WYĽ8qqнՎY=a >'=U >#>Bx2>iM>pq<NM=z=L>bл>E+5=v w%=$==@L);?%=ۼ@X=OQ;U=9~9F׼/uZeUJR <+=B0!Y@$l~}#BR>51۽<dz|:jX5=7< s:=Vu3Uk88<~K;wL>QT=q=+?=[M= {=Y >Yf>J<|=1{?Dx<[ T9<ƺ=Є;2<'=E=8< ,=V!މ-=h=J==<}he=M<˯==˺=M3I?Mq=W/$a5м =47t!=5->U,=s g*= = 8j=#=Jý4M(;J#=,4=-\t<н/a;=.[=}=򨎽6ދ=a=.5=NX=k =SKOc8 ==„e><3; ѽ?> > i@=m^iM (UNZҦX׾⌑k>e)Vd`V ?Xtv?>=~3HȺ='S>=k=/%_c><5=I=P>Tƽ(>Ŕ`;w~>z>1*TL=k>qOEKY=*i)<ڼCj >"Om^s:~>׽g=*C#>Y=\*?]"?Ё<>v=k=7>仾"h$)Z<5$i= VݽQGýϡ=/'=GлnM>kU>TIJx>*Cϊ>>O(=-h'-]L =]L>_9焾uYP=>Bc>~>^1L=!m1-;>gʥs1vGp( b*==⋾ 7>7)q=oGGx!>"=󁅽v3>ͪę>Pd>#;V=>Nh>X=c⇾=ͽntkV"N>?>@;>>h.>u{ >\b?qoyF<=Yq/>I]>=.=S>Tץ<8 ?A=o%$tT<= >CbF>;= X=1==Q>c-ol| i=%[=;o;>gV =g="=tz>HK;7Ξ >\hu=5=OL=:f%^>V=<6<5=8O=B=^]7$Ν< jڽ?=vCBl%%4=hӽҲ=䆽}=3}<'M >fP<7aYW=(>Tý߼9>ݨ;P9뼷wPm=W0P>z>,Qd>d>f> >p,>{˽CorKWQ :7/*$=ȃ!==|">=j 5=½Zu=t< =e.2= >eN<ѽ!== =<ʹ<* )L1=С)>C>?mDJ4>Ƚ tҽn6\>;[>'Y\=<¨==.= >󡽵ǼK|C`l=r%=Hl8I޽y>Q>-d=̣D>i<$ɼ=y;>j:;b:3Kǟ'>D >rt<= <3FҼ =")fd<57ZS=7'<9f<=p<$I;@D=;ҩ==ǻb=< XԼv~=@$=nk=6=/=d kXw;7m:XM=[>ȣ=剖%!uν6 = <@< =F=ٝp}(;= =f, = frǽ'=j+ķR>09i{VO=R=$ս)=<1mZY~=p4=u=ԃ;zKі=|Ga j;#]:ϫ(R>j>>[Џ==4xg==tc'LSp L=Sý(B \=`$>>li=>C=y=Y w#dL. =:"=6>;NK=NXݥlxc;j;s/=.fa<0;z=ӼF}!>=ArԼ߀ >v7>~ =3NμQ;Oٽ '½Խ=G==/>}=>=g=2< z=ӭNj>ٽͽF;=$pV=C=コAO==X=K )j=`=">=O׻->S>Mɽl 0|d==٢UEƂ.>^=V[=h>d;>∽,di;n,qV¾:tȵ~$Ra彝h>=م> (>T3>02>#=#d=|p=!NJ=<ؽ/>K3kÎ<³=A(=SI:)=XP><[Q*>k޽j>4=:N>qZ>Z >ܧ ?Ծqy> >o>Zv(X/'>F=XrVW{">V)>'Ϛ= =ѽ;=Y=#=-a[>>^(*p=S36ɸ=E>#KzQ=>C>4<$2*q^m=! 㬽_=Z׽=<;S>O=svv<&l?=j=l!Qxd>t8HA=Y #<}= Hˋ-=M >X?}8>#&; U?=A?h\ ==w=.=OK>)ʽDy==:qoV4=7={z>uj꼄[=c3=0%)[ >m} bjꭻgB =Q罆6=_=R8=AAWC<>Η^=Ts<K!Є= wT`$ ˺=il>u=EB=o6 ~Z;>=h>М7:̽{ z^L&=^4&V=ϟ`;JY>w}onim<=f=uU&>9=6>bΑ",>/٦ =5 >;B>L>ܮ->2mn7=Q+$ = >=;DA=GMC>1e:M=>T_2X2DVnf=+]*D'=b~=3SAt>~Y>iT=X=(>m‡=UP= [ܽB泽և=H={n>ïG:eu<=@A >b<9>ˉ=Ynzf̕+t>p6aJH=5|=]5=!=N=P#辶}c>G!>m >?m>??e ?>`[8>=;m %=/Ԥ-^=;mlŽ&.=[8r];l>!=n)᥎b->.J :v%=<=ݻ#>=10MFm.ݽ@G>{̟=)B=͉7=- :`=>F,'=nE\C:>\ֽ>1?;=vD޽ق>=Hνzd=ʽ֦5=>>;,#UI0Mdž>El>u=j|9KM===?W^ؽ=Ƀ>;zp=i%YRM'4=E;7dm=T;6:H=IR"7x)`==(t\j> l8=q@D=MO> />m.^>T>Br>|i> >Nmfs{=~Z0ɾuZG#ϾrkC=ga>10=[o=URz[==?żʘ#[Ž)=Q`ކvW1`!E=ڽX>\XE=PcE>!JVD !>F;=n >Lj1>` 7>=Gi=,\*c nHrj_{cw,n<V<)c0H;?6>_s=<6'ӼHQ= *>߇lx=Z>|@Q=x=a)}5=ye=>v==;>q=_P&~= {=<7)[#-=i%>J?.(>?&<=C=%X+d>bY׽?kq=dU=5ּ<>:>k>#-jX<"=i=/=gd >yE#F=Bͽ(=jGHM{MžV:M"=tؐ=k"kC>n=Q> >2 >0&=Jiv +y==mW==|gEAv>z>5{=vTNH΅`,trgb:>Qt>9\P>X>Ƽ+%>W6 h=+{<+~;i=@;lj?mB=%/SF=>2==냽{K>hsqѼh<Ю=xH8=u]O{ >:>C,Z7>›˖w5r* nuJ羲Rߘ=^=h9,h>f>u>>н#O>A>x>#>>T">5?>Cm&\=>Y%> Yίnֽ>> =>">XI>̮ޡx`V<m.<%;F<ǽh<<2> W-<0ߑwŽ&%>U=x˅>xH=Ikֽ^=#>f~+ )>ɹ* 1o=P>$ >ɽ%L4%>[Q缼 B9>^<[=f>N.=NH3-To]Q4<ɇa=*2n=AnH;&;1t=2:h+mx"6ߌpLֻ`|Rll.dS'ڼv1OM;irP<"⼔s9u6kEʼ̄<ņh{;5>=A<= ;1:=a=݂漍i pٽYc )"!='+ļC˺} |==>=i<=)U<ظ/:b:',Q;%<ܕ;QI(Wu<;ZBՋ=< nE=ɞ=ݜ<<5<80(=k=sƺp@aǻEy<@=zٽ}Y;;:GX<{ېY-ɼ#q;;3Z=(=uw+;IAռ<,<)y=[ &<}cYc5Hr3&'&E#tϱDT>B1~<َ<`ʽήOE ^2^C 18Ļih::!=J =;el<==+4:^@мJżRN<;9|/o%=>W{^>==@eq=@G̽Bp齊%Q;U< XԽ4} 뗼D%㼛E@?)vkہC<:K %`:R}ۼwc=śyy4Խ@'=ݼޯ=6E;{2 rȽ9#K-NXsW;LsX=="Rk<ؽ/i:vQg @l8=j=}2=*='ͽ=T>(<\i3݆h_<<հ=<< =7y9<:=A=s>J;{9=<^ MZ4<`‡;:ܼxQ tI3\e+N j< ,Unb,4Waۼ!6R z;5CXrl=SU==0Tn<ޱ.<@Mv7<hoa23; 7K޽8;`>q{MQR =-x밼7^<ߺdf+iq-;YK=̱]0e ==ۅi=Y%/`Fư^=7T=T<G:K;ݗ,=d<.;ceUx==j=/WLx׽!=)<=N<,?=͓=ig%=V< Q=u z۽xo/Y<<w;<*;>0KjMFm5nj5]14P<9AB}:W=g5<Լ 3;teIp $D{===H\:= =iy=~e=e===Б=<4 =7c=j/=+]S<@=o%==!?)=A==S=TF<{w=ps~=6A;X= V=3!=d0*=B Z$v tt=Hb=q!e4^9<,VZ<<<~TtD<ٽ<<k ٍ p>@<O=N3>WoJ$7 < =%yJP o;<֜<ɼiZ <O#=O@=);Y=߻a5#<+,|Tͽ.C=ߜ</ؕ0!6Ľ>dfՃ3ۈ;k91HN;{G =w;1<̿<3;vaݼWkU;w<Y=^`=r=$=)ºJ=9<==u=fI@=U=<,>41>/5>e=K=}$=BBR=d<9}= :<-<1=9<}0Q =C<X~D<ټ?;;[(P;h(ļdƼ<&9=#/%r5/&=Gp@m;nhl<8| = rμZك; /N`~Zk c/k" ::zWk d;<±H@H<7;=z+(Z B2y#[XS='xң >љܚ=fQ5㺽qW=*=fy=3=;uK=:$Ġ!ѼӣIL'2;S;<S*;<'<1=R=ۖ=>w,Ub:}޽m=T=R=;=tt==a<= f;H< =&+;n=׊=_U==(ν0Uo%];k2;sH:`C=9&>Oi^==< [:=U =Jb ļ"=1|Z$=l ;tBzϻևEjpC=FU=tt=$=og=`< Cn=\do#A=d ><;l=a%I=~q}w*8c1}=.l=1j\GxM-hxeR="SBn;g \ȉQ'3<<===^/a=b 4y;0j={r= != my /a<~=ߝC= &q̻=C==C=[I=a=l::=mH1 \,dEݽ)W)N,<jh<| Y>$v<*~=G=0'Muۼ= T<6=)<"= Z={&=47=1 *UF=d%=x-G ͼ_߼<$y/=̋$=z=^q=3'ּ=%Mn{D;=j<$}mt=  =C6=?=<_k4Iм脱V,==K=p=L7Yu=eJ4'ٽ- ،m==b=Fl2KP?:Jw=Gً==<;̔Kz[T<}~b= )Naz;aʽR=\=ql=/佺VTqC ;90a&='PkzahK3<Ѽ~:'<q)=C+%ڼ*Tʤ >>jͳLڼ ȽiʼeZDҼ<7=}9=ɍ<<ן=t=e*=v==h=Aثe=AvQ>=V=Sa <*üjLar<9Ɩ<ǽ#zh= \L`4Qk#+ F l:&=}>>ezؤ8:e= >j=Oc@>@^^=ِ:`:׍;lT:0u< eaM>;='F P=Ϫ=7=>JJ=4=x=Ȓ>9<-<0ad<%=F ==O-&.i S]$,-O׼̼[<=!6 ӽxd;fG6 V.pg;AKݽLm;;o<=+Ľ<|<$ZncT9<,ItI=֪Sκ*.=1Ժ!2-='P; 4D<=)t ;kͅw=.0f r=,=k9U">цmcʄ<=|+2d*͌iqM/dؽ! sOu/C; )=Q=;~>1-;!;\͆L)=i>GՂ +–<<8=7YV Nφ=:a=_i=E.1> 4>"t:,='+==_;; * _:==O=aPA' (^;=wb?/KD==5Fr7?)<r=l=9><ٽ<ۉ'Yĺ?\ʼ=r5qO$l:==>=>Zg6>K:H4<ă;a$<#=| b__=װk;). :ra-Cɉ߇ ;i<;9J=.B.S tgj;=<6L~<>J=ƒz9ADJ=<<=9i<(=>Y2;EU⏭f)̹`f .Ix%ݽ6|ٽfT$vܽ-S\5 +M[A<,\&/<= {Il3=/=F&wfV%ʼ XjO=e=<ü\ DNg٨; ;! <r[=U <亠h<;:aZ x<)<;5\&!9=|;_)vK;X,Ļ;;t<Ϩ<+<=<<.Ky;}:XbI/;<@<|S: )<ۊ:ǃ;p<Q'^詼5<;f7k<4ej_[\ 8"`l-hǻr8fǼ訡 QWL(=DƉ=>=dG{ȼ%G3*LѼɼ^u:\y4s+mcƽ Ŋ z-x H;c\^a=c= e<ɸ=hDRL ;p=l <<<1=7!=,,3==Zk[/U=kFd4Ħg :d4V/ V|K/ڼ$=-{Jh&{-=@=*pZ< A =ϱ༱&|=R\UlSK=S=_== = <`=4<ʇy86Nn<%Q\z=ĭ!=j=Sx<~c9ᆽZů2Roo;|\N8<)IkͼN>=-<,I=x{Z @==h=c=7FXy*$(мa =~= 1<,=< l<#<؟_1-:>bT[ =<|"E<=[;Fw;i "9px=nu<" =KZ:\<پ>=N=ԓ ^<==uda.Z 34F-qڻu>==׬<ф@a=3Ɏ<=#<=lY K] k<5q<+ Ct4=K<#Ry ;%t<{z8!y=>>k h7qs=;A<0Q;1T=n)u<~<| $qT=/;Kvb=.<+;=/<9J:=XM&< v<<;;ɮ<|=jP='<8Ml%I{<(6` rǡ{ߵӿYw4e"M<] ߨIh [ m"f̼k~6-=pTY<2Q<~"Nhg;ki;K_==wb=Fr=\4""x<3<g7};;缍kۼHe+=lμ^;_M{w% DRЈ/7!{>;=<_8=ΰ6O>=G=*<= N޷<<`w<;=8< <͙\=һ?i<JtTAҼU n1l|<=P ہ;=Z=W=H< _f<=@<[u#J J@c7ڳPGi<_( kF"Uqμ`Tm:v :z\D=\:W`?<;f7<%:*1=|5=k<V7=O ==4=={<#<%<Ю<;Ȼ(KbD<Ӽ.H¼p:;;>4;QF=u<|sdc<S<Ț0ػ<ؤGn;ak]Dp-0R:W=[3>}s=V+_=b_=<*͡#=g7| =Eͼ %0;wdV;# wAaۼS=5[JrZ3u4<TU}0ӼtSּ < M.S |k1c -_muQ$K<)=dG<<<@2a#I&'Uv( = <̤;=OIֻ2T/0ļ;%7En =HL&+'%c<!;]+wfH 'Gۻ;*)=GJ<<_<Ļ*< <#)я;UQyNHRZ; @%T =Q<.:oh=U=D=G=,==xX<:9ĺ` =:={="%=p];3=g%;450y_@wã?*dB*septimbre_amt.note_branch.neck.conv.weightJdO >3C=ܼ=nl=>{G> =>)o>Z>b=<>cb3=mﱽ^ԽN=7  =n =a}=(=ӵ=өܺspij==D"<8=H<{'= =gַ=pU;<'=>>NJ,Z=`A=A =n/*=ͨDS 9WYR=P<̊joV5>z$>*=s6l<<)T20j}ŽPD<糼q=q<$==aObA<;)=-U>=V˽ <<)8\k?=E=p,#<&=Iǃ= sʽt:ݦ׽Y={==_u;}= >G;JKL`=1 =Rq0J2>(e<*:zn:Vczi=r=քBF6>륮ȝ=0 G>)>';<3 Nʻ(+svR9䇦m=>?NR1<_<=l 6'=N6Wp0>i-=k*<^=k="(Qս==>IZ&9J9&<ҽGV l =}{*X<<@;g==y_>ؔC===R>=\=i=A52<6Ӽ|猽k="J =~<սӽ_&)`=J[=ϋ;8-<ߪS!= =P===}f<רYս-=H:>s==Mr<9= >?=k2/K`L|#\wS=:=q=zP="&9ކ;¢> >2<<kc/>'SJ="]=ՁR^B! SXIf;⾍!g=v=>=^=_}=S<@=ߔ7$Z=mm=!ʎ==~s'=*5=;<N>s5>=^;F۽O>-HG"ǓѼA@>,H]v }gb<B=ZHY[oһr=wp=l?=R*~C<8=\=˼Ҽ܊ g=B;,G$T]<$< J=սʽ T`H/К)%`N"]HGtBὉ0ڽ=׽?IoC?4",Sj5={o*}u;".wJں\.78e~<)ﺔc;#;wsGX=g=qnn^8:=-NҼ ::S*._=]l<݊= ;^c(4=8=McE=N Nh=J<%=@>\*[]=B v@2=<ے8><2;eP=fŽ=< =׶{v<)GKS2~缦>=@9m"W!=HmLR&=M=}>&C t6z_2<=c;Wu=1e1 = > ="=k=y=E!F[=3=>=d>p/=qP;ԑ:4==T7\=a=09Cs=PY">ElB=]!h X_7j:Σ&wR]绤==E=5$q3s s4: ]Q>=A=0-PB0<=i=,=u,?;KM>9r=t>a==/:=XS=5<uVƽb;< ܓo)G#Ք2 <K!qy/,ҽmʇu6I9I *Ur=ɚsh<n< [==սQe[6><R<;2ӝ>&505 4S:4=+yZ===xq4P<ۇc < Z Nw=>B<{=ͮ:=Cq><=>f\<ȡ%N[Z<Eؤ넒{=ܯ M=D=X>=tkM׻)@Q_R6=$I=}aM"!=w(>,MeԜ<Ҽ*+-R=7d>0g'a!̻ő&Qc w^lb&< >=H=91Ysu'F=N>܏>+>[̽=2=<=(=OV޾=5=gE >C1:kmy{\=n*>S=Dן=&=>.U=aT =$C>`^䒽@=;;>>ѽOo ; tf>nB>~ Ѽ$>) |G=νf=t@`Xb_^K< =NkIMɽd޼A׼+j>L'=-\>}iHS!o =F=>E༻<_=Wq|D<~Mw~ǽv=5 /B= B=f=̽ҽ $eRi=-=^BVO!> <*spj=>3> 1B>N>n<ā~=Z=9>'G>W=L~ܼ =)=c`0==[r!0>þN4>@u}=LX"= K=eEx'ʽи =a_>{>ׁ$=Q)X==`s,='=^=Ԡ >ɽԗZ<==^;γ$ըwZ5=E=X=}2=&>:/:qm=tl#.Nf==Xo{=+L4ok=&Z=l=0P =8Ë_߼CK >ޖuD/<FX2L>\>>6]pjb=4*z==^ne+b=D2Jq#<6 ߩ,=o=;DWXFF=H;!==ƨNw~=z<&6I=*H=(3>.=#=% >$=@ȣfv56jųʂ>w=q=Y=) ߓa@L=J =JQM(=䳙`==">>}>K=w;Nu=-*)S9=cb= ==Q#= !>e;K*Ro3_j< 819<==p&O=w=ۻֻ(V>C=Q>"Z>LZ>;>S=8[>͘K2r:d<l ̀>F=0Ϣ3*k = 0_=&~x=#=\E)=M=Ӷ=esҽM/,6HԽq=Е/: +H>Q>zܽ=F.UҼc&>:jѽ;-F>K>)=%=cfn9>V>½Ug>@b>XL<4=+=,]Va+e=4>o<s0ďE=49I}ѽ*2<<km<И'<=P={=*>򺷡u40k7v6{W=`۲ܽI=ҽƁq =v<= <ݬ|j=;o:uY >J =x^g;!ʸӽ]&nNJ\D>Z]齲5"=|d>v=1|>e42 ;$=aᆣ=S(ˤ>PU>P<ۿ=G;Nl_-•=~>;a5\s<6= >=ϧ#w~)=1м9=Z&I='m(>K]\>g^<0>E<Ʌ;# V7 k="W>?u>@{=wF#<Ͻ=+ pGL>p5w=y[>Ƞf;?<?n|<W=&,ݼE'O>$>5gw>#>>y=4R>lV>W>#=WJ=eƽ'y,’=z#>2|=!>_>q#:m罰:6=ӼCA@Dz;Y)BGL>ES=ج@lj2="= >>gB n>E=> 4N=I=♭<_=9'z= =h{f>x=>+>I0_O>H=𳓽ہ=j;>9ʽ<Ğ29Ngo=V=OJ>&ӽ`^ftg|=ɝU>%="6r=D2|=Ah;&//IkZ>=JbD=qK>cho=җJ=,m|;>WؽM};3p~=ݽHhΕ=HpqR=H=e`>=%=ۜ>0<>tMU:Wm=+h; =>3={2m/ >zd=D)>[>(TA >N-꺛H=9dqa=߽bϕ=5s=[Ž &̸H"=N\=N;H ɽ= y{ȼ4=*>܂$ X#>7:;B=G׼=#k:l>q="|;f沽GC0M =_E =SB=l0>/}񎙽(&>kg==q=>YfaK>̰>]1>nL㨤1>7>)"?:꾪U2>>X(= $:h:#v/pg>"_<^>;0qqIyo>Q7lMAP?>;<1=F)>=Vsd5+Îڽ#>i*33f==Nn=Eq=>FO$;> =>?UQWu>'>u5'!b==j?>>>4>y6NK=0^/k`<x$j>YAYԽEt Εӽ >">$=>k>ӕvɑ;L>lѾ|e=ü>`v<x>'֔N=S>" SJd>ٱΚYj<$kq墽>l*<Ƒ>R"]bUP=F۽FzD={S">N >/`Q->==y@=;> `= +=jC=>>D=:>EXa`= /[%sj0>`>#bU21h~>L1?>"=e0>w۽޾RN>>3=ž9Ű>#Qe>ǽmC㽾!u=G) ">dYHzWUk;v>S>!J>-;c>=;;=;%>=;QvPm",>瓡<[=clWĽY&,=Y'm7ޟ 7i=, ~Z)i;vmֲ=5k>oJ=V 뽬=iv4oW=;t99=]Ttf߽f;vG=rt<ŽڳI =(=c=/Q>4@Xvս{lZ +א>!==r=Pl=M=e==HDn<:IGy;<c3&>8W❠=|H > ]= T>>wD6O<=;HD=H=~ ΤJV?|<Ɇ<Daa8Gngq>i<7<㒐6X.>zY>g;O0?;)D߽}1n=//!U%>/>3rx[ZͶF<ڬ=\Z]< =o̽SiU<':>ػ =ҽcuљzcG蠄;s=I{=6=C9<=(?d=Y;i<8=7m"P= >.oθ J=A>"};Y/Pݼ<'= t>>)=]* (=|F(H>66J=g=K ];T >\>e$>o.>E,Y==$ڼŀ=6."Y9=>5=E=+f G 'V=;h]?>Cg>H^߸=Y~V6s~{1=> սQ=* @">=nh`>oŽA=t< o%uOTru:W;ul8mϕ=H̓=7(=Ml=(d=BLXg>-<=?iR=}G*1I=\% .=в.*=OE=z8aЎ=۽M$ӽ,y-=\;͗teUнW=88=1K=B5=28>1=q;HϬ<槕===es=a>ip8=YV=;=t:M֢PGM>6Z>U=H<;* B*septimbre_amt.note_branch.conv_yn.0.weightJ rȽn0< }-V<:U<b= 3RuF`伏3J =*=xV=6=e=:в<:* =+z#N<`2el47ƭșf2<A*c =,r=Y<=F›=U= =`\⼂f'û/67Y>Q"k==".mGQy 6CZq堽;}?;#;2ŰOX `B5aq~<2 eI<=E/>p=<=H]=U;ʹ ŒȽ,=&<&<~>`O< @0<DA <t{q7<'b>BK;CR-=;>jJ0S6h;0 >f%ռqU>[vĿV>֛* D> P lA>0\g=iK>W&==\2B87ѳ>Oqx(ڐ> =n0@4=@>Zn=wb>$D <0=P=4=s D<<=qZ<е=܅g$=xCg > Z<>I<"=d sv=Qϼ>9=p5j>uh<Rѽl=I>5Q=ڛ=j$=|Q='=葷=A \4ӟ]&-=N:mṇeNWI>ׇ]<4=ӻkdR =`Ja` m!="3H=QJ=\׀=3^=i``>pF`=">.dq7/B3{4T.(B=n'O=>;&= =r<9l=.n=oS =U=n.BݽK=C:>k<= >膽BUL=&-=D<}(>9sŽ=<=8]Q<]Y="lB y(s'#%4 <\=ol<fY z=8%н<4g<̫=`=t>ǵ<>mTI=b=T<2m=~>=G&<ǘмV >`u=;"=B "r =B޽HR3=o懺.0Z=*Z=>=6M#|r=+㳽=C`0=}M<>IG=NY>:͖>{5rz}-H=*o=1==M[u=7f<)ͽˈN?ԽPא=e=d8nQ=U=s_8`&Q}=)Ż`{'=9=_=: =Z8Y=6̽C=.ě<2>̇Hﺽ) =l O`-=G=5uG߻!4:aC=b;׸ɽ= c֏<}<= =v+'<'Y=>P> =;9=feA;6|%;sX}>4 < zI^,;rCʽjK9<9ĽI½==<3 > 9 o=LX-= }6b<=N20O ==A!=c<< D<=f{bM<=Ҡ1;;=X<e=*SIM;*ܚfu"=R◽%>I, .1=< D=ýbmFS=|*w@;u&ܽI=+=89ܽ<a>m6u(> P=3>#{=![; ~==kF~Q=RK=bK> :UY6cн3 [g3=4F{ս/==Ҿ< 舼Lq =y}=\E={'JRo1<ཽ=oɽ.x=4S4N<@N=7潏BZ(=8ؽ~ӽ 62˽! ] =? :=(=8c>^knp;ɽ*\"GN-߆<'lwB<=IM,=~3彇0=C<=Ivv+9=x@xPLS#=!=qr"Ҽ:=' Ҋ=^1<=o<]ق=Z<=ýu)2=CdvJ=Ay=2\=d(;㈽)iϊ>'l Ѵ&Cc&6,%落NOq3^=#9yȽ=,6=m-J;<>"Z/;s7=gNZu%qXz :8=X.=UP=ʦo='=;4<x<->hb0=/3;I=*6 <=K5U~V8=Ѳ=y;ld%@=aG<ҍ=L0%ɽX>=7J<>R);]=Cc=, =b'L q==g_oLSO~<` =p=hK5:k>;g<Kr[b߼(R8<)DhE=|קQмlݽ1e9?&bżŴ=T.=i4=Xv>#ޜ<<%I=I<񼮍^46;N<#e< AZ tz>^2xܓ=ڇX4=*AkٿU=/IR<q;񎼥go= npHc #R /Й==Us0{R;y=(@>ȼT$< >nѽv7+ > pt&}^=㭉Q= t=T8g<V)<`FMfgԼ=B1;B'g C:ոҸcϤ5<}c =u^zÍLҼI@=*L΂m<(B-3j<<\񷼬uE=f#6v~<q;P__㼼@$ Y={ ۜ:WEM=OHl)99xP=ss-3;6=8*=3gEuw;ZB=鼭t=;F pj:晽@g7;ԙɽ驼ׁ%-"r<*=n`<+;g ѫI@|=h =tFN =}5->I4Z=0;Dκf=Dq=0=Wh<νQJ?'>vŃ=[>=@hxʙ=[=c=P>c 4=(_<Y=©<=3=K:'<cse=_C=l6<Ք<,$5F<`x[~K= Pӻ4;9=U|k=hLՖ=y7闗MSw7=m<=WLX<%]>{<9W>' j|]YƻodTQw0z>"vҼgǮ;𤻽>j<8#{H<a1>=#7½k뽖~Xһ:)=p~='=>=  >JK<=+).Qp>o=7y=3=5n=x+>q;]K;EV}݆GMۘA(༨ >}<'N$EL9⽲(H󱽼Obe\YE=5V@;2oV\Dz#<齑<B<:;=Co9]=%4·,lwζ8sI/|;7=:.YC=<ļZ@1P-<*CGS35Pۼ/>r=n<`=42=` =pJwt=]ic=*=.u=DsΫ>=> "Ep-JQ{ֻ"l:%nܾ-8뮼>_8=~=r'8:?m˼U; <<)=$=;=Z7*=G;ZEֺ<(aɼ6=1;/5h !=l̘p=>=F >%=Q1>mn;!=Qv=m(Qz <<9=m< =[Kz=B`Խ(Z D)̽踼#㸽+[i𼒮o'$ľE>!jvc\TMĸ=~ O[e2f jZX;*!Bseptimbre_amt.encoder.bJzs?*dB)septimbre_amt.encoder.early_conv.0.weightJd6_=bd=x\N=wڼa+=SǺs<S<^gc=`pv=gO _Y~<3:Ga)?y7^2:zX=j);>:Q=oi=YJ=W<+=m{|0K[@E=<cx2j[<<ǚQHbV>.o<} cOѻ\J<%Zve=j>==7d=8U=l?;===>)=ljn=˯==d=}= D=p`=$=*!>kl=d&>V֡1<4=nE[c~==ei=!o@=χ9UKB vW=bqA:= 6dVӬ_=R=ɡ0tQXSFW:v꼋}<ȼU=J+9<[(׊)<'t>;>z@>rJ9>n<6N~̂Fs=RO=FO}dڜٮ9E5=WνD8db{ ̽B<#=v zG*<<=->D<*c<#=lܼ"<=5f̩^&N^=v$j9%Y<3[<䏼$tXb`w <$|<<K=ʏ[=68k~Z Q=>\= =c=wѼǙ=L]U.=6lta76=9=c<= !<= /G{:`2$"=0=B=M=9&<<<K=B<1qN<*6D`Ͻ4BA޽߽v$U}T===< =v?) m=ۢ=<7yiAg>r}=!=h=@>k_>]GzF{.f.V @bͪҏIӴνlսҫ=^X }+E=lvv~q6 ==&;;Qf`m=JU+==Y=}Ex;x2ȅ;ZCvt5=؍=GWdUSA;|<%ay=<A4O.[=f2I#$ ="^f>Ȯw>k>>1R=CN=;y:t=]4>="f<6Q=$ ==B=+3IYUgOd;+\c Ъ =(i=x;OPy74,=K=g ;\XJɼϼ稽[˽&u4?(=K<;=y^8½0aWl2Q>GT<$>{<&m7>t$=\k=d>SiHg=5<;T=D< <0*= 4Qۼâ5֓/<.I=c&}3=9dZb|O-==S<$=Li= x={-|"V<NsIk;)=V?=m!=D B_ϸ;=ii=W; =bu =(T=Yo0<A=aT<%^<2=)út~= 쥼~< g⽃r{5fGHa::̮s=Ӳ|% I\4u%<`<[=֕=,>='|=,=In=T缣lM3ǽ<:v@r"`>wG>J2$>e^>T>J=;=\\=5c=/D=ywԇ2v0!Lʭ87+Q7Ͻ%^>ȹ<=xR====i$Uq=-\]Kf;%.T=i2<69=WB겆?#>@r 4;:Bv=jG6<3N=E=ov# Ҽ:p==ŤUf",4)u!>Fe>=2`;U՝ :Zo=HdtHi=egB>g>>Qm>rZ> ݽ,3è5P=}M*<Gh=˺H?==j>>)#a<[=mQ77喽E?cI;XKs?;\Q<ρ#=+wT;K烼r=![=N5=38 4ѻ=KJ;/=C;=Ү)< >*oB'septimbre_amt.encoder.early_conv.0.biasJ@gaDm>PS>(;'=ҙ=j.z;f*>d>=ŮY=KT[Z=*B)septimbre_amt.encoder.early_conv.3.weightJ{I=|<<C;+#==ra=Q=X==vK+=ԼaTQd{& tu |Ҽ~:%< y <{*אi'+gu (@wbn^n{8%.߉uޫ.<s|=P==oV WP<=w<ged)79<; ӹ׺:RC N;L<=UV:꽋I>'8=nt=q=Sզ/= 6= Jd<5KTp|1;Ov?X#⩱K7νiА?c$[M 0;mش,J)ũ٧f_;འgǽ~ά<t=|=ǹ*q;6=Ǧ*= _naw=-XNkp1=?3eLoһws;7=I=G;yV= ==̷==M=:a=%p=k=GZ =o;*$;#9v#';q<䇺;+f:!*`@¼Lkwifdc׼&΄ݾ v$@Q}D)_=p=z'=s=\==l={>mb=tT=<5F=8'jQ=` >lj=ni=3=o!=Zû`g:1={=:4;,`O>=+> >b=vh%""ۈ<=D<$<ϵ;f<<<-=7⻼w<9<,=/R=Wμ]v;HA+=^vFf;A/8=D=<_$={=C<{=e[v<<"8M=;=cݮ=Enʼ/;;A=05 ĉޠ=`?;k3;< i==.=r?:r<4-lmmu;;vp<N-<;ڹx=F׀&>*:=H<<鞬;S=L=D9A==&= tϽ?Ťs؊W+s; <==Gμj<==U%Uc`advb<5<4T5="=Je= Ĺ<-j"O ^+M;$<{+='$=JK=*&=Q;"=7=:bw4X=kS=l===Y=H>\=3=*= =Z==IټB<*2 = <9 ݼF?׼s3 k=S= 7= =4=&\=`ň:1*<<ڼ`=ѐ=7u=<^;$=Og><3a<3L=\=B< 5= g=BGX=\;ż;K<= =@+[ph'=i$=U=aw^C`<=ʹ< A=K?撽ؽN 2;$h=-=mۉS<k=<U|u/;rCS$6/F"DUh;ӻe($R<|wP; C<;Z]FU#W[=ґ=@d=B!=b=H}*ܰ x޼A! o5(Ck=J;޴<=^<8=x<8D=ZK=]k~=5=C<{ =bc=Hs>-a=G2==<%=)9$-HH9) =49='=M< ^=U=ѽ=M7]=s== >Z>G>e=T<=/=[|=V=P=a- *E)넽:`*켿Y Ἲ *SoҏAv,bDʁ|B+ k=]^iϽDjc3xq-?1.f}g;mr躪<̞;c)=mu<8=g;K=`c=b9<<<#Trݺ=2"f!gXNAFω#xҽYYлc pyr=ϳ8="o=Ō<*ռyl H4;f<<"=i=u<=E=R=9=,=L>=+=&ʈ;ڒ7eo8+lἝF6텤4v < :=<< 㔼=)5zt涼<μDf=-ҼAe=Gy=HQ=yۉ.O====2=E=H#.VTC7{=8=W=2=*==7м?k<02 <2ܻQKM=`^<'k5] $|<ՉON=m;Q}=1o=l<2;8;+=k2<^N=%^=㚼m<=gE=|=z?=Paq<*=x= I;Gӻ5M=<63-=h <;=x,}Q=A;< =$=b=Ŕ= >DAP>'#=dh,k; =)+6v _eԼjzE=zz < aa`j<$຺*=6=@>7o=&=>`X3a<U^:0k3f/1p;7Woڛ׼/ټY6.Lml<7<<`ǝ=r=<' >=UC>=1s==z%=>=eE=*==ؼ>x=a==g=X=F=Q= lW=r=P<;z;uEh>ia>>==>O:=t=f'E=W==<-ֻLx=^F=9[=IP=N:=a>=O?=a=l h=ܚ=(==g=B(=ALu==_~=$%<<|߇<:ݶ=>==?<;]=D/=.=Jĭ<:b=r=Y=w<JJP(%<]}>ȕ=m(=ʪ*=aЧ=c=6=w=Y='=o;<3i<I ѽДԑyi<;h5&<ٝ=(tfkt ו='=x=;I;'什l4'߼A+<;ED;Ik]Dy8AIƽ4T(OIJ<1Pϼj ;]FW];t=.T=r6Y=<=9QQ]U<ƽ< =ׅ<ݽWī=@7=:=Lۂ;Bn=!׽3WCZDm=c=f=,N=Q<T=Is";A<@<($=ۂغq=½Uɽ<+6 uA5j,<ܰ Ύr];<ʉ=7a?yH"IB {?>*;I<W?0;=,;<f;==X=i ټsCAd\ 5sfiG刽%= s==m<\:Ji¼Wl7~ =1W=M7`LY(fѤN3^fM#?=wؼ<爵K<׼=7ITD,((iͽ*%CݶGi$ ˼D=ߎ\=_M='!Pi=a,<\=L =Et4]!?= ؊ᗼzd<1z<<]N]a("օ"t̽9z ~;,\=r=-= =Z7=Sk=#; =B)7=x=EUź ѕ\(<;f;n/<<奼[k9=&Wr<===Yͼ(]<< ɼ,-;Hu;cJ=={;h<,5[;==e,=Ku=CNo<-sq '<;i<yD==}L=CN='sR=:<<>(]=Z<{,䪘!VS!m |:Ev}}[" != =:q===)B= =@="˼=ýLo}ƽd<)@=5>~=R[=.=<~"=φ=T=; <<" =`=< <|l=GI=@VYM;=F"'X< :.F&D=D.== <2 m==D>={=;rswv~K=e3UkgU=ٺV=ڹ=u;8 =V̻xI3Yl!ļ7)<|:|?cں;N<=n(=^A;#=<[:X<<G=b=8 = <@=%ĻM cD{&Z<< <=̷=l==_n<4=mX:heb; ,r/!8:=~&~Y? <\=:,Y<<8<ҋ<̋;֭J=MA<)a =l=ܕ=i;t;> =="={M4==7,=HB =|=!O6mB<[=~/?=v=Y.=<Y;;4ۘ=K=ŅY >.>y=ݛ=}==%=('=3 =dQc=.>$¢=T=M=\}=l==ڑ=I?=E=DD=6xd{MTc =<6Y2XYB=> M콏ǽƽhֻJ:}㦽 )/:g<+F" =X;=HKoW)@A;y<[ L=1;,<{9=[ӱ<<%<5Իk=LO= >:>dqۋXA ټݨ;?|=m;*ͽW^Ym<Լ =2)=͡^=`=&L< ̎<#=:G;= =gdwۻDK=xF~9#r=[ý޻tx/n)}齣elQ *̃₽9&;3a<#4=T=8ѧ< E<"I834 :1K=*=х~DaS<+=<<J'=P=z=i-2=Օ]=kd=S=:=O= =*k=D<,O=}Aq^iSm^b6't=4<󼖼 u<º 83<]oۼ%&m <%`=U=b>0~?=fE=`= w=v<)=[a<"<}uj><<1=<j=<=ɬ_p/ /u=x=פ=J<=F4H >{|=V;?ϸ=3=סaμ TbK===H< Lr뽾*#=};X<. ]ܸӻT8<°=T<=<\<ӆVꆼtM)4DO<;598 UlD<,;Ȅ姺*<nj 㼉)<<;=(ڬ=䌦=q6=VN=U=[+ =3=ze=)=ͳ=d=.=yp=@^=^=U=Kص=`=ł== =P_J=V=hA=Ű==a\=Q=< K<<4"ӄ==Eb=M.3<˨H[IwE==!B= =L=\=yh=zA=D=p^=o~$*==ic=5==ei4:=|۽==kN=7=z=%>=E~=\ <ּ_ru輗ڗ$9=w/]AG{e:|y9ӽ;Ud%=/=n㽵 d6=j Uܕ<=|m=]w^ѼPY4`{n=::=K_=Q=?g>^-a / <F%=@8;=4V;Fm;5=8Vf_# $:J ê$=z<<=`p!W5ĽDq!;]4q)m):1ٽ:<EPnC Zzկս(I8 V fx7n˼;;"<, =P<1<[=[;GڻZ[=-oI=cD'=)$>_=>{==>x+eZ[j;#ٽĴ܃&Dμ\I\ 0leEYLLŽ4M !IX%:zayCD<0W=F<;vy/D2.;?ڻ)޼#[6ɼnVa94HVV]3H(ʼ<҆;ܚ1'PY؂WU=n2Q>>=={=>=5=Sd=<3X===}X=r=F߻=ս bi޼Ž=^ 3^"-2ɽ>pĽ_齦Y彩_*OY*IX5髽(_ݽ+/<e3Pؖ;f;"/=8>;"ĻL|;򝼼9 3 qvrPܬ<=irh1՘Z=9gDBu Ta:5F=,=]=H鼲%sA w}սR趽Գ =&X=V=a=;lz=1I=m5;m ;B=p=<%[;<=JU;Nܼ,<Դ==|=ڜ< Z;3 =38<<*A<7;'#V(mHڻĚ?M=*OB'septimbre_amt.encoder.early_conv.3.biasJ 2 =x(=IJ⃼ط=t=Hȫ)nY9Q$XR=nM=v;iX&<=ZCa2>=5DH^;I<-U=1"<֜١/<9ˆ<}1<E8=t@Qyo;=DJ|Q^;:=av/A[=o = m;{F--O > U=+>J> -=lQeڱ~2;ۄoA=4k=A=m={<=m'ƺv<0= 6R=D>=Heue);r= ߼ƚHAӼ=Fk3ݽ>Yj(& ( ==#:#T?=>f==zJ;i =<`V=Xh =ܼh=[м j2]^:z!=M =e&OP:2޼v;M73!Y<;h:wZB7GüVüӗ޼͏==17=܀<]K=O,==Fy%=Qeżh9Ade:2 h<#berC+4^PM=x@w^ddU=>;יj<"]=!<ޠ=i.9=GZ)b<[==|;8=ӚNg*G)cVs^ѽ;7=I<<:=D K= x|=_=(<0BHo =Sx p=ܪCF= <ɼȃkrSy 5V|gq=]= < T= }鬿<3iEH=Ķ =Z+мM <;_N Op#"ݯɳ=Ҧ;w27p=C6<)Z>Y8=;X1=aEo<@< jC>Û<7;(;񰁽H& F;t;g,;/c ;v==괯<3[T<蝹สm+<~<\ h]W O uIӯKkZc!9,< Q<=20*$/=q#=;=Ĉ< <<o<S;5=  =Pbh^vNp|A<-/<= } jϼP<':=:5=M1.<Ė<툤; -B=D>=7 %=H%= ͼ{8== * =W*=ptM4f=Flœ۟=I ;f5rUM<<fE҇=L`Z k<8=~wX=s솽f7 <62; S:pk"P|=G=D{=}i<>6 1=|:==!=˽3Ѽv=x%f<gܜ; +q<qLټv ;=7==3̸=4Mp<̨_=Y=h]=Y=꼳k='$Qy="f&+c9!<47;Uk(^m `@b=r!=v=n7=hK<s;wQ` !M=!=䟼I(;<9<5EgXo?/=w=>_=PLq;THs<_` LW RYdFB׽#=oO\<^==!>iԻ3B++'=bJa]=${=+0W`=ׅH1 U10>N=:6L?Q3\ܼM*}%3@=(l=6<_>ݲ=u&[=>~;7%pz=e JO@e9 KO#Qʴ=/=Ɛk=U==]$[:ۼQg 8x,SZ(7׼ʹa=_g=ك=s/= =srS=s<;'2<ޘpՅ !="FB2?=.yqH=}#"@mѻ;aI=.z ='ļU< :FG>#=5lR=Dvc齡aM==-|j<1Cj;d4E={1='ZvB< `D= 9DXϺ =U߁ 鼼; =NO!>8+=c`LXyG<'<_<;뮢<D4`eF=`e><ι7*Z+=q\<@Pr9㼤ٽ =Hq._k_!(=<8qs<+c;!Nu=c림< )ǃD |]=ޙ=SF*lB#septimbre_amt.encoder.res1.1.weightJl}p=%i<=pщ'$Ǽ=KQ<מʻ4ju2Ÿ9t>c=i; =F[<߸<{=K*<=q>õ(;<=)28=(P5<{y== B лg>;B[3>=DSw>2`KE =U{<=i=hl!.V<q7=z;6$%u1<w^=FM>}5<0HzTb[S=$=U>(M >x=].>?&=m<^N==S>=j$>#E=_<$3=f= ܼH=WIXq=};; %u;<\;N=Q<6> =Q<y='< kżmǹ;b"L 8:Uؽ+^}~{;֢=Bz=<:L=X vr`==?󼃪b AEC=:=-w==[=Vb=S3<-q==R.W==}==t=u޻7)K<(;<]6Ms#OZ”=#=A=% =1P>"<}U>5@0=Y/=u:(!"*o=ʛX{2A*=Zي]_#=!=!ٳs=aϧ=@S=g=|M<07==ad<챏;]=K@m=mh==9=\V;kֽ5=Rt<==h=Z'Y=8==<6i/i4<"da~ =\=E~ύ=9*='I=׉=Z$>AD2vB큼*{?Q =G'<=V=.'0=<8j=q0QV2=='=7VpR===>7h= t<'=YY2g=J=m<=S=q< _Q:Bȼ;=@z==\=ݡl=V= 5=ze=:=fȼظk=ղhyr3=G=`;T=w$=zɻdn;żp=^=tA4"a=e%<Ɣ='u=HMf@{9< '=T̽VռԒ9MDQ&c'2=,iнOm=`Aj<=q==rY]>KB~W]M?q==~lወ<2 =q=[r;2ڏ;q=)=Q!f< -b=1=ql[Ѽ";S=1LƼ<[z<#Am<= fC=->Y=+=L=i;W@\=ʽѽxx/0<=Eڽ=v=a7>)0z=Gt==Ѻ==oh<%f=rQ*J'=2=848=m=VX.n<*<+m֙=<=/婼k\==oU= =%=U=5aO$""=0=1DA#=<[擼8E==}aQ Z O =3<̽+:=̖!>6YM=q >T~/a=s;*㼶W=Ox=u׀< = (= 1%=5==7a=&L=M><9p~=aӥ"=%=Qd=7;g 0:۽%:佮OWwq:!L"=ۼq P7X= B^)ĉۼ;8߽½pG:7ˋ9OymgVn3===`=~<$ t=9;#b=qf;<=ș~w=.u=Ϥ==oºRIL;SJnd&?G=EV;Aû,`1Լ)7efl=&&"qZt"Pת)Rxj\=e =^<<@/yU`H{?=(7<;œ=P==7=6=@{K=z=S{;2+6=ϼ`=:<և=Ƶs=!g=T༯48==WB/<-x'/I>RV== <1g<<Ѽ<_,=@I;?=enl=(9=:}<٭<);E9f^=7⎽bR˱9FQ7@5 Wt9q>=2h@,=0 =$<K<>=[A^~<:=V9}t=j=h<=r?>|= =$Y;Z<:`W<4<ƸzQC/Oc==㎸<&'= 7ꬣi2;A(&== =Ĵ=zA=j=\n<ȝ<ĽV ='{<= v=Bq}<8Rg=C=iy"kt3 >E&F# )/<"mއ!>(;FƎ=;[<=5 >4=!<)%4X A=л{=%EźM]u`HiOcv;9=:vZ=3<=z;2=sU_==cnCac=Rc5xt=pK<@/=FA=Pʼ;tohW P3$=<<l;)A_Wd<= V0=p!KqmǺx<04b2:"L===J< jü^.ӻ}=P+Ff<>6ԟx=ǃ=q_=zx&8 l.=- A؟>Q罯мP0Dvp;=.\:gkskl;H=xT)=2`ͣ==S=»<D0[2ep<%UŽ?9 <0==U1BDzWz<<5=#(.Y#==AL=+P===(=ZZDEc ёBw=V̽O>#CqB#=a\hF;<@V<ɈZoK=&] j=G=u6:=~4c'=<ŖV=O< <^=y7/j <\M=L=(`=y=sY{<:==6; <;t+8ܻcV~ԁ;= ;6b= ywv=0m==>=N=D= ;Lp;>- =w< J51z=̼ ,<NI=~N H==o> =מ=}<8 =>=jǬ-Bȼ}弟̪ۧ<=< =[<=%4s7=9p=9=<)Y=?=9==E;?=08=A1= ộ){<ц!q3c<Ѩֽ?m?e"Qob߽눽G͢|$꨽r0=ÑZS 71=_<@ٽ\;S .ؽ`@=m<<^=6;Q/DbIc{8T,=ʻ8/[}==ai==Bք7=e1 =)]=~>L&'5=`yu滵&޽³W׼ =;R<5m>W =g;3-="=={κ ? =͞׽;E>ӯ=Ό=ہ<B>@=,;se=g-V=3 -wɽ;D;-n(:_<<%N=Ϥ=<ݼO<:@$& RX6P)=<g<,==p;=_dqi, d= qLcqLnʼ-<=z=. =*B!septimbre_amt.encoder.res1.1.biasJ`.1^>%<,( >xýX=BzkQ=T+:d=hؿdż]-μ? =]?@O<@E41*lB#septimbre_amt.encoder.res1.3.weightJly)=^='D==;&;Rl< >O3K蜹D3H5>S>V<%k,C,K;`ZF=5=n=*nH2;<ؼ}Fy'iJc6ۉ=qּ(= K=j =vY=;#T=߹==f >%Ȼ=ʼ i= ==O<<<+m9=먽;P=QZe<[ K=żrN< w) ==qH2I[L=F( 1|]i=4q=ڼQ<컻P2&=(F=t;yFq=%E=;c{ X88ۻ/=5=d8!O=Cv=Kјt<5=4{;܌¼k.c*::\"7< ==@= CI. ;G;œw*6`<𐼶B=j<{P=Z"<<^ ļip=% cy=<^PEer%<{CMåL@nZs;=<27o=9(=p|<} @Eѽ>wO =&=ҽb4k;Xy/<$<+i=}U==mh=WͻO=~="üX=-^=/N=85Ժws==~OMM*Y4=Fz(M?5FN$`<5[==)ƅ=H~=Q=f[==$=u=L6X= =oOq====>>N==> =M>=! >QPy=[=2m=@VۼF3(<9F짽v?<#;w޼ڸ|DMn̄wt^<q:H=g<ڸ}=r=3=Fw:ɼx=i=~=;/)=Ńೠ<=)+==zA:j$M̼B.WB:Ѫ9;:=~軋=udg=D/qL.0=%=z#eżAN=-Za)/(=ʚv==#==A9=>2R=[g,=9CtEu[[Z躼)J=Ⱥ%V={=^=[)=)8="=7̇2='R0vfH.U^;օ[ʺ o=g Hl M`I6ǻ4coA=tǗ+=Kі c9ڽ.{靽u/;%o$9m=9>o=='Ar0ȽYfH =ּ҈=P=a<4= =9z.=:d:S@P 6 x8 6M%=(=1%<6u=f Q}9*#Kļ*<;5 }Zh>#=߷=$I=#==ɑ=wjV=2==[±5]#׽-[=s=o;U=S:<1Q:G=s=>J -=e=؀==<={?=@=wK=U!NG)IŒ=ּ7;ͥt==0 =7=Cg˼J%< =k=d/=#Fr 9뀱I@t} =I._Aۜ;+=m=D=)V=l E伡sFP`&=ؗ:( ,h;3<%==do9<=/>D ?i<,<5ԉa\P=|ʜ===f= ;|3bx=;=VL=jE@=NW=<<+=S<{.<)UӼ0VMݼɒQU4X=PB4Z_=Y һ"&9<$*=?<7x;><9,== ;j_<y#<$}N<ہ;ն<=%qV;ͼ>=4=VÇ6㚽`)<񧳻K6XZ=?:+uH;F=_׆=4=⊩8˙(=i);p\arC4ѣ< =w=(bI= ;WU==6,<:9= c=w齳;Y|=6ּ^G yX޽v <»(@<=Qf=$;?=Bu׻E~AꭻUN;(%&Iv=. =Ƈ;m;h=<9$"=<^YsrּԽU,N"?~ !U/4+=<ƪzQ2y sYf,ri+=ڃ\<7뗽}c͉aNVGܠǽS<[6=W#8=%=i^pMML96 =MԵ<> %Ṟ=<2==<ɑ6=/==⪼<:=A5廇-Z ?I= =Dػ =Ĵ=cT=U%m=`=e]="fwx ==$p=:BOl03Xz K_\R% #(V*==s= = 9|=ДqF/K6 4@;쁊z=a=~OUD=;f >)%vIl< * 4DW`ѼڒI<=f=iJ=쳻һ+ =[=n=ړ=~]<>?K<\=w= =C<;<*Kv=L 6=W=om=ѻn=.= Pp=rAд.m1_9mۦ;=50=AjX;=-U==L"m!( .=2r8=%=;A^=oT=R=D=GV=Yn={ r:H jb='=#=/m8=;?I;V=A=s3_{=UfL@Eb7l=s8=,ө{r蟽vmD =Q= .=W *I3=\0=a=m=";ٙ =<>R<\;ѩ@<n<'=a;'2<|Ľ=;t4=̎=pk=oG=\T =_;fɺ=^ʽ㝡ݍ'G =z=5R5ۻ޽*iB!septimbre_amt.encoder.res1.3.biasJ@ͽܙaT3=R7Y3&R=(ȻE= Eؽ7(=@4,=Њ),1/8Ȍd)9#ջ<4J I =z =\rХ} .=&-֌;jRO@;9T;OqfYs;޼<2p<]t;h Ȁ߉*ڃRV=,q<=!f===~>eyTxջq<%2=#<`=g8/=y=D=u4=:=f= [?O㼪k$zK8U;U;f5(Z@AyK!$à/=V'=@`<0MY=2=м=K2=n;|@;ʽGA-t(Un ;/0#;ĽEU멽(qI($!`ݚ};f =qBG/==|*FOʗG**gX<=Y-=t8<D=t%==V-=).=C=r;cQ;=`;U+>@=R<ͫ! x=E= L=ˍ>;h ˼%=clj< =~=O8=x0=PԮ6B+ds3=c}=0,uԼ >ܭk=A|ơ,=fAZ<Y=I25^YJ t(WK.:T$N$ÛU%Fr?O`ۼU^-=>\ʎ^\8#=@;8=H=(̼;8><߿m/N٣;<'==^;U[2xuǽ>Ae}^>~=Dƻ-o=>=S=<(=<==1<1` >ՠ=F\=@=)&=H1*=>) yUQm,=C$=ZȆah^ҷ`ג8\:kTؽ+r=-|<8\<f坽}Ӽi<ݺ==i= 6=bk >*h4<["="mV =An .=tH;;ݫzjsƼ>=2h:=ž9=;>w8qzg;S;v<1ևH }Y;<_<9qm=2=c<ڱ>=sd=B=֮e]0ez;"=F > :.;oBc<"WYon<ǶUr9sWD,*=G<:=85*c3ה1"j<=z2Ȇ2<q} sߙaΙo<=_Ǽx<B<_=*rX=>;<17<9Ɉ =ܶKxdNI*=<[~Y<` uXR翼WLwyݔ4Yg <%|/L2< #h6=(Ը5=ތNB=Y}<~\[{<=;e-Ԓ8"&<)@(c=h# ;ܨ<5G<}Vhxмf4Cػ&UX3=9<$<…=%=A≽9h=Zq<Vh;FLGR:<{"f<ICUA\_= rm4=_n̼#;<<oͽ2D&Ե<֧o<z-=ʻ=O>Q$8=<+oߜ9jC;"BC<-ֽ}P?;jKPeǽC<D=<Ջ;ivVvBJ< =V+=sio<;|L <$;:Ias+<15<_[{7"dM=:p.<ˏdfQ)>j*Bval_25J*Bval_29J*Bval_33J*.Bval_47J $*Bval_353J*Bval_369J?*/Bval_379J *Bval_398J*Bval_483J$*Bval_484J*Bval_632J*Bval_686J9*Bval_741J*Bval_773J*Bval_795JH*Bval_850J*Bval_882J*Bval_904JT*Bval_959J*Bval_991J*Bval_1013J]*Bval_1068J*Bval_1100J*Bval_1122Je*Bval_1177J*Bval_1209J*(Bval_1253J* Bval_1257J????* Bval_1260J*TBval_1269J@#t?Eϡ??1?/?.?G?|?[?8?F{?S?N*??fɘ???*TBval_1271J@b*o=OGF<&yt}e?m-{^ѼѽE=*(Bval_1275J*Bval_1279J??*Bval_1282J*4Bval_1291J zP? x?a?T?d?b}i?V:l?.ra?*4Bval_1293J g<ȭۮo=+W<=*Bval_1295Jq>* Bval_1300J*0Bval_1320J *Bval_1327J̼+*TB add_824_biasJ@>Usf)?*?.>> پj=1=,O>6>ᾤ죝Q.*QB relu_biasJ@r[1>>G?fW{?NZ>1=z$>>>jb>7>*/B relu_1_biasJ8W^+?ɒ=@=9=*Bval_9J*Bval_10J*Bval_22J*Bval_30J*Bval_349J@*Bval_382JE-2*Bval_383J*Bval_384J*Bval_385J* Bval_1301J*Bval_1330J Z audio    time"= /pkg.torch.export.graph_signature.InputSpec.kind USER_INPUT"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"& !pkg.torch.onnx.original_node_namexb onset   T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1"? 0pkg.torch.export.graph_signature.OutputSpec.kind USER_OUTPUT". !pkg.torch.onnx.original_node_name squeeze_2b frame   T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1"? 0pkg.torch.export.graph_signature.OutputSpec.kind USER_OUTPUT". !pkg.torch.onnx.original_node_name squeeze_3b embedding    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1"? 0pkg.torch.export.graph_signature.OutputSpec.kind USER_OUTPUT"* !pkg.torch.onnx.original_node_namediv_1j septimbre_amt.cqt.cqt_kernels  H  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"D !pkg.torch.onnx.original_node_namep_septimbre_amt_cqt_cqt_kernelsj septimbre_amt.cqt.filtfilt.fir    !"< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"E !pkg.torch.onnx.original_node_name p_septimbre_amt_cqt_filtfilt_firj septimbre_amt.note_branch.k "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"B !pkg.torch.onnx.original_node_namep_septimbre_amt_note_branch_kj septimbre_amt.note_branch.b "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"B !pkg.torch.onnx.original_node_namep_septimbre_amt_note_branch_bjL 2septimbre_amt.note_branch.early_conv.0.conv.weight     jG -septimbre_amt.note_branch.early_conv.1.weight     j9 +septimbre_amt.note_branch.early_conv.1.bias  jD *septimbre_amt.note_branch.neck.conv.weight     j *septimbre_amt.note_branch.conv_yn.0.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"Q !pkg.torch.onnx.original_node_name,p_septimbre_amt_note_branch_conv_yn_0_weightj (septimbre_amt.note_branch.conv_yn.0.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"O !pkg.torch.onnx.original_node_name*p_septimbre_amt_note_branch_conv_yn_0_biasjH .septimbre_amt.note_branch.conv_yo1.conv.weight     j +septimbre_amt.note_branch.conv_yo2.0.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"R !pkg.torch.onnx.original_node_name-p_septimbre_amt_note_branch_conv_yo2_0_weightj )septimbre_amt.note_branch.conv_yo2.0.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"P !pkg.torch.onnx.original_node_name+p_septimbre_amt_note_branch_conv_yo2_0_biasj septimbre_amt.encoder.k "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"> !pkg.torch.onnx.original_node_namep_septimbre_amt_encoder_kj septimbre_amt.encoder.b "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"> !pkg.torch.onnx.original_node_namep_septimbre_amt_encoder_bj )septimbre_amt.encoder.early_conv.0.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"P !pkg.torch.onnx.original_node_name+p_septimbre_amt_encoder_early_conv_0_weightj 'septimbre_amt.encoder.early_conv.0.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"N !pkg.torch.onnx.original_node_name)p_septimbre_amt_encoder_early_conv_0_biasj )septimbre_amt.encoder.early_conv.3.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"P !pkg.torch.onnx.original_node_name+p_septimbre_amt_encoder_early_conv_3_weightj 'septimbre_amt.encoder.early_conv.3.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"N !pkg.torch.onnx.original_node_name)p_septimbre_amt_encoder_early_conv_3_biasj #septimbre_amt.encoder.neck.1.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"J !pkg.torch.onnx.original_node_name%p_septimbre_amt_encoder_neck_1_weightj !septimbre_amt.encoder.neck.1.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"H !pkg.torch.onnx.original_node_name#p_septimbre_amt_encoder_neck_1_biasj .septimbre_amt.encoder.res1.0.layer_norm.weight  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"U !pkg.torch.onnx.original_node_name0p_septimbre_amt_encoder_res1_0_layer_norm_weightj ,septimbre_amt.encoder.res1.0.layer_norm.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"S !pkg.torch.onnx.original_node_name.p_septimbre_amt_encoder_res1_0_layer_norm_biasj #septimbre_amt.encoder.res1.1.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"J !pkg.torch.onnx.original_node_name%p_septimbre_amt_encoder_res1_1_weightj !septimbre_amt.encoder.res1.1.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"H !pkg.torch.onnx.original_node_name#p_septimbre_amt_encoder_res1_1_biasj #septimbre_amt.encoder.res1.3.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"J !pkg.torch.onnx.original_node_name%p_septimbre_amt_encoder_res1_3_weightj !septimbre_amt.encoder.res1.3.bias  "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"H !pkg.torch.onnx.original_node_name#p_septimbre_amt_encoder_res1_3_biasj septimbre_amt.encoder.emb.0.k     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"D !pkg.torch.onnx.original_node_namep_septimbre_amt_encoder_emb_0_kj "septimbre_amt.encoder.emb.1.weight     "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"I !pkg.torch.onnx.original_node_name$p_septimbre_amt_encoder_emb_1_weightj septimbre_amt.encoder.emb.1.bias   "< /pkg.torch.export.graph_signature.InputSpec.kind PARAMETER"= 5pkg.torch.export.graph_signature.InputSpec.persistentNone"G !pkg.torch.onnx.original_node_name"p_septimbre_amt_encoder_emb_1_biasj\ val_25  "F $pkg.onnxscript.optimizer.folded_from['val_22', 'val_23', 'val_24']j\ val_29  "F $pkg.onnxscript.optimizer.folded_from['val_26', 'val_27', 'val_28']j\ val_33  "F $pkg.onnxscript.optimizer.folded_from['val_30', 'val_31', 'val_32']jf val_47  "P $pkg.onnxscript.optimizer.folded_from(['val_43', 'val_44', 'val_45', 'val_46']j` val_353  "I $pkg.onnxscript.optimizer.folded_from!['val_350', 'val_351', 'val_352']jF val_369 "3 $pkg.onnxscript.optimizer.folded_from ['val_368']j val_379  " $pkg.onnxscript.optimizer.folded_from_['val_371', 'val_372', 'val_373', 'val_374', 'val_375', 'val_376', 'val_377', 'val_378', 'var']j` val_398  "I $pkg.onnxscript.optimizer.folded_from!['val_395', 'val_396', 'val_397']jU val_483  "> $pkg.onnxscript.optimizer.folded_from['val_424', 'val_479']jU val_484  "> $pkg.onnxscript.optimizer.folded_from['val_428', 'val_479']j` val_632  "I $pkg.onnxscript.optimizer.folded_from!['val_409', 'val_630', 'val_631']j` val_686  "I $pkg.onnxscript.optimizer.folded_from!['val_683', 'val_684', 'val_685']j` val_741  "I $pkg.onnxscript.optimizer.folded_from!['val_707', 'val_739', 'val_740']jU val_773  "> $pkg.onnxscript.optimizer.folded_from['val_718', 'val_768']j` val_795  "I $pkg.onnxscript.optimizer.folded_from!['val_792', 'val_793', 'val_794']j` val_850  "I $pkg.onnxscript.optimizer.folded_from!['val_816', 'val_848', 'val_849']jU val_882  "> $pkg.onnxscript.optimizer.folded_from['val_827', 'val_877']j` val_904  "I $pkg.onnxscript.optimizer.folded_from!['val_901', 'val_902', 'val_903']j` val_959  "I $pkg.onnxscript.optimizer.folded_from!['val_925', 'val_957', 'val_958']jU val_991  "> $pkg.onnxscript.optimizer.folded_from['val_936', 'val_986']jd val_1013  "L $pkg.onnxscript.optimizer.folded_from$['val_1010', 'val_1011', 'val_1012']jd val_1068  "L $pkg.onnxscript.optimizer.folded_from$['val_1034', 'val_1066', 'val_1067']jX val_1100  "@ $pkg.onnxscript.optimizer.folded_from['val_1045', 'val_1095']jd val_1122  "L $pkg.onnxscript.optimizer.folded_from$['val_1119', 'val_1120', 'val_1121']jd val_1177  "L $pkg.onnxscript.optimizer.folded_from$['val_1143', 'val_1175', 'val_1176']jX val_1209  "@ $pkg.onnxscript.optimizer.folded_from['val_1154', 'val_1204']jo val_1253  "W $pkg.onnxscript.optimizer.folded_from/['val_1250', 'val_1251', 'val_1252', 'val_707']j{ val_1257  "c $pkg.onnxscript.optimizer.folded_from;['val_1250', 'val_1251', 'val_1255', 'val_1256', 'val_707']j{ val_1260  "c $pkg.onnxscript.optimizer.folded_from;['val_1250', 'val_1251', 'val_1258', 'val_1259', 'val_707']j val_1269    " $pkg.onnxscript.optimizer.folded_fromh['septimbre_amt.encoder.early_conv.1.weight', 'val_1264', 'val_1265', 'val_1266', 'val_1267', 'val_707']j val_1271    " $pkg.onnxscript.optimizer.folded_fromf['septimbre_amt.encoder.early_conv.1.bias', 'val_1264', 'val_1265', 'val_1266', 'val_1268', 'val_707']jn val_1275  "V $pkg.onnxscript.optimizer.folded_from.['val_1272', 'val_1273', 'val_1274', 'val_30']jz val_1279  "b $pkg.onnxscript.optimizer.folded_from:['val_1272', 'val_1273', 'val_1277', 'val_1278', 'val_30']jz val_1282  "b $pkg.onnxscript.optimizer.folded_from:['val_1272', 'val_1273', 'val_1280', 'val_1281', 'val_30']j val_1291    " $pkg.onnxscript.optimizer.folded_fromb['septimbre_amt.encoder.neck.0.weight', 'val_1286', 'val_1287', 'val_1288', 'val_1289', 'val_707']j val_1293    " $pkg.onnxscript.optimizer.folded_from`['septimbre_amt.encoder.neck.0.bias', 'val_1286', 'val_1287', 'val_1288', 'val_1290', 'val_707']j val_1295     "[ $pkg.onnxscript.optimizer.folded_from3['septimbre_amt.encoder.neck.2.weight', 'val_1294']jX val_1300  "@ $pkg.onnxscript.optimizer.folded_from['val_1298', 'val_1299']j val_1320  " $pkg.onnxscript.optimizer.folded_from]['val_1313', 'val_1314', 'val_1315', 'val_1316', 'val_1317', 'val_1318', 'val_1319', 'var_1']jH val_1327 "4 $pkg.onnxscript.optimizer.folded_from ['val_1326']j add_824_bias  j relu_bias  j relu_1_bias  j val_9  j val_10  j val_22 j val_30 j val_349 j val_382 j val_383 j val_384 j val_385 j val_1301  j val_1330  j val_0  j sym_size_int_85 j conv1d    timej flip    timej" conv1d_1    timej flip_1    timej, slice_1!    ((time + 1)//2)jB conv1d_26 40  H &$((((((time + 1)//2)) - 1)//256)) + 1jB view: 84   $ &$((((((time + 1)//2)) - 1)//256)) + 1j- conv1d_3!    ((time + 1)//2)j+ flip_2!    ((time + 1)//2)j- conv1d_4!    ((time + 1)//2)j+ flip_3!    ((time + 1)//2)j9 slice_2. ,(   (((((time + 1)//2)) + 1)//2)jO conv1d_5C A=  H 31(((((((((time + 1)//2)) + 1)//2)) - 1)//128)) + 1jQ view_1G EA   $ 31(((((((((time + 1)//2)) + 1)//2)) - 1)//128)) + 1j: conv1d_6. ,(   (((((time + 1)//2)) + 1)//2)j8 flip_4. ,(   (((((time + 1)//2)) + 1)//2)j: conv1d_7. ,(   (((((time + 1)//2)) + 1)//2)j8 flip_5. ,(   (((((time + 1)//2)) + 1)//2)jF slice_3; 95   +)((((((((time + 1)//2)) + 1)//2)) + 1)//2)j[ conv1d_8O MI  H ?=((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) - 1)//64)) + 1j] view_2S QM   $ ?=((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) - 1)//64)) + 1jG conv1d_9; 95   +)((((((((time + 1)//2)) + 1)//2)) + 1)//2)jE flip_6; 95   +)((((((((time + 1)//2)) + 1)//2)) + 1)//2)jH conv1d_10; 95   +)((((((((time + 1)//2)) + 1)//2)) + 1)//2)jE flip_7; 95   +)((((((((time + 1)//2)) + 1)//2)) + 1)//2)jS slice_4H FB   86(((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)ji conv1d_11\ ZV  H LJ(((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//32)) + 1jj view_3` ^Z   $ LJ(((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//32)) + 1jU conv1d_12H FB   86(((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jR flip_8H FB   86(((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jU conv1d_13H FB   86(((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jR flip_9H FB   86(((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j` slice_5U SO   EC((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jv conv1d_14i gc  H YW((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//16)) + 1jw view_4m kg   $ YW((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//16)) + 1jb conv1d_15U SO   EC((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j` flip_10U SO   EC((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jb conv1d_16U SO   EC((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j` flip_11U SO   EC((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jm slice_6b `\   RP(((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j conv1d_17u so  H ec(((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//8)) + 1j view_5y ws   $ ec(((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//8)) + 1jo conv1d_18b `\   RP(((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jm flip_12b `\   RP(((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jo conv1d_19b `\   RP(((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jm flip_13b `\   RP(((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jz slice_7o mi   _]((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j conv1d_20 |  H rp((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//4)) + 1j view_6    $ rp((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//4)) + 1j| conv1d_21o mi   _]((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jz flip_14o mi   _]((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j| conv1d_22o mi   _]((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)jz flip_15o mi   _]((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j slice_8| zv   lj(((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)j conv1d_23   H }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j view_7    $ }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j cat_8     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j pow_1     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j sum_1     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j sum_2     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j! val_359     j val_360     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_361     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_362    j val_363  j val_364  j val_365 jO val_366 "< $pkg.onnxscript.optimizer.folded_from['sum_2', 'val_365']j val_367    j val_370 j var    j! val_380     j sqrt     j add_607     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j log     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j log_1     j sub_94     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j add_617 j floordiv_359 j add_618 j floordiv_360 j add_619 j floordiv_361 j add_620 j floordiv_362 j add_621 j floordiv_363 j add_622 j floordiv_364 j add_623 j floordiv_365 j add_624 j floordiv_366 j add_625 j floordiv_367 j add_626 j val_390  j val_391  j zeros     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_9     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_14     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_476  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_478  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_480  j val_481 j val_482  j val_486  j val_487  j val_488     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_489     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_490     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_492  j val_493 j val_494  j val_498  j val_499  j val_500     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_501     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_502     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_2     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_19     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_562  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_564  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_566  j val_567 j val_568  j val_572  j val_573  j val_574     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_575     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_576     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_4     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_28     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_36     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_656  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_658  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_660  j val_661 j val_662  j val_666  j val_667  j val_668     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_669     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_670     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_672  j val_673 j val_674  j val_678  j val_679  j val_680     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_681     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_682     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_7     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_41     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_49     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_765  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_767  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_769  j val_770 j val_771  j val_775  j val_776  j val_777     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_778     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_779     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_781  j val_782 j val_783  j val_787  j val_788  j val_789     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_790     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_791     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_10     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_54     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_62     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_874  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_876  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_878  j val_879 j val_880  j val_884  j val_885  j val_886     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_887     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_888     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_890  j val_891 j val_892  j val_896  j val_897  j val_898     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_899     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_900     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_13     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_67     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_75     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_983  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_985  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_987  j val_988 j val_989  j val_993  j val_994  j val_995     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_996     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_997     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_999  j val_1000 j val_1001  j val_1005  j val_1006  j val_1007     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1008     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1009     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_16     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_80     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_88     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1092  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_1094  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_1096  j val_1097 j val_1098  j val_1102  j val_1103  j val_1104     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1105     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1106     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1108  j val_1109 j val_1110  j val_1114  j val_1115  j val_1116     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1117     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1118     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_19     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_93     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_101     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1201  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_1203  }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1   j val_1205  j val_1206 j val_1207  j val_1211  j val_1212  j val_1213     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1214     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1215     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1217  j val_1218 j val_1219  j val_1223  j val_1224  j val_1225     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1226     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1227     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j slice_scatter_22     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j mul_595     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j add_824     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j getitem     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j leaky_relu     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j getitem_3     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j add_856     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j relu     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j getitem_6     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j relu_1     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j conv2d_1    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j sigmoid    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j getitem_9    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j relu_2    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j concat    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j convolution_2    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j sigmoid_1    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j squeeze   T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j squeeze_1   T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j mul_740     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j add_927     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j convolution_3     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1254    j val_1261    j val_1262  j val_1263  j val_1270   j group_norm     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j leaky_relu_1     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j conv2d_3     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j add_955     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1276    j val_1283    j val_1284  j val_1285  j val_1292   j group_norm_1     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j convolution_4     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j prelu     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j permute    }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1 j layer_norm    }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1 j permute_1     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j convolution_5     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j relu_3     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j convolution_6     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j add_995     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j mean     j" val_1302     j val_1303     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1304     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1305   j val_1306  j val_1307  j val_1308 jS val_1309 "? $pkg.onnxscript.optimizer.folded_from['add_995', 'val_1308']j val_1310   j val_1312 j var_1   j" val_1321     j sqrt_1     j sub_205     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j div     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j mul_863     }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j conv2d_4    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j linalg_vector_norm    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j clamp_min    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j val_1333  j expand    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j max_1 j div_2   T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j unsqueeze    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j max_2 j div_3   T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1j unsqueeze_1    T }(((((((((((((((((((((((((((time + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) + 1)//2)) - 1)//2)) + 1/ 0pkg.torch.export.ExportedProgram.graph_signature/ # inputs p_septimbre_amt_cqt_cqt_kernels: PARAMETER target='septimbre_amt.cqt.cqt_kernels' p_septimbre_amt_cqt_filtfilt_fir: PARAMETER target='septimbre_amt.cqt.filtfilt.fir' p_septimbre_amt_note_branch_k: PARAMETER target='septimbre_amt.note_branch.k' p_septimbre_amt_note_branch_b: PARAMETER target='septimbre_amt.note_branch.b' p_septimbre_amt_note_branch_early_conv_0_conv_weight: PARAMETER target='septimbre_amt.note_branch.early_conv.0.conv.weight' p_septimbre_amt_note_branch_early_conv_0_bn_weight: PARAMETER target='septimbre_amt.note_branch.early_conv.0.bn.weight' p_septimbre_amt_note_branch_early_conv_0_bn_bias: PARAMETER target='septimbre_amt.note_branch.early_conv.0.bn.bias' p_septimbre_amt_note_branch_early_conv_1_weight: PARAMETER target='septimbre_amt.note_branch.early_conv.1.weight' p_septimbre_amt_note_branch_early_conv_1_bias: PARAMETER target='septimbre_amt.note_branch.early_conv.1.bias' p_septimbre_amt_note_branch_early_conv_2_weight: PARAMETER target='septimbre_amt.note_branch.early_conv.2.weight' p_septimbre_amt_note_branch_early_conv_2_bias: PARAMETER target='septimbre_amt.note_branch.early_conv.2.bias' p_septimbre_amt_note_branch_neck_conv_weight: PARAMETER target='septimbre_amt.note_branch.neck.conv.weight' p_septimbre_amt_note_branch_neck_bn_weight: PARAMETER target='septimbre_amt.note_branch.neck.bn.weight' p_septimbre_amt_note_branch_neck_bn_bias: PARAMETER target='septimbre_amt.note_branch.neck.bn.bias' p_septimbre_amt_note_branch_conv_yn_0_weight: PARAMETER target='septimbre_amt.note_branch.conv_yn.0.weight' p_septimbre_amt_note_branch_conv_yn_0_bias: PARAMETER target='septimbre_amt.note_branch.conv_yn.0.bias' p_septimbre_amt_note_branch_conv_yo1_conv_weight: PARAMETER target='septimbre_amt.note_branch.conv_yo1.conv.weight' p_septimbre_amt_note_branch_conv_yo1_bn_weight: PARAMETER target='septimbre_amt.note_branch.conv_yo1.bn.weight' p_septimbre_amt_note_branch_conv_yo1_bn_bias: PARAMETER target='septimbre_amt.note_branch.conv_yo1.bn.bias' p_septimbre_amt_note_branch_conv_yo2_0_weight: PARAMETER target='septimbre_amt.note_branch.conv_yo2.0.weight' p_septimbre_amt_note_branch_conv_yo2_0_bias: PARAMETER target='septimbre_amt.note_branch.conv_yo2.0.bias' p_septimbre_amt_encoder_k: PARAMETER target='septimbre_amt.encoder.k' p_septimbre_amt_encoder_b: PARAMETER target='septimbre_amt.encoder.b' p_septimbre_amt_encoder_early_conv_0_weight: PARAMETER target='septimbre_amt.encoder.early_conv.0.weight' p_septimbre_amt_encoder_early_conv_0_bias: PARAMETER target='septimbre_amt.encoder.early_conv.0.bias' p_septimbre_amt_encoder_early_conv_1_weight: PARAMETER target='septimbre_amt.encoder.early_conv.1.weight' p_septimbre_amt_encoder_early_conv_1_bias: PARAMETER target='septimbre_amt.encoder.early_conv.1.bias' p_septimbre_amt_encoder_early_conv_3_weight: PARAMETER target='septimbre_amt.encoder.early_conv.3.weight' p_septimbre_amt_encoder_early_conv_3_bias: PARAMETER target='septimbre_amt.encoder.early_conv.3.bias' p_septimbre_amt_encoder_neck_0_weight: PARAMETER target='septimbre_amt.encoder.neck.0.weight' p_septimbre_amt_encoder_neck_0_bias: PARAMETER target='septimbre_amt.encoder.neck.0.bias' p_septimbre_amt_encoder_neck_1_weight: PARAMETER target='septimbre_amt.encoder.neck.1.weight' p_septimbre_amt_encoder_neck_1_bias: PARAMETER target='septimbre_amt.encoder.neck.1.bias' p_septimbre_amt_encoder_neck_2_weight: PARAMETER target='septimbre_amt.encoder.neck.2.weight' p_septimbre_amt_encoder_res1_0_layer_norm_weight: PARAMETER target='septimbre_amt.encoder.res1.0.layer_norm.weight' p_septimbre_amt_encoder_res1_0_layer_norm_bias: PARAMETER target='septimbre_amt.encoder.res1.0.layer_norm.bias' p_septimbre_amt_encoder_res1_1_weight: PARAMETER target='septimbre_amt.encoder.res1.1.weight' p_septimbre_amt_encoder_res1_1_bias: PARAMETER target='septimbre_amt.encoder.res1.1.bias' p_septimbre_amt_encoder_res1_3_weight: PARAMETER target='septimbre_amt.encoder.res1.3.weight' p_septimbre_amt_encoder_res1_3_bias: PARAMETER target='septimbre_amt.encoder.res1.3.bias' p_septimbre_amt_encoder_emb_0_k: PARAMETER target='septimbre_amt.encoder.emb.0.k' p_septimbre_amt_encoder_emb_1_weight: PARAMETER target='septimbre_amt.encoder.emb.1.weight' p_septimbre_amt_encoder_emb_1_bias: PARAMETER target='septimbre_amt.encoder.emb.1.bias' b_septimbre_amt_note_branch_early_conv_0_bn_running_mean: BUFFER target='septimbre_amt.note_branch.early_conv.0.bn.running_mean' persistent=True b_septimbre_amt_note_branch_early_conv_0_bn_running_var: BUFFER target='septimbre_amt.note_branch.early_conv.0.bn.running_var' persistent=True b_septimbre_amt_note_branch_early_conv_0_bn_num_batches_tracked: BUFFER target='septimbre_amt.note_branch.early_conv.0.bn.num_batches_tracked' persistent=True b_septimbre_amt_note_branch_early_conv_2_running_mean: BUFFER target='septimbre_amt.note_branch.early_conv.2.running_mean' persistent=True b_septimbre_amt_note_branch_early_conv_2_running_var: BUFFER target='septimbre_amt.note_branch.early_conv.2.running_var' persistent=True b_septimbre_amt_note_branch_early_conv_2_num_batches_tracked: BUFFER target='septimbre_amt.note_branch.early_conv.2.num_batches_tracked' persistent=True b_septimbre_amt_note_branch_neck_bn_running_mean: BUFFER target='septimbre_amt.note_branch.neck.bn.running_mean' persistent=True b_septimbre_amt_note_branch_neck_bn_running_var: BUFFER target='septimbre_amt.note_branch.neck.bn.running_var' persistent=True b_septimbre_amt_note_branch_neck_bn_num_batches_tracked: BUFFER target='septimbre_amt.note_branch.neck.bn.num_batches_tracked' persistent=True b_septimbre_amt_note_branch_conv_yo1_bn_running_mean: BUFFER target='septimbre_amt.note_branch.conv_yo1.bn.running_mean' persistent=True b_septimbre_amt_note_branch_conv_yo1_bn_running_var: BUFFER target='septimbre_amt.note_branch.conv_yo1.bn.running_var' persistent=True b_septimbre_amt_note_branch_conv_yo1_bn_num_batches_tracked: BUFFER target='septimbre_amt.note_branch.conv_yo1.bn.num_batches_tracked' persistent=True x: USER_INPUT # outputs squeeze_2: USER_OUTPUT squeeze_3: USER_OUTPUT div_1: USER_OUTPUT J 2pkg.torch.export.ExportedProgram.range_constraints{s53: VR[0, int_oo]}B  ================================================ FILE: dataProcess/AI/septimbre_worker.js ================================================ // const ort_folder = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/'; // self.importScripts(ort_folder + 'ort.wasm.min.js'); // ort.env.wasm.wasmPaths = ort_folder; self.importScripts('./postprocess.js'); self.importScripts('./SpectralClustering.js'); self.importScripts('./dist/bundle.min.js') ort.env.wasm.wasmPaths = './dist/' const model = ort.InferenceSession.create( './septimbre_44100.onnx', { executionProviders: ['wasm'] } ); self.onmessage = function ({data}) { if (typeof data === 'number') { // 接收到的是k self.k = data; return; } const tensorInput = new ort.Tensor('float32', data, [1, 1, data.length]); model.then((m) => { return m.run({ audio: tensorInput }); }).then((results) => { const note_events = createNotes( results.onset, results.frame, 0.31, 0.35 ); console.time('clusterNotes'); const clustered_notes = clusterNotes( note_events, results.embedding, results.frame, self.k || 2 ); console.timeEnd('clusterNotes'); self.postMessage(clustered_notes); }).catch((e) => { // promise中的报错不会触发worker.onerror回调,即使这里throw了。所以只能用onmessage self.postMessage({ type: 'error', message: e.message }); }); }; function clusterNotes(note_events, embTensor, frameTensor, k=2) { // 模型中已经对onset和frame进行归一化了 const raw_frameData = frameTensor.cpuData; const frameDim = frameTensor.dims; // [1, 84, frames] const raw_embData = embTensor.cpuData; const embDim = embTensor.dims; // [1, 12, 84, frames] const frameNum = frameDim[2]; const noteNum = frameDim[1]; const frameData = Array(noteNum); for (let i = 0; i < noteNum; i++) { // 和raw共享内存 frameData[i] = new Float32Array(raw_frameData.buffer, i * frameNum * 4, frameNum); } const spaceSize = noteNum * frameNum; function getEmbedding(note, time, emb) { // embDim: [1, 12, 84, frames] // raw_embData: Float32Array for (let i = 0; i < embDim[1]; i++) { // 计算在一维数组中的索引 // 索引 = i * noteNum * frameNum + note * frameNum + time emb[i] = raw_embData[ i * spaceSize + note * frameNum + time ]; } return emb; } const embeddings = []; const buffer = new Float32Array(embDim[1]); for (const note_event of note_events) { const { onset, offset, note } = note_event; const emb = new Float32Array(embDim[1]); // 取音符中间的embedding for (let t = onset; t < offset; t++) { const e = getEmbedding(note - 24, t, buffer); const frame = frameData[note - 24][t]; const w = frame * frame; // 用frame的值作为权重 for (let i = 0; i < embDim[1]; i++) { emb[i] += e[i] * w; } } let norm = 0.0; for (let i = 0; i < embDim[1]; i++) norm += emb[i] * emb[i]; norm = Math.sqrt(norm); for (let i = 0; i < embDim[1]; i++) emb[i] /= norm; embeddings.push(emb); } const labels = SpectralClustering(embeddings, k); const clustered_notes = Array.from({ length: k }, () => []); for (let i = 0; i < note_events.length; i++) { clustered_notes[labels[i]].push(note_events[i]); } return clustered_notes; } ================================================ FILE: dataProcess/ANA.js ================================================ /** * @file ANA.js (auto note alignment) * @abstract 融合HMM和DTW的音符自动对齐 * @description * ## 记法 * 从左到右——时频谱从开始到结尾 * 从上到下——音符序列从开始到结尾 * 起点:左上角;终点:右下角 * * ## 转移规则: * 从左到右从上到下计算 * 仅有当前格为-1时才能计算向下扩散,向下扩散不使用状态转移概率(实际还是用了,提高切换的门槛) * 其余都只能向右和右下扩散 * 计算第t列仅能使用第(t-1)列,需要乘上状态转移概率 * * P(s_{t}=-1 | s_{t-1}=-1) = 0.32 * P(s_{t}!=-1 | s_{t-1}=-1) = 0.68 * * P(s_{t}=-1 | s_{t-1}!=-1) = 0.2 * P(s_{t}=s_{t-1} | s_{t-1}!=-1) = 0.8 * * ## 激发概率 * 取可能遇到的bin的max,以此为边界缩放,并小值补偿(开根号),记为当前bin存在音符的概率 */ /** * HMM 进行自动音符-音频对齐 规则见上 * @param {Array} noteSeq 音符序列,已经插入了间隔-1 * @param {Array} spectrum 时频谱 第一维是时间 * @param {number} minLen 建议的音符最小长度 可为小数 * @returns {Array>} 全局最优路径 [[n, s], [n2, s2], ...] */ function autoNoteAlign(noteSeq, spectrum, minLen = 2) { class AlignInfo { constructor(v = -Infinity, k = 0) { this.value = v; // 指向上一帧的某个bin this.keep = k; // 音符长度 } }; /** * 找到可能的最大最小值,返回线性归一化函数 * @param {Set} noteSet * @param {Array} spectrum * @returns {Function(number)} 归一化函数 */ function _getNormalizeFN(noteSet, spectrum) { let max = -Infinity; let min = Infinity; for (const s of spectrum) { for (const bin of noteSet) { if (s[bin] > max) max = s[bin]; if (s[bin] < min) min = s[bin]; } } const len = max - min; return (x) => (x - min) / len; } const fn = _getNormalizeFN(new Set(noteSeq), spectrum); let buffer_curr = Array(noteSeq.length); let buffer_prev = Array(noteSeq.length); for (let i = 0; i < noteSeq.length; i++) { buffer_curr[i] = new AlignInfo(); buffer_prev[i] = new AlignInfo(); } buffer_prev[0].value = 0; const k = 0.52; // 由于大值很少,0很多,因此要提高对小值的敏感度 const P = Array(spectrum.length); for (let frame = 0; frame < spectrum.length; frame++) { const from = P[frame] = new Uint16Array(noteSeq.length).fill(-1); const frameSpectrum = spectrum[frame]; // 先向右和右下扩散 for (let i = 0; i < noteSeq.length; ++i) { const root = buffer_prev[i]; // 由于路径限制,并不是每个位置都能到达,可以跳过 if (root.value === -Infinity) break; if (noteSeq[i] === -1) { if (i + 1 < noteSeq.length) { const hasNote = Math.pow(fn(frameSpectrum[noteSeq[i + 1]]), k); // 以下的概率和不为1...然而强制缩放为1效果很差,不如就这样,可解释性还高 const keepP = 0.32; // 保持空状态 const right = root.value + Math.log(Math.max((1 - hasNote) * keepP, 1e-12)); if (buffer_curr[i].value < right) { buffer_curr[i].value = right; from[i] = i; buffer_curr[i].keep = root.keep + 1; } // 切换为音符 const rightdown = root.value + Math.log(Math.max(hasNote * (1 - keepP), 1e-12)); if (buffer_curr[i + 1].value < rightdown) { buffer_curr[i + 1].value = rightdown; from[i + 1] = i; buffer_curr[i + 1].keep = 0; } } else { // 没有下一个了 保持较小速率降低 const p = root.value - 1; if (buffer_curr[i].value < p) { buffer_curr[i].value = p; from[i] = i; buffer_curr[i].keep = root.keep + 1; } } } else { // 是音符 const hasNote = Math.pow(fn(frameSpectrum[noteSeq[i]]), k); let keepP = 0.8; if (root.keep < minLen) { // 初始概率必须大 不然高时间分辨率频谱下容易出现很碎的音 keepP = 0.999 - 0.09 * (root.keep / minLen); } // 保持音符 const right = root.value + Math.log(Math.max(hasNote * keepP, 1e-12)); if (buffer_curr[i].value < right) { buffer_curr[i].value = right; from[i] = i; buffer_curr[i].keep = root.keep + 1; } // 暂停 const rightdown = root.value + Math.log(Math.max((1 - hasNote) * (1 - keepP), 1e-12)); if (buffer_curr[i + 1].value < rightdown) { buffer_curr[i + 1].value = rightdown; from[i + 1] = i; buffer_curr[i + 1].keep = 0; } } } // 再处理纵向扩散 第一位永远是-1可以跳过 for (let i = 1; i < noteSeq.length; ++i) { if (buffer_curr[i - 1].value === -Infinity) break; if (noteSeq[i - 1] === -1) { const hasNote = Math.pow(fn(frameSpectrum[noteSeq[i]]), k); const down = buffer_curr[i - 1].value + Math.log(Math.max(hasNote * 0.8, 1e-12)); if (buffer_curr[i].value < down) { buffer_curr[i].value = down; from[i] = from[i - 1]; buffer_curr[i].keep = 0; } } } // 交换位置并复原 [buffer_curr, buffer_prev] = [buffer_prev, buffer_curr]; for (const i of buffer_curr) { i.keep = 0; i.value = -Infinity; } } // 寻路 const path = []; let noteidx = noteSeq.length - 1; for (let frame = P.length - 1; frame >= 0; frame--) { path.push([noteidx, frame]); noteidx = P[frame][noteidx]; } path.reverse(); return path; } ================================================ FILE: dataProcess/CQT/cqt.js ================================================ // 开启CQT的Worker线程,因为CQT是耗时操作,所以放在Worker线程中 function cqt(channels, tNum, fmin, useGPU = false) { return new Promise((resolve, reject) => { const worker = new Worker("./dataProcess/CQT/cqt_worker.js"); worker.onerror = (e) => { reject(e); worker.terminate(); }; worker.onmessage = ({ data }) => { resolve(data); worker.terminate(); }; worker.postMessage({ audioChannel: channels, sampleRate: channels.sampleRate, hop: Math.round(channels.sampleRate / tNum), fmin, useGPU }, channels.map(x => x.buffer)); }); } ================================================ FILE: dataProcess/CQT/cqt_worker.js ================================================ /** * 用定义计算CQT,时间复杂度很高,但是分析效果好 */ class CQT { /** * 创建窗函数 幅度加起来为1 * @param {number} N * @returns {Float32Array} 窗幅度 */ static blackmanHarris(N) { let w = new Float32Array(N); const temp = 2 * Math.PI / (N - 1); let sum = 0; for (let n = 0; n < N; n++) { w[n] = 0.35875 - 0.48829 * Math.cos(temp * n) + 0.14128 * Math.cos(temp * n * 2) - 0.01168 * Math.cos(temp * n * 3); sum += w[n]; } // 归一化(幅度归一化,和矩形窗FFT除以N的效果一样) for (let n = 0; n < N; n++) w[n] /= sum; return w; } /** * 预计算CQT参数 * @param {number} fs 采样率 * @param {number} fmin 最低的频率(最低八度的C) 默认为C1 * @param {number} octaves 要分析几个八度 * @param {number} bins_per_octave 几平均律 * @param {number} filter_scale Q的缩放倍数 越大频率选择性越好 */ constructor(fs, fmin = 32.70319566257483, octaves = 7, bins_per_octave = 12, filter_scale = 1) { this.fmin = fmin; this.bins_per_octave = bins_per_octave; this.bins = bins_per_octave * octaves; const Q = filter_scale / (Math.pow(2, 1 / bins_per_octave) - 1); [this.kernel_r, this.kernel_i] = CQT.iniKernel( Q, fs, fmin, bins_per_octave, this.bins ); } /** * 得到CQT kernel 时域数据 * @param {number} Q * @param {number} fs 采样率 * @param {number} fmin 最低音 * @param {number} bins_per_octave 八度内的频率个数 * @param {number} binNum 一共多少个频率 * @returns {Array} [kernel_r, kernel_i] */ static iniKernel(Q, fs, fmin, bins_per_octave = 12, binNum = 84) { const kernel_r = Array(binNum); const kernel_i = Array(binNum); for (let i = 0; i < binNum; i++) { const freq = fmin * Math.pow(2, i / bins_per_octave); const len = Math.ceil(Q * fs / freq); const tmp_kernel = new Float32Array(len << 1); const tmp_kernel_r = kernel_r[i] = tmp_kernel.subarray(0, len); const tmp_kernel_i = kernel_i[i] = tmp_kernel.subarray(len, len << 1); const window = CQT.blackmanHarris(len); const omega = 2 * Math.PI * freq / fs; const half_len = len >> 1; for (let j = 0; j < len; j++) { const angle = omega * (j - half_len); // 中心的相位为0 tmp_kernel_r[j] = Math.cos(angle) * window[j]; tmp_kernel_i[j] = -Math.sin(angle) * window[j]; // 而且CQT1992继承自本类,用正相位增加的旋转因子可以让频域带宽在正频率上 } } return [kernel_r, kernel_i]; } /** * 计算CQT * @param {Float32Array} x 输入实数时序信号 * @param {number} hop 步长 * @param {Float32Array} raw 可选的输出数组 如果提供了就用它来存储能量(累加) 否则新建一个 * @returns {Array} 第一维是时间,第二维是频率 */ cqt(x, hop, raw = null) { let offset = hop >> 1; const output_length = (x.length - offset) / hop | 1; const output = Array(output_length); output.raw = raw ??= new Float32Array(output_length * this.bins); for (let p = 0, pointer = 0; offset <= x.length; offset += hop, pointer++) { const nextp = p + this.bins; const energy = output[pointer] = raw.subarray(p, nextp); p = nextp; for (let b = 0; b < this.bins; b++) { // 每个频率 const kernel_r = this.kernel_r[b]; const kernel_i = this.kernel_i[b]; let real = 0, imag = 0; const left = offset - (kernel_r.length >> 1); const right = Math.min(kernel_r.length, x.length - left); for (let i = left >= 0 ? 0 : -left; i < right; i++) { const index = left + i; real += x[index] * kernel_r[i]; imag += x[index] * kernel_i[i]; } energy[b] += real * real + imag * imag; } } return output; } // 能量谱归一化为幅度谱 static norm(s) { let count = 0, mean = 0, M2 = 0; for (const e of s) { count++; let d = e - mean; mean += d / count; let d2 = e - mean; M2 += d * d2; } let invSigma = Math.sqrt(count / M2); for (let i = 0; i < s.length; i++) s[i] = Math.sqrt(s[i] * invSigma); } /** * 初始化 GPU kernel 缓冲区和管线 * 管线结果为能量和相位 * 增加的属性: * this.adapter * this.device * this.workgroupsize * this.kernelBuffer * this.kernelInfoBuffer * this.configBuffer * this.CQTpipeline * @param {number} workgroupsize 线程数 */ async initWebGPU(workgroupsize = 256) { if (!navigator.gpu) throw new Error("WebGPU not supported."); const adapter = this.adapter ??= await navigator.gpu.requestAdapter(); if (!adapter) throw new Error("No GPUAdapter found."); const device = this.device ??= await adapter.requestDevice({ requiredLimits: { maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize, maxBufferSize: adapter.limits.maxBufferSize, } }); this.workgroupsize = workgroupsize; // --- kernel 缓冲区创建 --- const numBins = this.bins; const kernel_r = this.kernel_r;; const kernel_i = this.kernel_i; let totalKernelsLength = 0; // 总大小 for (let i = 0; i < numBins; i++) totalKernelsLength += kernel_r[i].length << 1; // 创建一个在创建时即映射的 GPU 缓冲区 const allKernelsBuffer = this.kernelBuffer ??= device.createBuffer({ label: "All Kernels", size: totalKernelsLength * Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.STORAGE, mappedAtCreation: true, }); const mappedKernelsRange = allKernelsBuffer.getMappedRange(); const mappedKernelsArray = new Float32Array(mappedKernelsRange); const kernelInfoData = new Uint32Array(numBins * 3); // 每个卷积核3个信息:实部偏移、虚部偏移、长度 for (let i = 0, currentOffset = 0; i < numBins; i++) { const infoBaseIndex = i * 3; const len = kernelInfoData[infoBaseIndex + 2] = kernel_r[i].length; mappedKernelsArray.set(kernel_r[i], currentOffset); kernelInfoData[infoBaseIndex] = currentOffset; currentOffset += len; mappedKernelsArray.set(kernel_i[i], currentOffset); kernelInfoData[infoBaseIndex + 1] = currentOffset; currentOffset += len; } allKernelsBuffer.unmap(); // 以后不能改了 // --- Kernel Info Buffer --- const kernelInfoBuffer = this.kernelInfoBuffer ??= device.createBuffer({ label: "Kernel Info", size: kernelInfoData.byteLength, usage: GPUBufferUsage.STORAGE, mappedAtCreation: true, }); new Uint32Array(kernelInfoBuffer.getMappedRange()).set(kernelInfoData); kernelInfoBuffer.unmap(); this.configBuffer = device.createBuffer({ label: "Config Buffer", size: 4 * Uint32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, }); // --- CQT代码 --- const shaderModule = device.createShaderModule({ label: 'CQT Energy Compute Shader', code: /* wgsl */` struct KernelInfo { real_offset: u32, imag_offset: u32, length: u32, }; struct Config { hop: u32, num_samples: u32, num_frames: u32, first_frame_center_offset: u32, }; @group(0) @binding(0) var all_kernels: array; @group(0) @binding(1) var kernel_infos: array; @group(0) @binding(2) var config: Config; @group(0) @binding(3) var audio: array; @group(0) @binding(4) var output: array; // 共享内存 用于协作加载 kernel 能提速6% var s_kernel_r: array; var s_kernel_i: array; // 一次计算一个频点的workgroupsize个时间帧 使得负载均匀 @compute @workgroup_size(${workgroupsize}) fn main( @builtin(workgroup_id) workgroup_id: vec3, // (numBins, blocks, 1) @builtin(local_invocation_id) local_id: vec3 ) { let frame = workgroup_id.y * ${workgroupsize}u + local_id.x; let bin_idx = workgroup_id.x; let info = kernel_infos[bin_idx]; let klen = info.length; // 计算当前帧对应的音频起始位置 let frame_center_pos = i32(config.first_frame_center_offset + frame * config.hop); let left = frame_center_pos - i32(klen >> 1u); let num_samples_i32 = i32(config.num_samples); var real: f32 = 0.0; var imag: f32 = 0.0; for (var base_k: u32 = 0u; base_k < klen; base_k = base_k + ${workgroupsize}u) { let t_idx = local_id.x; let load_k_idx = base_k + t_idx; // 超出kernel长度的填0 (对于最后一块tile很重要) let valid = load_k_idx < klen; s_kernel_r[t_idx] = select(0.0, all_kernels[info.real_offset + load_k_idx], valid); s_kernel_i[t_idx] = select(0.0, all_kernels[info.imag_offset + load_k_idx], valid); workgroupBarrier(); if (frame < config.num_frames) { let current_block_size = min(${workgroupsize}u, klen - base_k); for (var j: u32 = 0u; j < current_block_size; j = j + 1u) { let audio_idx = left + i32(base_k + j); // 边界检查 在音频两端补零 if (audio_idx >= 0 && audio_idx < num_samples_i32) { let audioSample = audio[u32(audio_idx)]; real = fma(audioSample, s_kernel_r[j], real); imag = fma(audioSample, s_kernel_i[j], imag); } } } workgroupBarrier(); } if (frame >= config.num_frames) { return; } // 频率优先存储 let out_index = ${this.bins} * frame + bin_idx; output[out_index] = output[out_index] + real * real + imag * imag; // 如果多通道会累加 }` }); this.CQTpipeline ??= device.createComputePipeline({ label: 'CQT Full Compute Pipeline', layout: 'auto', compute: { module: shaderModule, entryPoint: 'main' }, }); } /** * 使用GPU计算CQT 需要先调用 initWebGPU * 第一次传入的音频数据会被视为尺寸用于后续所有计算 * @param {Float32Array} audioData * @param {number} hop */ cqt_GPU(audioData, hop) { const device = this.device; const numBins = this.bins; // 配置 const offset0 = hop >> 1; const numFrames = 1 + (audioData.length - offset0 - 1) / hop | 0; device.queue.writeBuffer(this.configBuffer, 0, new Uint32Array([hop, audioData.length, numFrames, offset0])); // 输入 this.inputAudioBuffer ??= device.createBuffer({ label: "Full Audio Buffer", size: audioData.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, }); device.queue.writeBuffer(this.inputAudioBuffer, 0, audioData); // 输出 const totalValues = numFrames * numBins; const outputBufferSize = totalValues * Float32Array.BYTES_PER_ELEMENT; this.outputBuffer ??= device.createBuffer({ label: "CQT Output Buffer", size: outputBufferSize, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, }); const bindGroup = device.createBindGroup({ label: 'CQT Bind Group', layout: this.CQTpipeline.getBindGroupLayout(0), entries: [ { binding: 0, resource: { buffer: this.kernelBuffer } }, { binding: 1, resource: { buffer: this.kernelInfoBuffer } }, { binding: 2, resource: { buffer: this.configBuffer } }, { binding: 3, resource: { buffer: this.inputAudioBuffer } }, { binding: 4, resource: { buffer: this.outputBuffer } }, ], }); const encoder = device.createCommandEncoder(); const pass = encoder.beginComputePass(); pass.setPipeline(this.CQTpipeline); pass.setBindGroup(0, bindGroup); pass.dispatchWorkgroups(numBins, Math.ceil(numFrames / this.workgroupsize)); pass.end(); device.queue.submit([encoder.finish()]); return numFrames; } /** * 提取GPU数据并用CPU归一化 * @param {GPUBuffer} buffer 要归一化的 * @param {number} numFrames 帧数 * @returns {Array} 归一化后的幅度谱矩阵 */ async norm_CPU(buffer, numFrames) { const device = this.device; const readBuffer = device.createBuffer({ label: "Read CQT Buffer", size: buffer.size, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, }); const encoder = device.createCommandEncoder(); encoder.copyBufferToBuffer(buffer, 0, readBuffer, 0, buffer.size); device.queue.submit([encoder.finish()]); await readBuffer.mapAsync(GPUMapMode.READ); const ampMatrix = Array(numFrames); const raw = ampMatrix.raw = new Float32Array(readBuffer.getMappedRange()).slice(); readBuffer.destroy(); CQT.norm(raw); for (let t = 0, offset = 0; t < numFrames; t++) { const next = offset + this.bins; ampMatrix[t] = raw.subarray(offset, next); offset = next; } return ampMatrix; } freeGPU() { this.kernelBuffer?.destroy(); this.kernelInfoBuffer?.destroy(); this.configBuffer?.destroy(); this.inputAudioBuffer?.destroy(); this.outputBuffer?.destroy(); this.freqParamArray?.destroy(); this.kernelBuffer = null; this.kernelInfoBuffer = null; this.configBuffer = null; this.inputAudioBuffer = null; this.outputBuffer = null; this.freqParamArray = null; this.CQTpipeline = this.device = this.adapter = null; } } self.onmessage = async ({ data }) => { let { audioChannel, sampleRate, hop, fmin, useGPU } = data; const cqt = new CQT(sampleRate, fmin, 7, 12, 2.8); let cqtData; try { if (useGPU === false) throw new Error("强制使用CPU计算"); await cqt.initWebGPU(256); console.log("WebGPU初始化成功,使用GPU计算CQT"); const numFrames = cqt.cqt_GPU(audioChannel[0], hop); for (let i = 1; i < audioChannel.length; i++) { // 开启其他通道的计算 会累加到cqt.outputBuffer cqt.cqt_GPU(audioChannel[i], hop); } cqtData = await cqt.norm_CPU(cqt.outputBuffer, numFrames); cqt.freeGPU(); } catch (e) { console.log("使用CPU计算CQT\n原因:", e.message); cqtData = cqt.cqt(audioChannel[0], hop); for (let i = 1; i < audioChannel.length; i++) { // 开启其他通道的计算 会累加到cqtData.raw cqt.cqt(audioChannel[i], hop, cqtData.raw); } CQT.norm(cqtData.raw); } // 要求cqtData都是一整块 self.postMessage(cqtData, [cqtData.raw.buffer, ...audioChannel.map(x => x.buffer)]); self.close(); }; ================================================ FILE: dataProcess/NNLS.js ================================================ /** * 为密集计算设计的高性能非负最小二乘求解器 */ class NNLSSolver { /** * @param {number} K 个数 * @param {number} M 维度 * @param {number} lambda 正则化参数 防止不稳定 * @param {Float32Array|null} buffer_r 可选的外部残差缓冲区,长度应为M */ constructor(K, M, lambda = 1e-4, buffer_r = null) { this.K = K; this.M = M; this.lambda = lambda; // 预分配内存 this.c = new Float32Array(K); // 最终系数 (K) this.s = new Float32Array(K); // 候选系数 (K) this.w = new Float32Array(K); // 梯度 (K) this.residual = buffer_r ?? new Float32Array(M); // 增量残差 (M) this.matM = new Float32Array(M * M); // 正规方程矩阵 (M*M) this.rhsM = new Float32Array(M); // 正规方程右侧向量 (M) this.L = new Float32Array(M * M); // Cholesky 分解矩阵 (M*M) this.z = new Float32Array(M); // 临时连续解向量 (M) this.isP = new Uint8Array(K); this.pIdx = new Int32Array(M); } /** * 求解非负最小二乘问题 min ||Ax - b||_2^2 s.t. x >= 0 * @param {Float32Array} A 每M个数为一组,一共K组 * @param {Float32Array} b 长M * @returns {Float32Array} 长K的非负系数向量x 是this.c的引用 */ solve(A, b) { const { K, M, c, s, w, residual, isP, pIdx } = this; c.fill(0); isP.fill(0); residual.set(b); let pCount = 0; const tol = 1e-7 * M; // 根据维度动态调整容差 for (let iter = 0, maxIter = K << 1; iter < maxIter; iter++) { // 1. 计算梯度 w = A^T * residual let maxW = -1, jMax = -1; for (let j = 0; j < K; j++) { if (isP[j]) continue; let dot = 0; const offset = j * M; for (let i = 0; i < M; i++) dot += A[offset + i] * residual[i]; w[j] = dot; if (dot > maxW) { maxW = dot; jMax = j; } } if (jMax === -1 || maxW < tol) break; isP[jMax] = 1; pIdx[pCount++] = jMax; while (pCount > 0) { // 求解子问题,结果暂存在 s 中 if (!this._solveSubProblem(A, b, pCount, pIdx, s)) { const last = pIdx[--pCount]; isP[last] = c[last] = 0; break; } let alpha = 2.0; let hasConstraintViolation = false; for (let i = 0; i < pCount; i++) { const idx = pIdx[i]; if (s[idx] <= 0) { const ratio = c[idx] / (c[idx] - s[idx] + 1e-15); if (ratio < alpha) { alpha = ratio; hasConstraintViolation = true; } } } if (!hasConstraintViolation) { // 无冲突:更新残差并接受新系数 this._updateResidual(A, c, s, pCount, pIdx); for (let i = 0; i < pCount; i++) c[pIdx[i]] = s[pIdx[i]]; break; } // 有冲突:按 alpha 步长靠近,并剔除归零的变量 for (let i = 0; i < pCount; i++) { const idx = pIdx[i]; c[idx] += alpha * (s[idx] - c[idx]); } for (let i = 0; i < pCount; i++) { const idx = pIdx[i]; if (c[idx] < 1e-9) { // 稍微放宽归零判定 c[idx] = 0; isP[idx] = 0; pIdx[i] = pIdx[--pCount]; i--; } } this._fullResidualUpdate(A, b, c, pCount, pIdx); } } return c; } _solveSubProblem(A, b, n, pIdx, s) { const { M, matM, rhsM, L, z, lambda } = this; // 1. 构建正规方程 for (let i = 0; i < n; i++) { const offI = pIdx[i] * M; let dotB = 0; for (let r = 0; r < M; r++) dotB += A[offI + r] * b[r]; rhsM[i] = dotB; for (let j = 0; j <= i; j++) { const offJ = pIdx[j] * M; let dotA = 0; for (let r = 0; r < M; r++) dotA += A[offI + r] * A[offJ + r]; if (i === j) dotA += lambda; matM[i * n + j] = dotA; } } // 2. Cholesky 分解 for (let i = 0; i < n; i++) { for (let j = 0; j <= i; j++) { let sum = matM[i * n + j]; for (let k = 0; k < j; k++) sum -= L[i * n + k] * L[j * n + k]; if (i === j) { if (sum <= 0) return false; L[i * n + j] = Math.sqrt(sum); } else { L[i * n + j] = sum / L[j * n + j]; } } } // 3. 前向替换 (L * y = rhsM -> 结果存入 z) for (let i = 0; i < n; i++) { let sum = rhsM[i]; for (let k = 0; k < i; k++) sum -= L[i * n + k] * z[k]; z[i] = sum / L[i * n + i]; } // 4. 后向替换 (L^T * x = z -> 结果存入 z) for (let i = n - 1; i >= 0; i--) { let sum = z[i]; for (let k = i + 1; k < n; k++) sum -= L[k * n + i] * z[k]; z[i] = sum / L[i * n + i]; } // 5. 映射回原始大向量 s s.fill(0); // 必须清零,因为s共享 for (let i = 0; i < n; i++) { s[pIdx[i]] = z[i]; } return true; } _updateResidual(A, oldC, newS, n, pIdx) { const { M, residual } = this; for (let i = 0; i < n; i++) { const idx = pIdx[i]; const delta = newS[idx] - oldC[idx]; if (Math.abs(delta) < 1e-14) continue; const offset = idx * M; for (let r = 0; r < M; r++) residual[r] -= A[offset + r] * delta; } } _fullResidualUpdate(A, b, c, n, pIdx) { const { M, residual } = this; residual.set(b); for (let i = 0; i < n; i++) { const idx = pIdx[i]; if (c[idx] === 0) continue; const offset = idx * M; for (let r = 0; r < M; r++) residual[r] -= A[offset + r] * c[idx]; } } // 在调用 solve() 之后可以使用此函数获取当前残差的 L2 范数 calcError() { let sum = 0; for (let i = 0; i < this.M; i++) sum += this.residual[i] ** 2; return Math.sqrt(sum); } } ================================================ FILE: dataProcess/aboutANA.md ================================================ # JE数字谱自动对齐音频 Auto Note Alignment 2025/12/27 文章已经整理到知乎: https://zhuanlan.zhihu.com/p/1988276192063800011 下文为8/21刚完成算法时的整理: ----------------- - 问题:给定音高序列和时频谱,求对应关系。音频为polyphonic,还可能为多音色,而音高序列为monophonic,比如只有人声或某种乐器的。最终得到赋予时值信息的音符。此任务类似自动排布视频字幕。 - 输入:时频谱(而不是音频)、音高序列 - 输出:音符在时频谱上的坐标 - 定位:计算复杂度少于AMT(自动扒谱),最好不使用神经网络。因为如果AMT更快,就没必要让用户给出音高序列了。好比有自动识别、添加字幕功能时,用户就没必要重新打一遍字幕了。 ## 难点 - 音符之间可能需要插入“间隔” - 对于连续的同一音高的音符序列,如何断开 ## 最初建模:隐马尔可夫模型 HMM 使用时频谱的时间轴,每一帧的隐状态即为音符,目标是最大化全局概率。假设第t帧频谱为 $\vec{s}_t$ ,第t帧的隐状态记为 $v_t$ ,第i个音符(音高)为 $n_i$ ,间隔记为"O"。则有: $$ v_t = \begin{cases} n_i \rightarrow v_{t+1}=& \begin{cases} n_i:&保持不变\\ O:&间隔\\ n_{i+1}:&下一个音符 \end{cases}\\ \\ O \rightarrow v_{t+1}=& \begin{cases} O:&保持间隔\\ n_{i+1}:&下一个音符 \end{cases}\\ \end{cases}\tag{1} $$ HMM有三个要素:初始状态分布,状态转移矩阵,激发概率。 - 初始状态可以设置为"O"。 - 按照传统HMM的建模方法,每个音高都对应各自的状态,比如noteDigger有84个半音,则有(84+1)个状态(考虑了"O")。而用户给出的音符序列,相当于约束了状态转移矩阵。然而,由于每个音符的长度未定,同一个状态可能承载多种分支,使得状态转移矩阵无法构建:比如音符“123124”,第一条转移路径在t时到达第一个2,第二条转移路径在t时到达第二个2,那此时状态2的转移概率如何构建?显然此时两个分支的转移概率应该分开来算。因此,传统的HMM状态建模不可行。 - 激发概率难以合理设置。由于频谱状态空间无限大,必须动态求解。而频谱反应的是分量的幅度,值域为 $[0,+\infty)$,没有合理的、到 $[0, 1]$ 的映射。 ## 简化:DTW (失败) DTW 即 `Dynamic Time Warping`,常用于序列对齐。初见DTW是在MusicNet数据集中,DTW免去了人工的对齐,但也因此此数据集的精度不高。想到DTW是因为本任务就是两个序列的对齐:音高数组和(所有帧的)频谱(构成的)数组的对齐。 DTW也是状态的转移,不过将每个元素视为一个状态。上述传统HMM状态建模仅仅编码了`音高`,导致了时序的混乱;DTW相当于将 `(音高,顺序)` 作为整体编码,因此音高序列有多长,就有多少个状态。这一点值得学习。 DTW和HMM的Viterbi解码基本原理都是动态规划。如果将问题建模为使用上述状态编码的HMM,且状态转移概率均等,那就可以用DTW来解码路径。 相比于HMM使用激发概率,DTW使用距离(其实概率也可以算一种距离)。距离的好处是直接加减、没有范围限制,很容易从幅度谱中映射,比如我选择了用“当前频谱当前音高的幅度的相反数”,因为幅度越大表明越有可能有该音高,而“距离越大越不相似”与之相反,所以加个负号。 如何解决提到的难点?可以在每个音符之间插入一个"O"。那如果两个音符理应紧密相连怎么办?DTW中有一对多、多对一的情况,理论上不匹配的会被折叠,即"O"可以不出现。 最困难的是"O"到各个频谱的距离。最终我选择了频谱均值,在统计了一些数据后设置为0.08的相反数,这大概能代表整个时频谱每个单元的能量均值。 实现上为了减少空间复杂度,使用Hirschberg algorithm,虽然运算量*2,但节省了`帧数/2`倍的空间(帧数往往在4k以上)。 然而效果并不好,仅有局部可以对齐。我认为是DTW的无记忆性和缺少约束导致的: 1. 无记忆:特指求距离时仅依赖当前状态,缺少上一个状态。比如同为切换到"O",从音符切换到"O"时的距离应该和“音符和频谱的距离”有关,因为是音符的结尾;而若上一个状态就是"O",此时的距离应该和“下一个音符和频谱的距离”有关,因为要识别下一个音符的开头。 2. 缺少约束:比如结果中出现了宽度为0的音符,这是被折叠了,而实际音符应该有长度约束。 长度约束可以在DTW的路径回溯添加,具体为限制音符的回溯方向。而使用Hirschberg algorithm的DTW无法解决“无记忆”的问题,因为此算法不按顺序,根基就是“DTW的无记忆距离计算”。为此只能回到DTW最初的实现。而要增加的记忆的作用是可以利用上一帧的状态计算本帧本状态的距离,意味着距离和路径有关。这会导致什么呢?比如考虑下面的D格: | 累积距离 | 上一帧 | 当前帧 | | - | ----- | ------ | | 状态X | A: -1 | B: -2 | | 状态Y | C: -3 | D: ? | | 方向 | 距离增加 | | --- | -------- | | A→D | -5 | | B→D | -3 | | C→D | -1 | 一通计算发现应该选A→D,更新D的距离为-6。但在DTW的路径回溯中,上一步选择的是距离最小值,因此D的上一步会选择C,而不是计算距离用的A。因此DTW整个框架是没法引入记忆的。 ## 融合HMM和DTW DTW被其路径回溯限制,那我们可以改成Viterbi算法的路径记录啊~于是回归HMM建模与Viterbi解码。 状态设置同DTW,即首先给音符序列间插"O",然后每个元素作为一个状态。 此时可以设置状态转移概率了,即给式(1)中每一行设置一个概率,具体为多少可以根据实验调参。马尔可夫链基于概率,是累乘的,但只要取对数就变成了DTW的累加。问题是如何得到合理的激发概率。 映射的难点在于无界到有界,而对于实际的样本其实最大值就是上界。所以我使用样本的最值作为边界、线性缩放至 $[0, 1]$。当然样本的最值取的不是所有时频单元的最值,而是时频谱中音高序列中出现的音高能取到的最值。但这样的概率合理吗? 我统计了一下每帧能量的分布,近似为卡方分布。每一个时频单元的能量分布应该也近似(没统计)。这意味着能量大的单元少,而中间或者低能单元的数目多。所以简单的线性缩放会导致大量单元的概率仅在0.5以下,所以我选择了再开根号。假设给出时频谱 $s_{t,f}\in R^{T \times F}$ 和音高序列 $\vec{n} \in Z^N$(为了下标方便,不考虑间插的"O";在$n_i$和$n_{i+1}$之间的间隔记为$O_i$),可以这样得到 $n_i \in Z$ 激发出 $\vec{s}_t \in R^F$ 的概率: $$ Amp = \max_{t,i} s_{t,n_i}, \\ amp = \min_{t,i} s_{t,n_i}, \\ t \in 1,2,3,...,T\\ i \in 1,2,3,...,N \\ p(\vec{s}_t | n_i) = (\frac{s_{t,n_i}-amp}{Amp - amp})^{0.5} $$ 假设$t$时刻的状态为$u_t$,定义 $p_{keepO}$ 为当前为“O”时保持为“O”的概率,$p_{keepN}$ 为当前为音符时保持音符的概率,则从 $t$ 到 $t+1$ 的转移概率如下。注意,虽然这里称之为“转移概率”,但下式其实对应于HMM的“激发概率”ד转移概率”,将两步结合起来了: $$ \begin{aligned} p(u_{t+1}=n_{i+1} | u_t=O_i) &= p(\vec{s}_t | n_{i+1}) \cdot (1 - p_{keepO})\\ p(u_{t+1}=O_i | u_t=O_i) &= 1 - p(\vec{s}_t | n_{i+1}) \cdot p_{keepO}\\ p(u_{t+1}=O_i | u_t=n_i) &= (1 - p(\vec{s}_t | n_i)) \cdot (1 - p_{keepN})\\ p(u_{t+1}=n_{i} | u_t=n_i) &= p(\vec{s}_t | n_i) \cdot p_{keepN}\\ p(u_{t+1}=n_{i+1} | u_t=n_i) &= (1 - p(\vec{s}_t | n_i)) \cdot p(\vec{s}_t | n_{i+1}) \cdot p_{NN}\\ &:= p(u_{t+1}=O_i | u_t=n_i) \cdot p(u_{t+1}=n_{i+1} | u_{t+1}=O_i) \end{aligned} $$ 注意最后一行,转移判定是“不是$n_i$且是$n_{i+1}$”,所以是两个相乘,进而发现其实是转移两次的结果,实际实现中,对每一轮动规,先进行沿着时间的转移,再保持时间不变,进行沿着状态的转移,且仅对“O”状态开展后一轮转移。拆解为两次转移可以避免跨状态转移,保持了每次转移的一阶马尔科夫性。 实际应用中的状态转移和式(1)有不同。首先添加长度约束。需要记录当前音符状态(不考虑"O"的长度约束)已经保持了多长,小于最小长度时设置为99%的概率继续延续。 其次是转移方式。先做如下约定: - 从左到右——时频谱从开始到结尾 - 从上到下——音符序列从开始到结尾 - 起点:左上角;终点:右下角 输入的音符序列已经间插了"O"了,如果当前是音符,直接跳到下一个音符需要跨一行更新,不优雅;遇到边界还需要重新调整转移概率,麻烦。而从 $p(v_{t+1}=n_{i+1} | v_t=n_i)$ 的表达式可以看出,到音符的转移可以建立在到"O"的基础上。于是有了以下设计: 1. 只允许向右和右下转移,转移概率和为1。这保证了音符不会被折叠。 2. 同一列中,允许"O"向下转变,可以设置一个转变概率。这保证了"O"可以被折叠 3. 最终取最大值,并记录上一步。 “转变”其实不是很严谨,等效到状态转移相当于总概率超过1了。 最终效果优于DTW,人肉调参许久得到了如今使用的参数。 ================================================ FILE: dataProcess/analyser.js ================================================ class FreqTable extends Float32Array { constructor(A4 = 440) { super(84); // 范围是C1-B7 this.A4 = A4; } set A4(A4) { // 负数强制更新 if (A4 == this.A4) return; if (A4 < 0) A4 = -A4; let Note4 = [ A4 * 0.5946035575013605, A4 * 0.6299605249474366, A4 * 0.6674199270850172, A4 * 0.7071067811865475, A4 * 0.7491535384383408, A4 * 0.7937005259840998, A4 * 0.8408964152537146, A4 * 0.8908987181403393, A4 * 0.9438743126816935, A4, A4 * 1.0594630943592953, A4 * 1.122462048309373 ]; this.set(Note4.map(v => v / 8), 0); this.set(Note4.map(v => v / 4), 12); this.set(Note4.map(v => v / 2), 24); this.set(Note4, 36); this.set(Note4.map(v => v * 2), 48); this.set(Note4.map(v => v * 4), 60); this.set(Note4.map(v => v * 8), 72); } get A4() { return this[45]; } } class NoteAnalyser { // 负责解析频谱数据 /** * @param {number} df FFT的频率分辨率 * @param {FreqTable || Number} freq 频率表(将被引用)或中央A的频率 */ constructor(df, freq) { this.df = df; if (typeof freq === 'number') { this.freqTable = new FreqTable(freq); } else { this.freqTable = freq; } this.updateRange(); } set A4(freq) { this.freqTable.A4 = freq; this.updateRange(); } get A4() { return this.freqTable.A4; } /** * 创建从线性谱到CQ谱的加权矩阵 * @param {number} semiR 每个半音收集的频率范围 单位:半音 取0.5时半音间无重合 * @param {number} leakR 频谱泄露半径 单位:每FFT精度 * @param {number} oversample 过采样率 用于模拟泄露 */ updateRange(semiR = 0.667, leakR = 1, oversample = 32) { const win = this.win = Array(this.freqTable.length); const offset = this.offset = new Uint16Array(this.freqTable.length); // 用余弦模拟FFT的频率泄漏(FFT使用hanning窗) const H_fft = new Float32Array((oversample << 1) | 1); // 跳过两端的0 for (let i = 0, j = H_fft.length - 1, w = Math.PI / (oversample + 1); i < oversample; i++, j--) { H_fft[i] = H_fft[j] = (1 - Math.cos((i + 1) * w)) * 0.5; } H_fft[oversample] = 1; const over_df = this.df * leakR / (oversample + 1); // 用对数谱的余弦收集能量 新坐标u=B*log2(x/center) B=12 // du/dx = B/log(2)/x 每Hz对应的半音数 代表占据能量的宽度 const omega = Math.PI / semiR; function pitchCospuls(x, center) { if (x <= 0) return 0; let wrapedf = 12 * Math.log2(x / center); // 半音距离 if (Math.abs(wrapedf) >= semiR) return 0; // 余弦窗*du/dx 余弦周期为2表示相邻半音 常数项不管 会归一化 return (Math.cos(wrapedf * omega) + 1) / x; } const tuning = 2 ** (semiR / 12); // 半音范围对应的频率倍数 const leak_f = over_df * oversample;// 模拟泄露的频率范围 for (let i = 0; i < offset.length; i++) { let fc = this.freqTable[i]; let start = fc / tuning; let end = fc * tuning; start = offset[i] = Math.ceil((start - leak_f) / this.df); end = Math.floor((end + leak_f) / this.df) + 1; const H = win[i] = new Float32Array(end - start); for (let j = start, id = 0; j < end; j++, id++) { // 对每个fft中心频点计算贡献: \sum 泄露*窗值 for (let hid = 0, f = j * this.df - oversample * over_df; hid < H_fft.length; f += over_df, hid++) H[id] += pitchCospuls(f, fc) * H_fft[hid]; } // 幅度一致性: 频率越高窗越大 for (let j = 0; j < H.length; j++) H[j] *= fc; } } /** * 从FFT提取音符的频谱 原理是区间内求和 * @param {Float32Array} real 实部 * @param {Float32Array} imag 虚部 * @param {Float32Array} buffer 可选的缓冲区 避免重复分配 * @returns {Float32Array} 音符的幅度谱 */ mel(real, imag, buffer = null) { const noteAm = buffer ?? new Float32Array(84); for (let i = 0; i < this.freqTable.length; i++) { const H = this.win[i]; const offset = this.offset[i]; for (let j = 0; j < H.length; j++) { const eng = real[offset + j] * real[offset + j] + imag[offset + j] * imag[offset + j]; noteAm[i] += eng * H[j]; } } return noteAm; } // 上面函数的平方和版本 mel2(eng, buffer = null) { const noteAm = buffer ?? new Float32Array(84); for (let i = 0; i < this.freqTable.length; i++) { const H = this.win[i]; const offset = this.offset[i]; for (let j = 0; j < H.length; j++) { noteAm[i] += eng[offset + j] * H[j]; } } return noteAm; } /** * 能量谱归一化 Welford计算std * @param {Array} engSpectrum 能量谱 */ static normalize(engSpectrum) { let count = 0, mean = 0, M2 = 0; for (const frame of engSpectrum) { for (let i = 0; i < frame.length; i++) { const x = frame[i]; count++; const delta = x - mean; mean += delta / count; const delta2 = x - mean; M2 += delta * delta2; } } const invSigma = Math.sqrt(count / M2); for (const frame of engSpectrum) { for (let i = 0; i < frame.length; i++) frame[i] = Math.sqrt(frame[i] * invSigma); } return engSpectrum; } /** * 调性分析,原理是音符能量求和 * @param {Array} noteTable * @returns {Array} 调性和音符的能量 */ static Tonality(noteTable) { let energy = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (const atime of noteTable) { energy[0] += atime[0] ** 2 + atime[12] ** 2 + atime[24] ** 2 + atime[36] ** 2 + atime[48] ** 2 + atime[60] ** 2 + atime[72] ** 2; energy[1] += atime[1] ** 2 + atime[13] ** 2 + atime[25] ** 2 + atime[37] ** 2 + atime[49] ** 2 + atime[61] ** 2 + atime[73] ** 2; energy[2] += atime[2] ** 2 + atime[14] ** 2 + atime[26] ** 2 + atime[38] ** 2 + atime[50] ** 2 + atime[62] ** 2 + atime[74] ** 2; energy[3] += atime[3] ** 2 + atime[15] ** 2 + atime[27] ** 2 + atime[39] ** 2 + atime[51] ** 2 + atime[63] ** 2 + atime[75] ** 2; energy[4] += atime[4] ** 2 + atime[16] ** 2 + atime[28] ** 2 + atime[40] ** 2 + atime[52] ** 2 + atime[64] ** 2 + atime[76] ** 2; energy[5] += atime[5] ** 2 + atime[17] ** 2 + atime[29] ** 2 + atime[41] ** 2 + atime[53] ** 2 + atime[65] ** 2 + atime[77] ** 2; energy[6] += atime[6] ** 2 + atime[18] ** 2 + atime[30] ** 2 + atime[42] ** 2 + atime[54] ** 2 + atime[66] ** 2 + atime[78] ** 2; energy[7] += atime[7] ** 2 + atime[19] ** 2 + atime[31] ** 2 + atime[43] ** 2 + atime[55] ** 2 + atime[67] ** 2 + atime[79] ** 2; energy[8] += atime[8] ** 2 + atime[20] ** 2 + atime[32] ** 2 + atime[44] ** 2 + atime[56] ** 2 + atime[68] ** 2 + atime[80] ** 2; energy[9] += atime[9] ** 2 + atime[21] ** 2 + atime[33] ** 2 + atime[45] ** 2 + atime[57] ** 2 + atime[69] ** 2 + atime[81] ** 2; energy[10] += atime[10] ** 2 + atime[22] ** 2 + atime[34] ** 2 + atime[46] ** 2 + atime[58] ** 2 + atime[70] ** 2 + atime[82] ** 2; energy[11] += atime[11] ** 2 + atime[23] ** 2 + atime[35] ** 2 + atime[47] ** 2 + atime[59] ** 2 + atime[71] ** 2 + atime[83] ** 2; } // notes根据最大值归一化 let max = Math.max(...energy); energy = energy.map((num) => num / max); // 找到最大的前7个音符 const sortedIndices = energy.map((num, index) => index) .sort((a, b) => energy[b] - energy[a]) .slice(0, 7); sortedIndices.sort((a, b) => a - b); // 判断调性 let tonality = sortedIndices.map((num) => { return num.toString(16); }).join(''); switch (tonality) { case '024579b': tonality = 'C'; break; case '013568a': tonality = 'C#'; break; case '124679b': tonality = 'D'; break; case '023578a': tonality = 'Eb'; break; case '134689b': tonality = 'E'; break; case '024579a': tonality = 'F'; break; case '13568ab': tonality = 'Gb'; break; case '024679b': tonality = 'G'; break; case '013578a': tonality = 'Ab'; break; case '124689b': tonality = 'A'; break; case '023579a': tonality = 'Bb'; break; case '13468ab': tonality = 'B'; break; default: tonality = 'Unknown'; break; } return [tonality, energy]; } /** * 标记大于阈值的音符 * @param {Array} noteTable 时频图 * @param {number} threshold 阈值 * @param {number} from * @param {number} to * @returns {Array} {x1,x2,y,ch,selected} */ static autoFill(noteTable, threshold, from = 0, to = 0) { let notes = []; let lastAt = new Uint16Array(noteTable[0].length).fill(65535); let time = from; // 迭代器指示 if (!to || to > noteTable.length) to = noteTable.length; for (; time < to; time++) { const t = noteTable[time]; for (let i = 0; i < lastAt.length; i++) { let now = t[i] < threshold; // 现在不达标 if (lastAt[i] != 65535) { if (now) { notes.push({ // 上一次有但是这次没有 y: i, x1: lastAt[i], x2: time, ch: -1, selected: false }); lastAt[i] = 65535; } } else if (!now) lastAt[i] = time; // 上次没有这次有 } } // 扫尾 for (let i = 0; i < lastAt.length; i++) { if (lastAt[i] != 65535) notes.push({ y: i, x1: lastAt[i], x2: time, ch: -1, selected: false }); } return notes; } } ================================================ FILE: dataProcess/bpmEst.js ================================================ /// /** * @file bpmEst.js * @abstract BPM估计相关算法 * @description 算法说明: https://zhuanlan.zhihu.com/p/1995849093491222501 */ class SIGNAL { /** * 峰值检测 * @param {Float32Array} arr 输入数据 * @param {number} prominence 显著性阈值 * @returns {Array} 找到的峰值索引数组 从小到大 */ static findPeaks(arr, prominence = 0) { const len = arr.length; const outBuffer = []; for (let i = 1; i < len - 1; i++) { const current = arr[i]; if (current <= arr[i - 1] || current <= arr[i + 1]) continue; // 查找左侧基准 let l = i - 1; while (l > 0 && arr[l - 1] <= arr[l]) l--; // 查找右侧基准 let r = i + 1; while (r < len - 1 && arr[r + 1] <= arr[r]) r++; // 计算显著性 const leftMin = arr[l]; const rightMin = arr[r]; const maxBase = leftMin > rightMin ? leftMin : rightMin; if (current - maxBase >= prominence) outBuffer.push(i); } return outBuffer; } /** * 抛物线插值,返回相对于x2的偏移量 * @param {number} y1 * @param {number} y2 极值点 * @param {number} y3 * @returns {Array} [峰值相对于x2的偏移量, 插值后的y值] */ static parabolicInterpolation(y1, y2, y3) { const a = y1 + y3 - 2 * y2; const b = y1 - y3; if (a === 0) return [0, y2]; const dx = b / (2 * a); const y = y2 - b * dx * 0.25; return [dx, y]; } /** * IIR滤波器实现(直接型II结构,支持任意阶数) * @param {Float32Array} arr 输入信号 * @param {Array} b 分子系数(b[0], b[1], ..., b[M]) * @param {Array} a 分母系数(a[0], a[1], ..., a[N]),a[0]通常为1,会自动归一化 * @param {boolean} inplace 是否就地滤波(修改输入数组) * @param {boolean} reverse 是否反向滤波(用于filtfilt) * @returns {Float32Array} 滤波后信号 * @example 二阶高通滤波器 * 差分方程: * y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2] * 对应传参: * b = [b0, b1, b2] * a = [1, a1, a2] */ static filter(arr, b, a, inplace = false, reverse = false) { const order = Math.max(b.length, a.length); const result = inplace ? arr : (new Float32Array(arr.length)); const xHist = new Float32Array(order); const yHist = new Float32Array(order); let xPtr = 0, yPtr = 0; const processSample = (n) => { xHist[xPtr] = arr[n]; let y = 0; for (let i = 0; i < b.length; i++) y += b[i] * xHist[(xPtr - i + order) % order]; for (let i = 1; i < a.length; i++) y -= a[i] * yHist[(yPtr - i + order) % order]; y /= a[0]; yHist[yPtr] = y; result[n] = y; // 不用取余 加速 if (++xPtr >= order) xPtr = 0; if (++yPtr >= order) yPtr = 0; } if (reverse) { for (let n = arr.length - 1; n >= 0; n--) processSample(n); } else { for (let n = 0; n < arr.length; n++) processSample(n); } return result; } /** * 自相关函数 点积,进行了幅度补偿和归一化 * 通常用于较长序列 * @param {Float32Array} arr 输入一维时序信号 * @param {number} points 偏移点数 * @param {Float32Array} result 可选的输出数组 * @returns {Float32Array} 有效长度为 points */ static autoCorr(arr, points, result = undefined) { const L = arr.length; if (result === undefined || result.length < points) result = new Float32Array(points); // 先计算直流量用于幅度补偿 let mean = 0; for (let i = 0; i < L; i++) mean += arr[i] * arr[i]; mean = L / mean; result[0] = 1; // 计算各个tau的自相关值 for (let tau = 1; tau <= points; tau++) { let ac = 0; for (let n = L - tau - 1; n >= 0; n--) ac += arr[n] * arr[n + tau]; result[tau] = ac * mean / (L - tau); } return result; } /** * 高效的分帧自相关 * @param {Float32Array} arr onset envelop * @param {number} points 进行多少点的自相关 * @param {number} hopInWin 窗长内有几个hop * @param {number} hop 每次移动多少 * @returns {Array} 自相关帧数组 */ static autoCorrSeg(arr, points, hopInWin, hop = 1) { const len = arr.length; hopInWin = Math.max(1, hopInWin | 0); const numFrames = Math.floor((len - points) / hop) - hopInWin + 1; if (numFrames < 1) throw new Error("Input array too short"); const frames = Array(numFrames); for (let i = 0; i < numFrames; i++) { frames[i] = new Float32Array(points); } // 预分配一个通用的 bins 数组,避免在 tau 循环中重复创建 const maxBinCount = Math.ceil(len / hop); const bins = new Float32Array(maxBinCount); for (let tau = 0; tau < points; tau++) { // 预计算当前 tau 下的所有 bins const currentBinCount = Math.floor((len - tau) / hop); for (let b = 0, start = 0; b < currentBinCount; b++) { let binSum = 0; // 内部小循环计算一个 hop 长度的乘积和 for (let n = 0; n < hop; n++, start++) { binSum += arr[start] * arr[start + tau]; } bins[b] = binSum; } // 初始窗口的和 (第一个 frame) let running = 0; for (let f = 0; f < hopInWin; f++) { running += bins[f]; } frames[0][tau] = running; // 滑动更新后续 frame for (let frameIdx = 1; frameIdx < numFrames; frameIdx++) { running += bins[frameIdx + hopInWin - 1] - bins[frameIdx - 1]; frames[frameIdx][tau] = running; } } // 归一化 for (let f = 0; f < numFrames; f++) { const frame = frames[f]; const energy = frame[0]; if (energy < 1e-10) continue; const invEnergy = 1 / energy; frame[0] = 1; for (let tau = 1; tau < points; tau++) { frame[tau] *= invEnergy; } } return frames; } /** * 根据分析窗和hop长度生成配套的ISTFT合成窗 * @param {Float32Array} analysisWindow 分析阶段使用的窗 * @param {number} hop 跳跃长度 * @returns {Float32Array} 合成窗 */ static createSynthesisWindow(analysisWindow, hop) { const n = analysisWindow.length; const res = new Float32Array(n); let h = 0; for (let i = 0; i < n; i++) { const val = analysisWindow[i]; res[h] += val * val; if (++h === hop) h = 0; } // 将能量和转换为倒数 减少除法次数 for (let i = 0; i < hop; i++) { const s = res[i]; res[i] = s > 1e-10 ? 1.0 / s : 0; } // 生成最终合成窗 必须从后往前遍历 (n-1 到 0) h = (n - 1) % hop; for (let i = n - 1; i >= 0; i--) { res[i] = analysisWindow[i] * res[h]; if (--h < 0) h = hop - 1; } return res; } } class Beat { /** * 根据采样率得到适合的FFT长度 * @param {number} fs onset的采样率 * @param {number} sec 音频长度(秒) * @returns {number} FFT的大小 */ static fs2FFTN(fs, sec = 50) { let n = fs * sec; // 用50秒的音频,分辨率大概有1.2BPM return 1 << Math.round(Math.log2(n)); } /** * 压缩异常大的值 原位操作 * @param {Float32Array} onsetEnv * @param {number} percent 分位数 * @param {number} margin_ratio 允许超出的最大比例 大于1 * @returns {Float32Array} onsetEnv 返回同一个引用 */ static compressOutliers(onsetEnv, percent = 0.99, margin_ratio = 1.3) { // 理论上可以用堆排序只找后1%,但是sort底层是C++实现的,性能已经足够好了 const sorted = Array.from(onsetEnv).sort((a, b) => a - b); const margin = sorted[(sorted.length * percent) | 0]; // floor会使得索引一定存在 const marginMax = margin * margin_ratio; const actualMax = sorted[sorted.length - 1]; if (actualMax <= marginMax) return onsetEnv; // 用三次函数压缩 const x0 = actualMax - margin; const y0 = marginMax - margin; const a = (x0 - 2 * y0) / (x0 * x0 * x0); const b = (3 * y0 - 2 * x0) / (x0 * x0); const trans = (x) => x * (a * x * x + b * x + 1); for (let i = 0; i < onsetEnv.length; i++) { if (onsetEnv[i] > margin) onsetEnv[i] = trans(onsetEnv[i] - margin) + margin; } return onsetEnv; } /** * 高通滤波去除趋势 原位操作 * @param {Float32Array} onsetEnv * @returns {Float32Array} 去趋势后的onsetEnv 同一个引用 */ static detrend(onsetEnv) { // 对于20Hz采样的频谱,用0.96对低频的压制较好 0.9低频压制太多 0.99低频压制太少 const b = [1, -1]; const a = [1, -0.96]; // filtfilt SIGNAL.filter(onsetEnv, b, a, true, false); SIGNAL.filter(onsetEnv, b, a, true, true); return onsetEnv; } /** * 除以标准差并保持非负 原位操作 * @param {Float32Array} onsetEnv * @returns {Float32Array} onsetEnv 同一个引用 */ static onsetNorm(onsetEnv) { let std = 0; let minVal = Infinity; let mean = 0; for (const v of onsetEnv) { mean += v; std += v * v; if (v < minVal) minVal = v; } mean /= onsetEnv.length; std = Math.sqrt(std / onsetEnv.length - mean * mean); for (let i = 0; i < onsetEnv.length; i++) { onsetEnv[i] = (onsetEnv[i] - minVal) / std; } return onsetEnv; } /** * 对数谱差分法提取 onset envelope * 会进行抑制峰值、去趋势、std归一化、非负化 * @param {Array} spectrogram 幅度谱 * @param {number} a 平滑系数 0~1 越大越不平滑 * @returns {Float32Array} onset envelope */ static extractOnset(spectrogram, a = 0.8) { const ra = 1 - a; const onsetEnv = new Float32Array(spectrogram.length); const prevFrame = new Float32Array(spectrogram[0].length); prevFrame.fill(Math.log(1e-2)); // 防止一开始就有大变化 for (let i = 0; i < spectrogram.length; i++) { const frame = spectrogram[i]; let diff = 0; for (let j = 0; j < frame.length; j++) { const logedValue = Math.log(frame[j] + 1e-6); const delta = logedValue - prevFrame[j]; if (delta > 0) diff += delta; // 滑动更鲁棒 prevFrame[j] = prevFrame[j] * ra + logedValue * a; } onsetEnv[i] = diff; } // 抑制峰值 Beat.compressOutliers(onsetEnv, 0.99, 1.3); // 去趋势 Beat.detrend(onsetEnv); // 归一化并非负化 return Beat.onsetNorm(onsetEnv); } /** * 浮点数最大公因数 * @param {Float32Array} idx 峰值序号数组 * @param {Uint8Array} N 可选的倍数数组 * @returns {number} 最大公因数 */ static floatGCD(idx, N) { // 用最小间隔估计一个初始值 这里假设一次差分就能获取 let minInterval = idx[0]; for (let i = 1; i < idx.length; i++) { let inter = idx[i] - idx[i - 1]; if (inter < minInterval) minInterval = inter; } // 计算各个idx对应的倍数 并动态修正 minInterval if (N === undefined) N = new Uint8Array(idx.length); for (let i = 0; i < idx.length; i++) { const n = Math.round(idx[i] / minInterval); N[i] = n; // 修正 minInterval 因为距离越远误差越小 minInterval = (minInterval + idx[i] / n) * 0.5; } // MSE求最佳 minInterval let a = 0, b = 0; for (let i = 0; i < idx.length; i++) { a += N[i] * N[i]; b += N[i] * idx[i]; } return b / a; } /** * 对自相关结果进行BPM估计 * 从自相关结果中找到BPM峰值 * @param {Float32Array} corr 自相关结果 * @param {number} sr 采样率 * @param {number} BPMstd BPM的标准差 用于高斯加权 * @param {number} BPMu 期望的BPM值 用于高斯加权 * @returns {number} 估计的BPM值 如果无法估计则返回NaN */ static corrBPM(corr, sr, BPMstd = 1, BPMu = 110) { if (corr.length < 3) throw new Error("Correlation array too short"); const maxInterval = Math.ceil(60 * sr / 35) + 1; // 35 BPM对应的最大间隔 更低的不管 if (corr.length > maxInterval) corr = corr.subarray(0, maxInterval); // 峰值插值 let peakIdx = SIGNAL.findPeaks(corr, 0.02); if (peakIdx.length === 0) return NaN; // 置信度太小了,无法估计 const peak = new Float32Array(peakIdx.length); for (let i = 0; i < peakIdx.length; i++) { const idx = peakIdx[i]; const [dx, y] = SIGNAL.parabolicInterpolation( corr[idx - 1], corr[idx], corr[idx + 1] ); peakIdx[i] = idx + dx; peak[i] = y; } // 得到候选BPM const N = new Uint8Array(peakIdx.length); const nBPM = 60 * sr / Beat.floatGCD(peakIdx, N); // 一定是整数倍 // 选择最显著的BPM 用高斯权重 let bestBPM = nBPM, maxVal = -1; BPMu = Math.log2(BPMu); for (let i = 0; i < peakIdx.length; i++) { const bpm = nBPM / N[i]; // 候选BPM const k = (Math.log2(bpm) - BPMu) / BPMstd; const q = peak[i] * Math.exp(-0.5 * k * k); if (q > maxVal) { maxVal = q; bestBPM = bpm; } } return bestBPM; } /** * 估计每帧的BPM值 * @param {Float32Array} onsetEnv extractOnset的结果 * @param {number} onset_sr 采样率 * @param {number} minBPM 允许的最小BPM值 用于得到autoCorrSeg的points参数 * @param {number} winSec 窗口长度(秒)实际使用时会向上调整为hop的整数倍 * @param {number} hopSec hop长度(秒) * @param {number} centerBPM corrBPM的BPMu参数 * @param {number} BPMstd corrBPM的BPMstd参数 * @returns {Float32Array} 每帧的BPM估计值 */ static tempo(onsetEnv, onset_sr, minBPM, winSec, hopSec = 1, centerBPM = 110, BPMstd = 0.5) { // 确保winLen是hop的整数倍 const hop = Math.max(1, Math.round(onset_sr * hopSec)); const hopInWin = Math.ceil(winSec / hopSec); const winLen = hopInWin * hop; const maxInterval = Math.ceil(onset_sr * 60 / minBPM) + 1; const corrFrames = SIGNAL.autoCorrSeg(onsetEnv, maxInterval, hopInWin, hop); let f = winLen >> 1; const BPMt = new Float32Array(onsetEnv.length); let validBPM = centerBPM; // 如果都是NaN只能相信给的值 let NanIdx = []; for (let i = 0; i < corrFrames.length; f += hop, i++) { const bpm = Beat.corrBPM(corrFrames[i], onset_sr, BPMstd, centerBPM); if (isNaN(bpm)) { NanIdx.push(f); continue; } validBPM = BPMt[f] = bpm; centerBPM = centerBPM * 0.8 + BPMt[f] * 0.2; // 动态更新中心BPM } // 处理可能的NaN for (let a = NanIdx.length - 1; a >= 0; a--) BPMt[NanIdx[a]] = BPMt[NanIdx[a + 1]] || validBPM; const endAt = f; // 其余位置证据不足,直接复制邻近值 for (f += 1 - hop; f < onsetEnv.length; f++) BPMt[f] = BPMt[f - 1]; for (f = winLen >> 1; f > 0; f--) BPMt[f - 1] = BPMt[f]; // 中间用线性插值 if (hop === 1) return BPMt; f = winLen >> 1; let lastVal = BPMt[f]; let nextIdx = f + hop; while (nextIdx < endAt) { const nextVal = BPMt[nextIdx]; const step = (nextVal - lastVal) / hop; for (let i = 1; i < hop; i++) BPMt[f + i] = lastVal + step * i; f = nextIdx; lastVal = nextVal; nextIdx += hop; } return BPMt; } /** * Ellis节拍追踪算法实现 * @param {Float32Array} onsetEnv extractOnset的结果 * @param {number} onset_sr 采样率 * @param {number} tightness 动态规划的超参数 越大表示越尊重给出的节奏估计 * @param {number|Float32Array} bpm 单值:负数表示偏好,正值表示估计; Float32Array:每帧BPM估计 * @param {Array|null} rangeBPM [MinBPM, MaxBPM] 搜索范围 传入null表示范围无限制 * 以下参数仅在bpm为负数时有效 * @param {number} winSec 进行自相关的窗口长度(秒) * @param {number} hopSec 自相关的hop长度(秒) * @returns {Array} 识别到的节拍索引数组 */ static EllisBeatTrack(onsetEnv, onset_sr, tightness = 100, bpm = -110, rangeBPM = [40, 200], winSec = 16, hopSec = 1) { const sr60 = onset_sr * 60; const frameRange = (rangeBPM === null) ? [1, Infinity] : [sr60 / rangeBPM[1], sr60 / rangeBPM[0]]; if (typeof bpm === "number") { if (bpm > 0) return Beat.beatTrackDp( // 平滑以鲁棒 Beat.beatLocalScore(onsetEnv, bpm), sr60 / bpm, frameRange, tightness ); // bpm < 0 偏好模式 const BPMt = Beat.tempo(onsetEnv, onset_sr, rangeBPM[0], winSec, hopSec, -bpm); for (let i = 0; i < BPMt.length; i++) BPMt[i] = sr60 / BPMt[i]; // 转换为 帧/拍 return Beat.beatTrackDp( Beat.beatLocalScore(onsetEnv, BPMt), BPMt, frameRange, tightness ); } if (bpm.length !== onsetEnv.length) throw new Error("bpm length must match onsetEnv length"); const fpb = new Float32Array(bpm.length); for (let i = 0; i < bpm.length; i++) fpb[i] = sr60 / bpm[i]; return Beat.beatTrackDp( Beat.beatLocalScore(onsetEnv, fpb), fpb, frameRange, tightness ); } /** * 对onset进行平滑,得到局部节拍得分 * 直接抄袭的librosa的实现 * @param {Float32Array} onsetEnvelope * @param {number|number[]|Float32Array} framesPerBeat 每拍帧数,可以是单值或与onsetEnvelope等长的数组 * @returns {Float32Array} 平滑后的局部节拍得分 */ static beatLocalScore(onsetEnvelope, framesPerBeat) { const N = onsetEnvelope.length; const localscore = new Float32Array(N); if (typeof framesPerBeat === "number") framesPerBeat = [framesPerBeat]; let window = null; const getWindow = (fpb) => { const halfK = fpb | 0; const K = (halfK << 1) | 1; if (window === null || window.length < K) window = new Float32Array(K); const scale = 24 / fpb; // 越大意味着越窄 // librosa没有对窗进行归一化 会导致对低节拍的偏好 let sum = 0; for (let i = 0, j = -halfK; i < K; ++i, ++j) { const x = j * scale; sum += window[i] = Math.exp(-0.5 * x * x); } for (let i = 0; i < K; i++) window[i] /= sum; return { K, halfK }; }; if (framesPerBeat.length === 1) { // --- 静态节奏模式 --- const { K, halfK } = getWindow(framesPerBeat[0]); for (let i = 0; i < N; i++) { let sum = 0; const kMax = Math.min(i + halfK, K); for (let k = Math.max(0, i + halfK - N + 1); k < kMax; k++) { sum += window[k] * onsetEnvelope[i + halfK - k]; } localscore[i] = sum; } } else if (framesPerBeat.length === N) { // --- 动态节奏模式 --- let lastFpb = -1; let K, halfK; for (let i = 0; i < N; i++) { const currentFpb = Math.round(framesPerBeat[i]); // 只有当 fpb 变化时才更新窗口 if (currentFpb !== lastFpb) { const res = getWindow(currentFpb); K = res.K; halfK = res.halfK; lastFpb = currentFpb; } let sum = 0; const kMax = Math.min(i + halfK, K); for (let k = Math.max(0, i + halfK - N + 1); k < kMax; k++) { sum += window[k] * onsetEnvelope[i + halfK - k]; } localscore[i] = sum; } } else throw new Error('framesPerBeat 长度必须为 1 或与 onsetEnvelope 等长'); return localscore; } /** * 节拍追踪动态规划核心逻辑 (Ellis 算法) * @param {Float32Array} localscore 平滑后的起始强度 (beatLocalScore 的输出) * @param {Float32Array|number[]|number} framesPerBeat 每拍帧数 (1个或N个) 可以为浮点 * @param {number[]} frameRange 帧范围 [minFrame, maxFrame] 都包含 * @param {number} tightness 转移代价权重 * @returns {Array} 识别到的节拍索引数组 */ static beatTrackDp(localscore, framesPerBeat, frameRange = [1, Infinity], tightness = 110) { if (typeof framesPerBeat === "number") framesPerBeat = [framesPerBeat]; const isDynamicTempo = framesPerBeat.length > 1; const minFrame = Math.max(1, frameRange[0]) | 0; const maxFrame = Math.max(minFrame + 1, Math.ceil(frameRange[1])); const N = localscore.length; const dp = new Float32Array(N); const backlink = new Int32Array(N); // 计算第一个节拍必须超过的阈值 let scoreThresh = 0; for (let i = 0; i < N; i++) { if (localscore[i] > scoreThresh) scoreThresh = localscore[i]; } scoreThresh *= 0.01; let firstBeat = true; // 预计算 Log 表以提升性能 范围最大为 frameRange const r = Math.min(maxFrame - minFrame, N) + 1; const logTable = new Float32Array(r); for (let j = 0; j < r; j++) logTable[j] = Math.log(j + minFrame); for (let t = 0; t < N; t++) { // 获取当前的期望每拍帧数 (fpb) const fpb = isDynamicTempo ? framesPerBeat[t] : framesPerBeat[0]; const targetInter = Math.log(fpb); // librosa的搜索区间:[i - 2*fpb, i - fpb/2] // 同时还受限于 frameRange const searchStart = t - Math.round(Math.max(minFrame, fpb * .5)); let searchEnd = t - Math.round(Math.min(maxFrame, fpb * 2)); if (searchEnd < 0) searchEnd = 0; // 在搜索范围内寻找最优的前驱节点 let beatT = -1, maxS = -Infinity; for (let tau = searchStart; tau >= searchEnd; tau--) { const diff = logTable[t - tau - minFrame] - targetInter; const s = dp[tau] - tightness * diff * diff; if (s > maxS) { maxS = s; beatT = tau; } } // 累加得分到 dp 数组 const scoreI = localscore[t]; dp[t] = (beatT >= 0) ? (scoreI + maxS) : scoreI; // if (isNaN(dp[t])) console.warn(`NaN detected at dp[${t}]`); // 起始点判定 在找到第一个超过阈值的有效起始点之前,不建立回溯链接 if (firstBeat && scoreI < scoreThresh) { backlink[t] = -1; } else { backlink[t] = beatT; firstBeat = false; } } // 回溯 let tail = Beat.getLastBeat(dp); const beatIndices = []; while (tail >= 0) { beatIndices.push(tail); tail = backlink[tail]; } return beatIndices.reverse(); } /** * 识别最后一次检测到的 beat 位置 (Ellis 算法) * @param {Float32Array|Array} cumscore 累积得分数组 * @returns {number} 最后一次 beat 的索引 */ static getLastBeat(cumscore) { const n = cumscore.length; if (n === 0) return 0; // 1. 提取局部极大值 (Peaks) 预分配内存 const preLen = (n >> 1) + 1; const peaks = new Float32Array(preLen); const peakIndices = new Int32Array(preLen); let peakCount = 0; for (let i = 1; i < n - 1; i++) { const val = cumscore[i]; if (val > cumscore[i - 1] && val >= cumscore[i + 1]) { peaks[peakCount] = val; peakIndices[peakCount] = i; peakCount++; } } // 单独判断最后一个; librosa 不考虑第一个点 if (cumscore[n - 1] > cumscore[n - 2]) { peaks[peakCount] = cumscore[n - 1]; peakIndices[peakCount] = n - 1; peakCount++; } if (peakCount === 0) return n - 1; // 2. 中位数计算函数 function getMedianOfPeaks(arr, len) { const swap = (i, j) => { const tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }; function partition(left, right, pivotIdx) { const pivotValue = arr[pivotIdx]; swap(pivotIdx, right); let storeIdx = left; for (let i = left; i < right; i++) { if (arr[i] < pivotValue) { swap(i, storeIdx); storeIdx++; } } swap(storeIdx, right); return storeIdx; } function quickSelect(k) { let left = 0; let right = len - 1; while (left <= right) { if (left === right) return arr[left]; let pivotIdx = (left + right) >>> 1; pivotIdx = partition(left, right, pivotIdx); if (k === pivotIdx) return arr[k]; if (k < pivotIdx) right = pivotIdx - 1; else left = pivotIdx + 1; } } const mid = len >> 1; if (len % 2 !== 0) { return quickSelect(mid); } else { // 此时数组已被部分排序,第二次 quickSelect 极快 const v1 = quickSelect(mid); const v2 = quickSelect(mid - 1); return (v1 + v2) / 2; } } const median = getMedianOfPeaks(peaks, peakCount); const threshold = 0.5 * median; // 3. 反向搜索确定最后一个超过阈值的峰值位置 for (let j = peakCount - 1; j >= 0; j--) { const originalIdx = peakIndices[j]; if (cumscore[originalIdx] >= threshold) { return originalIdx; } } return peakIndices[0]; } /** * Predominant local pulse estimation * 理解为时变滤波 * @param {Float32Array} onsetEnv * @param {number} onset_sr * @param {number[]} rangeBPM [MinBPM, MaxBPM] * @param {number} winLen STFT窗长 * @param {number} hopLen STFT hop * @param {(number)=>(number)=>number} prior 传入时间点,返回一个函数f,f输入BPM,输出权重 * @returns {Float32Array} 滤波后的脉冲序列 */ static PLP(onsetEnv, onset_sr, rangeBPM = [40, 200], winLen, hopLen, prior) { const fft = new realFFT(winLen, 'hanning'); if (typeof hopLen !== "number") hopLen = fft.N; // 一半的窗长 if (hopLen <= 0 || hopLen > fft.N << 1) throw new Error("Invalid hop length"); const win = SIGNAL.createSynthesisWindow(fft.window, hopLen); const n_bpm = fft.N / (onset_sr * 30); // 每BPM对应的频率点数 fft.N只有一半故为30 const bpm_n = 1 / n_bpm; const fMin = Math.min(fft.N, rangeBPM[0] * n_bpm); const fMax = Math.max(0, rangeBPM[1] * n_bpm); const validPrior = typeof prior === "function"; const pulse = new Float32Array(onsetEnv.length); // 最终脉冲序列 for (let t = fft.N >> 1; t < onsetEnv.length; t += hopLen) { let offset = t - fft.N; const [real, imag] = fft.fft(onsetEnv, offset); // 加窗 let i = 0; for (; i < fMin; i++) real[i] = imag[i] = 0; if (validPrior) { const p = prior(t); let maxMag = -1; let maxAt = fMin; for (let j = i; j < fMax; j++) { const scale = p(j * bpm_n); real[j] *= scale; imag[j] *= scale; const mag = Math.hypot(real[j], imag[j]); if (mag > maxMag) { maxMag = mag; maxAt = j; } } // 只保留关键频率 // for (; i < maxAt; i++) real[i] = imag[i] = 0; // librosa 有归一化,但我认为不能有 // real[maxAt] /= maxMag; // imag[maxAt] /= maxMag; // for (i = maxAt + 1; i < fMax; i++) real[i] = imag[i] = 0; } for (i = fft.N - 1; i > fMax; i--) real[i] = imag[i] = 0; // 还原 const time = fft.ifft(real, imag); i = 0; while (offset < 0) i++, offset++; for (; i < fft.N && offset < onsetEnv.length; i++, offset++) { pulse[offset] += time[i] * win[i]; } } // 仅保留正值 并归一化 let std = 0, mean = 0, min = Infinity; for (let i = 0; i < pulse.length; i++) { // const e = pulse[i] = Math.exp(pulse[i] - 1); const e = pulse[i] = (pulse[i] > 0) ? pulse[i] : 0; mean += e; std += e * e; if (e < min) min = e; } mean /= pulse.length; std = Math.sqrt(std / pulse.length - mean * mean); for (let i = 0; i < pulse.length; i++) pulse[i] = (pulse[i] - min) / std; return pulse; } /** * PLP的高斯先验函数生成器 * @param {Float32Array} BPMt 每帧BPM估计 * @param {number} std 标准差 0.2刚好在倍数处切掉 0.3适合没有任何先验时使用 搭配BPMt=[] * @returns {(number)=>(number)=>number} */ static PLPprior(BPMt = [], std = 0.2) { const stdInv = 1 / std; return (t) => { const logbpm = Math.log2(BPMt[t] || 110); return (bpm) => { const k = (Math.log2(bpm) - logbpm) * stdInv; return Math.exp(-0.5 * k * k); } }; } /** * 获取每个节拍位置的最大onset强度 * @param {Float32Array} onsetEnv * @param {number[]} beatIndices 节拍位置索引 * @param {number} winLen 搜索范围 * @returns {Float32Array} beat的onset强度 */ static beatStrength(onsetEnv, beatIndices, winLen = 5) { const halfWin = winLen >> 1; const eng = new Float32Array(beatIndices.length); for (let i = 0; i < beatIndices.length; i++) { const idx = beatIndices[i]; let m = -1; const end = Math.min(onsetEnv.length - 1, idx + halfWin); for (let j = Math.max(0, idx - halfWin); j <= end; j++) { if (onsetEnv[j] > m) m = onsetEnv[j]; } eng[i] = m; } return eng; } /** * 假设全局节奏型不变 根据节拍强度推断节奏型 * @param {Float32Array} beatStrength * @param {number[]} patterns * @returns {[0]:number, [1]:number} 节奏型(小节拍数), 第一个重拍的位置 */ static rhythmicPattern(beatStrength, patterns = [2, 3, 4]) { const pateng = (size) => { const eng = new Float32Array(size); const cnt = new Uint16Array(size); for (let i = 0; i <= beatStrength.length; i++) { const k = i % size; eng[k] += beatStrength[i]; cnt[k]++; } for (let i = 0; i < size; i++) { if (cnt[i] === 0) throw new Error("No beats found for pattern analysis"); eng[i] /= cnt[i]; } return eng; } let maxPattern = 4, maxDiff = -Infinity, maxAt = 0; for (const p of patterns) { const eng = pateng(p); // 找到最大和最小值,最大值要记录位置 let maxVal = -Infinity, minVal = Infinity, maxIdx = 0; for (let i = 0; i < p; i++) { const v = eng[i]; if (v > maxVal) { maxVal = v; maxIdx = i; } if (v < minVal) minVal = v; } const diff = maxVal - minVal; if (diff > maxDiff) { maxDiff = diff; maxPattern = p; maxAt = maxIdx; } } return [maxPattern, maxAt]; } /** * 根据节拍强度和节拍位置,推断节奏型 * @param {Float32Array} beatStrength onset envelope at beat positions * @param {number[]} meters 支持的小节拍数 * @returns {[0]:number[], [1]:number[]} 检测到的下拍索引数组,节奏型对应的小节拍数数组 */ static detectDownbeats(beatStrength, meters = [2, 3, 4]) { const numBeats = beatStrength.length; if (numBeats === 0) return [[], []]; Beat.onsetNorm(beatStrength); let states = []; // 状态=(节奏型, 相位) meters.forEach(m => { // m: 节奏型 p: 小节内相位(0为重拍) id: 状态唯一标识 for (let p = 0; p < m; p++) states.push({ m, p, id: `${m}-${p}` }); }); // dp 存储: s(加权重拍和), c(加权重拍数), su(加权弱拍和), cu(加权弱拍数), a(累积评分) let dp = Array.from({ length: numBeats }, () => ({})); // --- 动态参数 --- const ALPHA = 0.97; // 遗忘因子:越小局部性越强 理论最大值为 1 / (1-ALPHA) const UPBEAT_W = 0.2; // 弱拍抑制权重 const METER_CHANGE_PENALTY = 0.6; // 切换惩罚 const BIAS_44 = 0.02; // 4/4 偏好 const HIST_W = 0.25; // 历史分值权重 // 初始化第一拍 states.forEach(s => { const isDB = (s.p === 0); const str = beatStrength[0]; // 允许第一拍在任何相位开始 dp[0][s.id] = { s: isDB ? str : 0, c: isDB ? 1 : 0, su: isDB ? 0 : str, cu: isDB ? 0 : 1, a: isDB ? str : -UPBEAT_W * str, prev: null }; }); // 动态规划 for (let i = 1; i < numBeats; i++) { const str = beatStrength[i]; // 假设当前为curr模式 states.forEach(curr => { let maxScore = -Infinity; let bestPrevId = null; let bestState = null; // 遍历所有可能的前驱模式 states.forEach(prev => { const pInfo = dp[i - 1][prev.id]; if (!pInfo) return; // 物理顺序约束 let isSwitch = false; if (prev.m === curr.m) { // 节奏型相同,但相位不连续,不符合要求 if (curr.p !== (prev.p + 1) % curr.m) return; } else { // 只有在旧小节末尾且新小节开头才允许切换 if (prev.p === prev.m - 1 && curr.p === 0) isSwitch = true; else return; } // 带有遗忘因子的统计量更新 const isDB = (curr.p === 0); const nextC = pInfo.c * ALPHA + (isDB ? 1 : 0); let nextSU = pInfo.su * ALPHA + (isDB ? 0 : str); const nextS = pInfo.s * ALPHA + (isDB ? str : 0); const nextCU = pInfo.cu * ALPHA + (isDB ? 0 : 1); // 计算当前局部均值对比度 const avgDB = nextC > 0 ? nextS / nextC : 0; const avgUP = nextCU > 0 ? nextSU / nextCU : 0; let contrast = avgDB - (UPBEAT_W * avgUP); // 切换惩罚 if (isSwitch) { contrast *= METER_CHANGE_PENALTY; // 仿射变换 降低对未来的相对影响 nextSU = nextSU * 1.05 + 4; } // 4/4偏好 if (curr.m === 4) contrast += BIAS_44; // 混合历史与当前 const currentScore = pInfo.a * HIST_W + contrast * (1 - HIST_W); if (currentScore > maxScore) { maxScore = currentScore; bestPrevId = prev.id; bestState = { s: nextS, c: nextC, su: nextSU, cu: nextCU, a: currentScore }; } }); if (bestPrevId !== null) dp[i][curr.id] = { ...bestState, prev: bestPrevId }; }); } // 回溯 let lastId = null; let maxA = -Infinity; states.forEach(s => { if (dp[numBeats - 1][s.id] && dp[numBeats - 1][s.id].a > maxA) { maxA = dp[numBeats - 1][s.id].a; lastId = s.id; } }); const dbIdx = [], dbMeters = []; for (let i = numBeats - 1; i >= 0; i--) { if (!lastId) break; const [m, p] = lastId.split('-').map(Number); if (p === 0) { dbIdx.push(i); dbMeters.push(m); } lastId = dp[i][lastId].prev; } return [dbIdx.reverse(), dbMeters.reverse()]; } } ================================================ FILE: dataProcess/fft_real.js ================================================ /** * 目前我写的最快的实数FFT。为音乐频谱分析设计 */ class realFFT { /** * 位反转数组 最大支持2^16点 * @param {number} N 2的正整数幂 * @returns {Uint16Array} 位反转序列 */ static reverseBits(N) { const reverseBits = new Uint16Array(N); // 实际N最大2^15 reverseBits[0] = 0; // 计算位数 let bits = 15; while ((1 << bits) > N) bits--; // 由于是实数FFT,偶次为实部,奇次为虚部,故最终结果要乘2,所以不是16-bits bits = 15 - bits; for (let i = 1; i < N; i++) { // 基于二分法的位翻转 let r = ((i & 0xaaaa) >> 1) | ((i & 0x5555) << 1); r = ((r & 0xcccc) >> 2) | ((r & 0x3333) << 2); r = ((r & 0xf0f0) >> 4) | ((r & 0x0f0f) << 4); reverseBits[i] = ((r >> 8) | (r << 8)) >> bits; } return reverseBits; } /** * 复数乘法 * @param {number} a 第一个数的实部 * @param {number} b 第一个数的虚部 * @param {number} c 第二个数的实部 * @param {number} d 第二个数的虚部 * @returns {Array} [实部, 虚部] */ static ComplexMul(a = 0, b = 0, c = 0, d = 0) { return [a * c - b * d, a * d + b * c]; } /** * 计算复数的幅度 * @param {Float32Array} r 实部数组 * @param {Float32Array} i 虚部数组 * @returns {Float32Array} 幅度 */ static ComplexAbs(r, i, l) { l = l || r.length; const ABS = new Float32Array(l); for (let j = 0; j < l; j++) { ABS[j] = Math.sqrt(r[j] * r[j] + i[j] * i[j]); } return ABS; } /** * 初始化实数FFT 使用Hanning窗 * @param {number} N 要做几点的实数FFT * @param {string} window 窗类型 'hanning' | 'none' */ constructor(N, window = 'hanning') { this.ini(N); this.bufferr = new Float32Array(this.N); this.bufferi = new Float32Array(this.N); // 存放最终结果的数组 // FFT返回Xr和Xi IFFT返回X this.X = new Float32Array(this.N << 1); this.Xr = this.X.subarray(0, this.N); this.Xi = this.X.subarray(this.N); // 窗函数初始化 if (window === 'hanning') this.initWindow(); else this.window = new Float32Array(this.N << 1).fill(1); } /** * 计算Hanning窗 * 并利用this.bufferr和this.bufferi对窗值进行重排 * 以加速FFT时的访问速度(随机访问->顺序访问) */ initWindow() { // this.N是实际长度的一半 const half_N = this.N; const N = this.N << 1; const pi2_N = Math.PI / half_N; // 2π/N = π/(N/2) for (let n = 0; n < half_N; n++) { // 利用对称性 由于最后会归一化,因此这里不用除以2 this.bufferr[n] = this.bufferi[half_N - n - 1] = 1 - Math.cos(pi2_N * n); } const window = new Float32Array(N); for (let i = 0, ii = 1, j = 0; j < N; i += 2, ii += 2, j += 4) { // 利用性质:reverseBits的偶数项都小于half_N(从bufferr中取值),奇数项都大于half_N(从bufferi中取值) window[j] = this.bufferr[this.reverseBits[i]]; window[j+1] = this.bufferr[this.reverseBits[i] + 1]; window[j+2] = this.bufferi[this.reverseBits[ii] - half_N]; window[j+3] = this.bufferi[this.reverseBits[ii] - half_N + 1]; } this.window = window; } /** * 预计算常量 * @param {number} N 2的正整数次幂 */ ini(N) { // 确定FFT长度 N = 1 << (Math.ceil(Math.log2(N)) - 1); this.N = N; // 存的是实际FFT的点数 // 位反转预计算 实际做N/2的FFT this.reverseBits = realFFT.reverseBits(N); // 旋转因子预计算 仍然需要N点的,但是只取前一半 const PIN = Math.PI / N; this._Wr = new Float32Array(Array.from({ length: N }, (_, i) => Math.cos(PIN * i))); this._Wi = new Float32Array(Array.from({ length: N }, (_, i) => -Math.sin(PIN * i))); } /** * 计算除第一层外的FFT * 要求第一层的结果存储于this.bufferr和this.bufferi * 结果存储于this.bufferr和this.bufferi */ _fftOther() { for (let groupNum = this.N >> 2, groupMem = 2; groupNum; groupNum >>= 1) { // groupNum: 组数;groupMem:一组里有几个蝶形结构,同时也是一个蝶形结构两个元素的序号差值 // groupNum: N/4, N/8, ..., 1 // groupMem: 2, 4, ..., N/2 // W's base: 4, 8, ..., N // W's base desired: 2N // times to k: N/2, N/4 --> equals to 2*groupNum (W_base*k_times=W_base_desired) // offset between groups: 4, 8, ..., N --> equals to 2*groupMem const groupOffset = groupMem << 1; for (let mem = 0, k = 0, dk = groupNum << 1; mem < groupMem; mem++, k += dk) { const [Wr, Wi] = [this._Wr[k], this._Wi[k]]; for (let gn = mem; gn < this.N; gn += groupOffset) { const gn2 = gn + groupMem; const [gwr, gwi] = realFFT.ComplexMul(this.bufferr[gn2], this.bufferi[gn2], Wr, Wi); this.Xr[gn] = this.bufferr[gn] + gwr; this.Xi[gn] = this.bufferi[gn] + gwi; this.Xr[gn2] = this.bufferr[gn] - gwr; this.Xi[gn2] = this.bufferi[gn] - gwi; } } [this.bufferr, this.bufferi, this.Xr, this.Xi] = [this.Xr, this.Xi, this.bufferr, this.bufferi]; groupMem = groupOffset; } } /** * 输入N点实数,输出N/2点复数FFT结果;X[0]的实部存放于Xi[0] * @param {Float32Array} input 输入 * @param {number} offset 偏移量 * @returns [实部, 虚部] */ fft(input, offset = 0) { // 偶数次和奇数次组合并计算第一层 并加窗 for (let i = 0, ii = 1, j = 0, offseti = offset + 1; i < this.N; i += 2, ii += 2, j += 4) { let xr1 = input[this.reverseBits[i] + offset] || 0; let xi1 = input[this.reverseBits[i] + offseti] || 0; let xr2 = input[this.reverseBits[ii] + offset] || 0; let xi2 = input[this.reverseBits[ii] + offseti] || 0; xr1 *= this.window[j]; xi1 *= this.window[j+1]; xr2 *= this.window[j+2]; xi2 *= this.window[j+3]; this.bufferr[i] = xr1 + xr2; this.bufferi[i] = xi1 + xi2; this.bufferr[ii] = xr1 - xr2; this.bufferi[ii] = xi1 - xi2; } // 其他层 this._fftOther(); // 合并为实数FFT的结果 this.Xr[0] = this.bufferr[0] + this.bufferi[0]; this.Xi[0] = this.bufferr[0] - this.bufferi[0]; // 实际上是X[N/2]的实部 for (let k = 1, Nk = this.N - 1; Nk; k++, Nk--) { const [Ir, Ii] = realFFT.ComplexMul(this.bufferi[k] + this.bufferi[Nk], this.bufferr[Nk] - this.bufferr[k], this._Wr[k], this._Wi[k]); this.Xr[k] = (this.bufferr[k] + this.bufferr[Nk] + Ir) * 0.5; this.Xi[k] = (this.bufferi[k] - this.bufferi[Nk] + Ii) * 0.5; } return [this.Xr, this.Xi]; } /** * 输入N/2点复数频域,输出N点实数时域 * @param {Float32Array} real 频域实部 * @param {Float32Array} imag 频域虚部 imag[0]存放X[N/2]的实部 * @returns {Float32Array} 时域实数 */ ifft(real, imag) { const calci = (idx) => { const xr = real[idx] || 0; const xi = imag[idx] || 0; const xrN = real[this.N - idx] || 0; const xiN = imag[this.N - idx] || 0; const [r, i] = realFFT.ComplexMul(xr - xrN, xi + xiN, this._Wi[idx], this._Wr[idx]); // 先不乘0.5 到最后归一化再做 return [xr + xrN + r, xi - xiN + i]; } // 拼接并计算第一层 { // 单独计算第一组 const x1r = real[0] + imag[0]; const x1i = real[0] - imag[0]; // reverseBits为了适应FFT乘了2 这里要除回去 const [x2r, x2i] = calci(this.reverseBits[1] >> 1); this.bufferr[0] = x1r + x2r; this.bufferr[1] = x1r - x2r; // IFFT需要取共轭 this.bufferi[0] = -(x1i + x2i); this.bufferi[1] = x2i - x1i; } for (let i = 2, ii = 3; i < this.N; i+=2, ii+=2) { const [x1r, x1i] = calci(this.reverseBits[i] >> 1); const [x2r, x2i] = calci(this.reverseBits[ii] >> 1); this.bufferr[i] = x1r + x2r; this.bufferr[ii] = x1r - x2r; this.bufferi[i] = -(x1i + x2i); this.bufferi[ii] = x2i - x1i; } // 其他层 this._fftOther(); // 结果重排并归一化 const norm = 1 / (this.N << 1); // 之前的0.5 for (let i = 0, j = 0; i < this.N; i++, j+=2) { this.X[j] = this.bufferr[i] * norm; this.X[j + 1] = -this.bufferi[i] * norm; // 取共轭 } return this.X; } } ================================================ FILE: dataProcess/stftGPU.js ================================================ /** * Short-Time Real Fourier Transform using WebGPU */ class STFTGPU { static reverseBits(N) { const reverseBits = new Uint32Array(N); const bits = Math.log2(N); for (let i = 0; i < N; i++) { let r = 0, n = i; for (let j = 0; j < bits; j++) { r = (r << 1) | (n & 1); n >>= 1; } reverseBits[i] = r; } return reverseBits; } constructor(fftN = 8192, hopSize) { this.fftN = 1 << Math.ceil(Math.log2(fftN)); this.realN = this.fftN >> 1; this.hopSize = hopSize; } async initWebGPU(workgroup_size_pow = 8) { // 最大为8 const adapter = await navigator.gpu.requestAdapter(); if (!adapter) throw new Error("WebGPU adapter not found."); const device = await adapter.requestDevice({ requiredLimits: { maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize, maxBufferSize: adapter.limits.maxBufferSize, } }); if (!device) throw new Error("WebGPU device not found."); this.adapter = adapter; this.device = device; this.workgroup_size_pow = workgroup_size_pow; const workgroup_size = 1 << workgroup_size_pow; this.maxSize = Math.min(adapter.limits.maxStorageBufferBindingSize, adapter.limits.maxBufferSize); this.memUsed = 0; const shaderModule = device.createShaderModule({ label: 'STFT Compute Shader', code: /*wgsl*/` const fftN: u32 = ${this.fftN}u;// 实数FFT长度 const M: u32 = ${this.realN}u;// 复数FFT长度 const PI: f32 = 3.14159265359; struct Config { audioLen: u32, hop: u32, numFrames: u32, initialOffset_stage: i32, // 第一阶段作为音频起始位置偏移 第二阶段作为stage }; @group(0) @binding(0) var audio: array;// 音频输入 @group(0) @binding(1) var complexData: array>;// 复数中间结果 [numFrames * M] @group(0) @binding(2) var config: Config; @group(0) @binding(3) var bitReverseLUT: array;// 位反转查找表 [M] @group(0) @binding(4) var energyOutput: array;// 能量谱输出 [numFrames * M] fn hanning(n: u32) -> f32 {return 1 - cos(PI * f32(n) / f32(M));} // Pass1 预处理阶段:加窗并填充复数数组 @compute @workgroup_size(${workgroup_size}) fn preprocess( // 对于8192点, dispatch(8192/(256*2), numFrames, 1) @builtin(global_invocation_id) global_id: vec3 // (x: n within frame, y: frame index) ) { let n = global_id.x; // range [0, 4095] let frame = global_id.y; let offset = i32(frame * config.hop) + config.initialOffset_stage; // 本帧的音频起始位置 // 取音频数据,越界补零 let idx_even = offset + i32(n * 2); let idx_odd = idx_even + 1; let re = select(0.0, audio[u32(idx_even)], idx_even >= 0 && u32(idx_even) < config.audioLen); let im = select(0.0, audio[u32(idx_odd)], idx_odd >= 0 && u32(idx_odd) < config.audioLen); // 加窗并构成复数 let win_even = hanning(n << 1u); let win_odd = hanning((n << 1u) + 1u); complexData[frame * M + n] = vec2(re * win_even, im * win_odd); } // Pass2 FFT计算阶段 config.initialOffset_stage (即 stage) 应该从 LOG2_M - 1 (11) 循环递减到 0 @compute @workgroup_size(${workgroup_size}) fn fft_stage( // dispatch(2048/256, numFrames, 1) @builtin(global_invocation_id) global_id: vec3 ) { let n = global_id.x; // range [0, 2047] 一个线程处理一个蝶形 let frame = global_id.y; let stage = u32(config.initialOffset_stage); // 作为stage使用 let step = 1u << stage; // 步长: 2048, 1024, ..., 1 let element_count = step << 1u; // 当前块大小 let blockIdx = n / step; // n*2 / element_count let offsetInBlock = n % step; // 旋转因子 W 计算 let tIndex = offsetInBlock * (M >> (stage + 1u)); let angle = -2.0 * PI * f32(tIndex) / f32(M); let w = vec2(cos(angle), sin(angle)); let index1 = frame * M + (blockIdx * element_count + offsetInBlock); let index2 = index1 + step; let u = complexData[index1]; let v = complexData[index2]; let sub = u - v; let out2 = vec2( sub.x * w.x - sub.y * w.y, sub.x * w.y + sub.y * w.x ); complexData[index1] = u + v; complexData[index2] = out2; } // Pass3 位反转 RealFFT后处理 能量谱 @compute @workgroup_size(${workgroup_size}) fn postprocess( // dispatch(4096/256, numFrames, 1) @builtin(global_invocation_id) global_id: vec3 ) { let k = global_id.x; // [0, M-1] let frame = global_id.y; // 1. 读取 Bit-Reversed 数据,恢复线性顺序的 Z[k] let revK = bitReverseLUT[k]; let Z_k = complexData[frame * M + revK]; // 2. 获取对称点 Z[N/2 - k] // 注意处理 k=0 的情况, (M-0)%M = 0 let k_sym = (M - k) % M; let revK_sym = bitReverseLUT[k_sym]; let Z_sym = complexData[frame * M + revK_sym]; // 3. Unscramble 公式 let Z_sym_conj = vec2(Z_sym.x, -Z_sym.y); let F_even = 0.5 * (Z_k + Z_sym_conj); let F_odd = 0.5 * (Z_k - Z_sym_conj); let angle = -PI * f32(k) / f32(M); let w = vec2(cos(angle), sin(angle)); let neg_j_F_odd = vec2(F_odd.y, -F_odd.x);// -j * Fodd let rot_F_odd = vec2(// -j * Fodd * w neg_j_F_odd.x * w.x - neg_j_F_odd.y * w.y, neg_j_F_odd.x * w.y + neg_j_F_odd.y * w.x ); let X_k = F_even + rot_F_odd; // 4. 计算能量谱 let energy = X_k.x * X_k.x + X_k.y * X_k.y; // 累加 let outIdx = frame * M + k; energyOutput[outIdx] = energyOutput[outIdx] + energy; }`}); const bindGroupLayout = this.bindGroupLayout = device.createBindGroupLayout({ label: "STFT Uniform Layout", entries: [ { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } }, { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } }, { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: "uniform" } }, { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } }, { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } }, ] }); const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }); this.prePipeLine = device.createComputePipeline({ label: "STFT Preprocess Pipeline", layout: pipelineLayout, compute: { module: shaderModule, entryPoint: "preprocess" }, }); this.fftPipeLine = device.createComputePipeline({ label: "STFT FFT Pipeline", layout: pipelineLayout, compute: { module: shaderModule, entryPoint: "fft_stage" }, }); this.postPipeline = device.createComputePipeline({ label: "STFT Postprocess Pipeline", layout: pipelineLayout, compute: { module: shaderModule, entryPoint: "postprocess" }, }); // 位反转缓冲区 const bitReverseLUTBuffer = this.bitReverseLUTBuffer = device.createBuffer({ size: this.realN * Uint32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, mappedAtCreation: true, }); new Uint32Array(bitReverseLUTBuffer.getMappedRange()).set(STFTGPU.reverseBits(this.realN)); bitReverseLUTBuffer.unmap(); // 配置缓冲区 this.configBuffer ??= device.createBuffer({ size: 4 * Uint32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, }); this.memUsed += bitReverseLUTBuffer.size + this.configBuffer.size; if (this.memUsed > this.maxSize) throw new Error("STFTGPU: Exceeded maximum buffer size."); } stft(audioBuffer) { // 第一帧的左侧 一般为负数 const initialOffset = (this.hopSize >> 1) - this.realN; const audioLen = audioBuffer.length; const numFrames = 1 + (audioLen - 1 - (this.hopSize >> 1)) / this.hopSize | 0; const bytes = numFrames * this.realN * Float32Array.BYTES_PER_ELEMENT; // 输入 const audioBufferGPU = this.audioBufferGPU ??= this.device.createBuffer({ size: audioBuffer.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, }); // 中间变量 const complexDataBuffer = this.complexDataBuffer ??= this.device.createBuffer({ size: bytes << 1, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, }); // 输出 const outputBuffer = this.outputBuffer ??= this.device.createBuffer({ size: bytes, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, }); // 检查空间 this.memUsed += audioBufferGPU.size + complexDataBuffer.size + outputBuffer.size; if (this.memUsed > this.maxSize) throw new Error("STFTGPU: Exceeded maximum buffer size."); // 写入数据 this.device.queue.writeBuffer(audioBufferGPU, 0, audioBuffer); this.device.queue.writeBuffer(this.configBuffer, 0, new Int32Array([ audioLen, this.hopSize, numFrames, initialOffset ])); // 创建统一的BindGroup const mainBindGroup = this.device.createBindGroup({ layout: this.bindGroupLayout, entries: [ { binding: 0, resource: { buffer: audioBufferGPU } }, { binding: 1, resource: { buffer: complexDataBuffer } }, { binding: 2, resource: { buffer: this.configBuffer } }, { binding: 3, resource: { buffer: this.bitReverseLUTBuffer } }, { binding: 4, resource: { buffer: outputBuffer } }, ], }); // === 预处理 === const commandEncoder = this.device.createCommandEncoder(); const passEncoder1 = commandEncoder.beginComputePass(); passEncoder1.setPipeline(this.prePipeLine); passEncoder1.setBindGroup(0, mainBindGroup); passEncoder1.dispatchWorkgroups(this.realN >> this.workgroup_size_pow, numFrames, 1); passEncoder1.end(); this.device.queue.submit([commandEncoder.finish()]); // === FFT计算 === const LOG2_M = Math.log2(this.realN); for (let stage = LOG2_M - 1; stage >= 0; stage--) { const commandEncoder = this.device.createCommandEncoder(); const passEncoder2 = commandEncoder.beginComputePass(); passEncoder2.setPipeline(this.fftPipeLine); // 更新stage this.device.queue.writeBuffer(this.configBuffer, 3 * Uint32Array.BYTES_PER_ELEMENT, new Int32Array([stage])); passEncoder2.setBindGroup(0, mainBindGroup); passEncoder2.dispatchWorkgroups(this.realN >> (this.workgroup_size_pow + 1), numFrames, 1); passEncoder2.end(); this.device.queue.submit([commandEncoder.finish()]); } // === 后处理 === const commandEncoder3 = this.device.createCommandEncoder(); const passEncoder3 = commandEncoder3.beginComputePass(); passEncoder3.setPipeline(this.postPipeline); passEncoder3.setBindGroup(0, mainBindGroup); passEncoder3.dispatchWorkgroups(this.realN >> this.workgroup_size_pow, numFrames, 1); passEncoder3.end(); this.device.queue.submit([commandEncoder3.finish()]); } readGPU(buffer = this.outputBuffer) { const readBuffer = this.device.createBuffer({ size: buffer.size, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, }); const commandEncoder = this.device.createCommandEncoder(); commandEncoder.copyBufferToBuffer(buffer, 0, readBuffer, 0, buffer.size); this.device.queue.submit([commandEncoder.finish()]); return readBuffer.mapAsync(GPUMapMode.READ).then(() => { const arrayBuffer = new Float32Array(readBuffer.getMappedRange()).slice(); readBuffer.unmap(); readBuffer.destroy(); const result = Array(arrayBuffer.length / this.realN); for (let i = 0, offset = 0; i < arrayBuffer.length; i += this.realN, offset++) { result[offset] = arrayBuffer.slice(i, i + this.realN); } return result; }); } free() { this.audioBufferGPU?.destroy();this.audioBufferGPU = null; this.complexDataBuffer?.destroy();this.complexDataBuffer = null; this.outputBuffer?.destroy();this.outputBuffer = null; this.bitReverseLUTBuffer?.destroy();this.bitReverseLUTBuffer = null; this.configBuffer?.destroy();this.configBuffer = null; this.prePipeLine = null;this.fftPipeLine = null;this.postPipeline = null; this.device = null;this.adapter = null; this.bindGroupLayout = null; } } ================================================ FILE: docs/DEVELOPMENT.md ================================================ # 开发概述 基本功能在`core/`文件夹中,包括: - 频谱分析与绘制 - 音符播放与绘制 - 音频播放与时间管理。音频是整个项目的同步时钟 - 左侧键盘的绘制 - 顶部的时间轴和小节轴 - 文件输入输出 ## 时频分析 用`Web Audio API`解码上传的音频,得到幅度数组。然后使用FFT,接着使用CQT,最后两种频谱进行融合。 - FFT参数:采样率44100Hz,取8192点的实数FFT,使用Hanning窗,分析范围:C1-B7,但点数限制只能区分F#2以上的音符。 - 从线性谱到对数谱使用频域窗,先模拟频谱泄露,然后在对数坐标中用Hanning窗。注意窗和(窗绝对值求和)应该正比于中心频率,这样不同频段才可比。 - CQT参数:采样率44100Hz,每个半音对应一个滤波器,每个滤波器为BlackmanHarris窗作用的 $e^{2\pi j\omega t}$(指数没有负号,因为最终取能量,无所谓)。由于窗导致主瓣增加,因此滤波器长度至少为2倍原长才能有矩形窗的主瓣分辨率。取2.8。没有用任何技巧,直接时域滤波。 - 归一化:在能量域进行二维的方差归一化。 - 频谱融合:CQT小的地方使用几何平均(相乘再开根号),以实现压制;CQT大的地方使用均方根,以突出。几何平均<算数平均<军均方根。之所以需要FFT频谱参与,是因为CQT频谱过于琐碎,需要平滑。 3个问题: 1. 有的音乐中心频率不是正好440Hz,是否需要自适应?懒得做了,调音前后结果基本相同,徒增运算量。 2. FFT低频分辨率不足。这个没办法,所以有了CQT。 3. 最高到22050Hz,但是音符最高3950Hz,取到C8,即只需777点。后面的是否保留?暂时没考虑保留。 ## 可视化 绘制由`requestAnimationFrame`驱动,采用“数据-渲染”的模式。另一种选择是事件驱动,但是很混乱,抛弃。 ### 视窗模型 即无限画布的实现原理。首先规定每个格子的宽高像素数,即`.width`和`.height`。在此基础上,定义`.scrollX`和`scrollY`,表示视窗左侧和世界左侧、视窗下侧和世界下侧的像素数。注意这里的`scrollY`和画布的纵坐标是反的。 ### 数据结构 一共有三个画布区域:左侧钢琴,顶部时间轴/小节轴,中心主工作区。左侧和顶部的绘制内容需要和主工作区的横向、纵向对齐。 主工作区采用画布叠加实现多图层(属性`.layers`),为了拓展性,暴露了图层增删的API: `.layers.addLayer` `.layers.removeLayer`。每个图层为一个封装过的画布,有独立的`dirty`属性,表示是否要重绘该画布。每个画布的绘制采用带有优先级的**注册制**,优先级越小越先绘制,实现了每个画布的内部图层。 由于频谱绘制频繁切换`fillStyle`,CPU占用较高,且内容基本不会变,因此单独作为一个背景图层,使用`dirty`标签作为重绘标记。`dirty`置位条件为: - 视窗位置更改 - 频谱发生改变 - 绘制参数改变(如倍率、谐波分析) 其余部分绘制较为容易,因此集成到另一个画布,`dirth`置位条件为用户是否操作,因为这层主要绘制时间线、音符等强交互内容。 ## MIDI ### 存储结构 两个方案:所有轨都在一个数组中,和每轨一个数组,或者……两者结合 - 所有轨都在一个数组:可以一次遍历实现音符拾取 - 每轨一个数组:可以方便地实现单轨样式的应用,更改音轨顺序容易,绘制容易,但需要每个轨道单独遍历 - 两者结合:维护较为麻烦 需要实现的功能: - 撤销重做: 差不多,都是`JSON.stringfy` - 单音轨播放(静音、乐器):一个数组简单,因为播放的时候只需要维护一次遍历 - 多音轨拖拽:音符拾取是单音轨简单。拖拽影响的是selected数组(见后文),两者平局 最终决定主存储使用一个数组(便于播放的状态维护): ```ts type Note = { // 单个音符 x1: number; // onset位置 x2: number; // offset位置 y: number; // 音高 ch: number; // 音轨 selected: boolean; // 是否选中 v: number; // 音量 }; .midiAction.midi: Note[] ``` 以`x1`为主序,升序排列。 而另一种设计体现在了“音符绘制”上。 ### 绘制 音轨越上,图层越上(此处图层指canvas内绘制顺序等效得到的图层)。然而,midi的数据结构非常扁平,不适合用于绘制。于是维护了一个`insight`数组,表示**当前视野中**各个通道的音符,数据结构如下: ```js .midiAction.insight = [ // 音轨的Array Note[], // 第一音轨的音符列表 ... ] ``` `insight`的更新条件较为复杂,详见代码注释。 ### 交互 关键鼠标操作如何改变状态。效果描述: 鼠标按下: - 如果按在空白则新建音符,进入调整时长模式 - 如果按在音符上: ctrl是否按下? - 按下:选择多个 - 没按下:是否已经选择了多个? - 是:鼠标抬起的时候,如果之前有拖动则什么也不做,否则仅选中当前那个 - 否:仅选一个 判断点击位置: - 前一半:后面的是拖动模式 - 后一半:后面的是调整时长模式 无论是那种模式,都支持音高上的调整 如何添加音符? 1. 点击的时候确认位置,已经添加进去了。 2. 设置这个音符为选中,模式是调整时长。 选中有两个方案: 1. 设置一个选中列表,存选中的midi音符对象的地址 有一个难点:绘制的时候如何让选中的不绘制两次? 2. 每个音符设置一个选中状态 有一个难点:每次调整音符状态的时候,都需要遍历所有音符 结论是:两者结合,空间换时间。 ## 音轨 音轨和音符仅仅通过音符的`ch`属性进行关联。音轨管理的是音色和显式层级,大多时候仅需作为一个字典供外部读取。 然而音轨涉及到UI操作,UI操作会改变midi数据;因此需要向外传递信息,故使用event与外界进行单向交流。耦合关系: `MidiAction`监听`ChannelList`的事件,而`ChannelList`不监听`MidiAction`,但受其控制(指可以调用其方法)。 - `ChannelList`->音轨变化(顺序、个数)->`MidiAction`&`MidiPlayer` 如何传递这个变化?改变顺序用reorder事件,删除用remove事件,添加似乎不涉及midi音符的操作。【修正:新增channel也需要事件,用于存档】 删除一个channel时,先触发remove,再触发reorder,remove事件用于删除midi列表对应通道的音符,reorder用于更改剩下的音符的音轨序号 由于reorder只在序号发生变化时触发,如果是最后一个删除或添加就不会触发,这意味着对此事件监听不能响应所有变化,那如何设置存档点?存档单独注册一个reorder的监听,add/remove前先取消注册,由add/remove自行设置存档,操作结束再注册回来,防止两次存档。 - `ChannelList`->音轨音量改变->`MidiPlayer` - `ChannelList`<-选中音符<-`MidiAction` 这样的设计下,“音轨”完全可以作为一个独立的库:`MidiAction`单向依赖`ChannelList`。 ## 播放同步 在每次animationFrame中,首要做的就是查询音频播放进度,更新系统时间。 然后是合成器播放音符。每次连续播放都会维护一个“音符播放进度”,每次预测下一帧会播放哪些音符,并使用`Web audio API`精确强大的schedule实现精确延时播放。 ## 撤销 本想改了什么存什么(以节省内存),但是没存的会丢失当前信息,所以必须midi、channel、beat都存快照。 ## 合成器 参考 https://github.com/g200kg/webaudio-tinysynth 完成了精简版的合成器,相比原版,有如下变化: - 抽象为类,音色变成static属性。 - 用animationFrame而非timeInterval实现了音符检查与停止。 - 为了契合“动态音轨”的设计,合成器中以channel为单位组织数组,而非原版以audioNode为单位。 - 每个音轨的原型都是合成器,故可以单独拿出来使用。 - 没有做成midi的形式,音符频率依赖外部传参 - 没有实现通道的调制、左右声道、混响。 - 没有做鼓的音色。 ## 不依赖音频的空白画布,即midi编辑器模式 由于使用了扒谱架构,同样需要确定时间精度(和一般midi编辑器不一样),因此需要复用onfile逻辑。 思想是替代Audio类,整理一下需要实现的功能: - AudioPlayer.update: 用到了audio.readyState,audio.paused,audio.cuttentTime(更新app.time、重复区间) - audio.readyState判断是否可以播放 - 设置audio.currentTime可以指定位置播放 - 设置audio.playbackRate可以指定播放速度 - 还有一些handler在createAudio中。 因此有了`fakeAudio.js`。 其次是Spectrogram._spectrogram,需要全部置为零(供绘制用)此外,查询Spectrogram._spectrogram以获取是否已经分析(onfile中据此判断是工作区否有文件,鼠标事件据此判断是否绘制音符) 于是设计了一个proxy,有length属性,用[][]访问总是零。 FakeAudio和这个Proxy的连接点在于时长,midi编辑器模式下总时长是会变的。于是借助setter完成了两者的数据关联。同时xnum也要能改变,于是也改为了setter。 ## 插件(plugins文件夹) 此处插件特指有独立可视化需求的功能,比如“和弦识别”,需要绘制识别结果。这些功能并非必须,为了保持核心代码的简洁,不在`App`类中实例化,而是在实例化后外部注入。 ## 其他(碎碎念) ## 去掉等待的动画 指一边分析一边把频谱绘制出来。改的地方:Array不能初始化好长度,每次应该用push添加元素造成Array.length在增加。每次更新进度条的地方改成频谱赋值。 这样确实能看到频谱生长出来,但是分析会导致此时的UI操作很卡顿。解决这个问题需要开worker后台计算,每次移交一个时刻的频谱。用了worker就不能双击打开了,不做。 此外这样意味着音频要先加载,如果出错了,会出现一堆未定义事件。 所以还是放弃。 ### 关于Web Auido API的自动采样 当AudioContext的采样率和输入音频的采样率不一样的时候会发是什么? https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html搜索“resample”可以看到会重新采样。问题是:是否会抗混叠滤波? 测试:首先创建了一个只含有一个G7音符(3136Hz)的midi,然后利用musescore转为WAV,采样率选择44100Hz。导入分析后,频谱符合预期。 改变AudioContext的采样率为4186Hz,如果抗混叠滤波,则这个G7肯定要被滤除。如果不抗混叠,则混叠到3136-(4186/2)=1043,位于C6(1046Hz)。 结果是在C6处出现了能量。所以不会抗混叠。 ================================================ FILE: index.html ================================================ noteDigger~在线扒谱
  • 导入音频
  • 导入midi
  • MIDI编辑器模式
  • 导出当前进度
  • 导出为midi

EQ设置(dB)

请先上传音频!
  • 调性分析
  • 节奏分析
    自动节奏型
  • 自动填充
    在新轨道中
    黑  红
  • 去除谐波
  • 数字谱对齐音频
  • 人工智障扒谱
  • 音色分离扒谱
  • 宽度
  • 高度
  • 遮罩厚度
  • 最短节拍宽
  • 谐波数
  • 精准设置重复区间
    ~
================================================ FILE: jsconfig.json ================================================ { "compilerOptions": { "target": "ES2023", "checkJs": false, // 不启用类型检查 因为用了很多流氓写法 "allowJs": true, // 允许分析JS文件 "noEmit": true // 不生成输出文件 }, "exclude": ["node_modules"] } ================================================ FILE: lib/beatBar.js ================================================ // 本文件用于管理小节信息,实现了稀疏存储小节的数据结构 class aMeasure { /** * 构造一个小节 * @param {number | aMeasure} beatNum 分子 几拍为一小节; 如果是aMeasure对象则复制构造 * @param {number} beatUnit 分母 几分音符是一拍 * @param {number} interval 一个小节的时间,单位ms */ constructor(beatNum = 4, beatUnit = 4, interval = 2000) { if (typeof beatNum === 'number') { this.beatNum = beatNum; this.beatUnit = beatUnit; this.interval = interval; } else { // 复制构造 this.beatNum = beatNum.beatNum; this.beatUnit = beatNum.beatUnit; this.interval = beatNum.interval; } } static fromBpm(beatNum, beatUnit, bpm) { let interval = 60000 * beatNum / bpm; return new aMeasure(beatNum, beatUnit, interval); } copy(obj) { this.beatNum = obj.beatNum; this.beatUnit = obj.beatUnit; this.interval = obj.interval; return this; } // 不关注bpm,而关注interval。所以修改了beatNum会导致bpm变化 get bpm() { return 60000 / this.interval * this.beatNum; } set bpm(value) { this.interval = 60000 * this.beatNum / value; } isEqual(other) { return this.interval === other.interval && this.beatNum === other.beatNum && this.beatUnit === other.beatUnit; } } // extended aMeasure class eMeasure extends aMeasure { /** * 构造一个有位置信息的小节 * @param {number | eMeasure} id 小节号 或 eMeasure对象(复制构造) * @param {number} start 小节开始时间 单位ms * @param {number | aMeasure} beatNum * @param {number} beatUnit * @param {number} interval */ constructor(id = 0, start = 0, beatNum, beatUnit, interval) { if(typeof id === 'number') { super(beatNum, beatUnit, interval); this.id = id; // 第几小节 this.start = start; // 开始的时间 单位ms } else { super(id); this.id = id.id; this.start = id.start; } } /** * 基于某个小节构造一个新的小节 * @param {eMeasure} base 同类型的小节 * @param {number} id 小节号 * @param {aMeasure} measure 如果要修改值就传 否则参数同base * @returns */ static baseOn(base, id, measure = undefined) { return new eMeasure(id, (id - base.id) * base.interval + base.start, measure || base); } } class Beats extends Array { /** * 构造一个稀疏数组,只存储节奏变化 * @param {number} maxTime 乐曲时长 单位ms */ constructor(maxTime = 60000) { super(1); this.maxTime = maxTime; // 用于迭代 this[0] = new eMeasure(0, 0); } /** * 找到当前小节模式的小节头 * @param {number} at 当前小节的时间或小节号 * @param {boolean} timeMode at是否表示毫秒时间 * @returns {number} 小节头在实际数组中的位置 */ getBaseIndex(at, timeMode = false) { let attr = timeMode ? 'start' : 'id'; for (let i = this.length - 1; i >= 0; i--) { if (this[i][attr] <= at) return i; } return -1; } /** * 迭代器屏蔽了数组的稀疏性 如要连续取值,在元素多的时候效果比getMeasure(id)好 * 注意传入的参数需要自行匹配好,否则后果未知 建议用this.iterator()代替此函数 * @param {number} index 开始的序号 * @param {number} baseAt 基于的eMeasure对象在实际数组中的位置 * @returns next() */ [Symbol.iterator](index = 0, baseAt = 0) { return { next: () => { // 确定base let nextBase = this[baseAt + 1]; if (nextBase && nextBase.id === index) baseAt++; else nextBase = this[baseAt]; // 得到小节信息 let value = eMeasure.baseOn(nextBase, index++); // 判断是否越界 if (value.start >= this.maxTime) return { done: true }; return { value: value, done: false }; } }; } /** * 从任意位置开始的迭代器 * @param {number} at 位置 * @param {boolean} timeMode at是否表示毫秒时间 * @returns 迭代器 */ iterator(at, timeMode = false) { // 由于在绘制更新中使用,故没有复用getBaseIndex以加速运行 let attr = timeMode ? 'start' : 'id'; for (let i = this.length - 1; i >= 0; i--) { if (this[i][attr] <= at) { let id = timeMode ? this[i].id + ((at - this[i].start) / this[i].interval) | 0 : at; return this[Symbol.iterator](id, i); } } return { next: () => ({ done: true }) } } /** * 根据小节号返回一个只读的小节 * @param {number} at 小节号或覆盖该时刻的小节 * @param {boolean} timeMode 传入的是否是时间 * @returns {eMeasure} 小节信息,修改返回值不会影响原数组 如果越界则返回null */ getMeasure(at, timeMode = false) { let i = this.getBaseIndex(at, timeMode); if (i == -1) return null; let id = timeMode ? this[i].id + ((at - this[i].start) / this[i].interval) | 0 : at; let m = eMeasure.baseOn(this[i], id); if (m.start >= this.maxTime) return null; return m; } /** * 返回一个可以修改的对象。若修改返回值会影响原数组,修改后应调用this.check() * @param {number} at 修改第几小节或覆盖该时间的小节 * @param {aMeasure} measure 小节信息 传递后也需要外界调用this.check()来确认设置 * @param {boolean} timeMode at是否表示毫秒时间 * @param {boolean} returnIdx 是否返回索引而不是对象 * @returns {eMeasure} 可以修改的对象 如果越界则返回null returnIdx=true则返回索引 */ setMeasure(at, measure = undefined, timeMode = false, returnIdx = false) { let i = this.getBaseIndex(at, timeMode); if (i == -1) return null; // 检查id是否存在 如果不存在就找到第一个data.id > id的位置插入 let id = timeMode ? this[i].id + ((at - this[i].start) / this[i].interval) | 0 : at; if (this[i].id == id) { if (measure) this[i].copy(measure); if (returnIdx) return i; return this[i]; } if (this[i].id < id) { // 不管是否重复 重复性的检查交给check let m = eMeasure.baseOn(this[i], id, measure); if (m.start >= this.maxTime) return null; this.splice(i + 1, 0, m); if (returnIdx) return i + 1; return m; } } /** * 整理小节信息: * 1. 合并前后参数一样的小节 (由merge控制是否合并) * 2. 校准每个小节的开始时间 * 应该在添加、删除、修改数组元素后调用 需要手动调用 * 在鼠标操作预览时不应合并小节 (会造成中途小节丢失) */ check(merge = true) { this[0].start = 0; this[0].id = 0; for (let i = 0, end = this.length - 1; i < end; i++) { if (this[i].start > this.maxTime) { this.splice(i); return; } if (merge && this[i].isEqual(this[i + 1])) { this.splice(i + 1, 1); i--; end--; } else this[i + 1].start = (this[i + 1].id - this[i].id) * this[i].interval + this[i].start; } } /** * 删除一个小节 * @param {number} at 位置 * @param {boolean} timeMode at是否表示毫秒时间 */ delete(at, timeMode = false) { let attr = timeMode ? 'start' : 'id'; for (let i = this.length - 1; i >= 0; i--) { if (this[i][attr] <= at) { // 如果只有一个小节,则删除小节头 if (this[i + 1] && this[i].id === this[i + 1].id) { // this[i+1].id不用减1,因为已经减过了 this.splice(i, 1); } break; } this[i].id--; // 后面的都前移一格 } this.check(); } /** * 增加一个小节,小节属性同前一个小节 * @param {number} at 位置 * @param {boolean} timeMode at是否表示毫秒时间 */ add(at, timeMode = false) { let attr = timeMode ? 'start' : 'id'; for (let i = this.length - 1; i >= 0; i--) { if (this[i][attr] <= at) break; this[i].id++; // 后面的都后移一格 } this.check(); } /** * 拷贝数据 用户撤销恢复 * @param {Beats} beatArray * @returns {Beats} this */ copy(beatArray) { this.length = beatArray.length; for (let i = beatArray.length - 1; i >= 0; i--) { this[i] = new eMeasure(beatArray[i]); } return this; } } ================================================ FILE: lib/fakeAudio.js ================================================ /** * 模拟没有声音、时长可变的Audio。模拟了: * 设置currentTime跳转播放位置 * 设置playbackRate改变播放速度 * play()和pause()控制播放 * 到duration后自动停止,触发onended * duration改变后,触发ondurationchange * 构造后,下一个时刻触发ondurationchange和onloadeddata */ function FakeAudio(duration = Infinity) { this.readyState = 4; this.paused = true; this.volume = 0; // 废物属性 this.loop = false; // 是否循环。和下面的_loop不一样 this._currentTime = 0; this._duration = duration; this._playbackRate = 1; this._loop = 0; this._beginTime = 0; this._lastTime = 0; this.onended = Function.prototype; this.onloadeddata = Function.prototype; this.ondurationchange = Function.prototype; const update = (t) => { let dt = t - this._beginTime; this._currentTime = this._lastTime + dt * this._playbackRate / 1000; if (this._currentTime >= this._duration) { if (this.loop) { this.currentTime = 0; } else { this.pause(); this.onended(); return; } } this._loop = requestAnimationFrame(update); }; this.pause = () => { cancelAnimationFrame(this._loop); this._lastTime = this._currentTime; this.paused = true; } this.play = () => { if (this._currentTime >= this._duration) this._lastTime = this._currentTime = 0; this._beginTime = document.timeline.currentTime; this._loop = requestAnimationFrame(update); this.paused = false; } Object.defineProperty(this, 'currentTime', { get: function () { return this._currentTime; }, set: function (t) { if (t < 0) t = 0; if (t > this._duration) t = this._duration; this._lastTime = this._currentTime = t; this._beginTime = document.timeline.currentTime; } }); Object.defineProperty(this, 'playbackRate', { get: function () { return this._playbackRate; }, set: function (r) { this._playbackRate = r; this.currentTime = this._currentTime; } }); Object.defineProperty(this, 'duration', { get: function () { return this._duration; }, set: function (d) { if (d < 0) return; this._duration = d; this.ondurationchange(); } }); // 给设置handler留时间 setTimeout(() => { this.ondurationchange(); this.onloadeddata(); }, 0); } ================================================ FILE: lib/midi.js ================================================ /** * 对midi事件进行封装 * 相比于原生midi事件: * - 使用绝对时间(在导出为二进制时被mtrk转换为相对时间) * - 不记录通道信息(在导出为二进制时由mtrk加上通道信息) */ class midiEvent { ticks; // 绝对时间 无需是整数 因为export时会被mtrk.tick_hex转为整数 code; // 必须是整数 由构造函数保证,但不限制范围 value; // 每一项必须是整数 由构造函数保证,但不限制范围 // 范围的限制由static方法保证 /** * 用参数创建一个事件 * @param {number} ticks 绝对时间,单位tick。若tisks == -1, 在mtrk.addEvent时会自动使用last_tick; 若<-1, 则last_tick - this.ticks(此时代表相对时间) * @param {number} code 如果有channel,则去掉channel,如0x91 -> 0x9;如果是0xf0则保留此编码;如果是0xff则需要加上后面的type,如0xff51 * @param {Array} value 数组,代表其余所有参数 */ #constructor_args(ticks, code, value) { this.ticks = ticks; this.code = code; if (value instanceof Number) this.value = [value]; else this.value = value; return this; } /** * 根据已经创建的对象创建事件 * @param {Object} eventObj 一个对象,包含ticks, code, value * @param {boolean} reference 是否引用 默认true */ #constructor_obj(eventObj, reference = true) { if (reference) { if (eventObj instanceof midiEvent) return eventObj; Object.setPrototypeOf(eventObj, midiEvent.prototype); return eventObj; } else { this.ticks = eventObj.ticks; this.code = eventObj.code; this.value = eventObj.value; return this; } } /** * 根据参数数目选择不同的构造函数创建事件。会把非整数转为整数 * @param 参考构造函数#constructor_args和#constructor_obj * @returns midiEvent */ constructor() { let e = (arguments.length == 3) ? this.#constructor_args(...arguments) : this.#constructor_obj(...arguments); // 数据整数化 for (let i = 0; i < e.value.length; i++) e.value[i] = Math.round(e.value[i]); e.code = e.code | 0; return e; } /** * 针对0xff事件的type * code存的是0xff<<8+type,所以type是code的低8位 */ get type() { if (this.code >= 0xff) return this.code & 0xff; return void 0; } /** * 导出为二进制数据,要求this.ticks是绝对时间(非负数) * 应由mtrk调用,可以保证this.ticks是绝对时间(调用mtrk.addEvent时会转换相对为绝对) * @param {number} current_tick 本事件发生前的时间 * @param {number} channel midi通道,对0xff??和0xf0事件无效 * @returns {Array} midi二进制数据数组的数组 */ export(current_tick = 0, channel = 0) { const d = mtrk.tick_hex(this.ticks - current_tick); if (this.code >= 0xf0) { if (this.code == 0xf0) d.push(0xf0, this.value.length); else d.push(0xff, this.type, this.value.length); } else d.push((this.code << 4) + channel); d.push(...this.value); return d; } static note(at, duration, note, intensity) { if (note < 0 || note > 127) { if (midi.autoFix) note = mtrk.constrain(note, 0, 127); else throw new Error('note should be in [0, 127]'); } if (intensity < 0 || intensity > 127) { if (midi.autoFix) intensity = mtrk.constrain(intensity, 0, 127); else throw new Error('note intensity should be in [0, 127]'); } return [new midiEvent({ ticks: at, code: 0x9, value: [note, intensity] }), new midiEvent({ ticks: at >= 0 ? at + duration : -duration, code: 0x9, value: [note, 0] })]; } static instrument(at, instrument) { if (instrument < 0 || instrument > 127) { if (midi.autoFix) instrument = mtrk.constrain(instrument, 0, 127); else throw new Error('instrument should be in [0, 127]'); } return new midiEvent({ ticks: at, code: 0xc, value: [instrument] }); } static control(at, id, Value) { return new midiEvent({ ticks: at, code: 0xb, value: [id, Value] }); } static tempo(at, bpm) { bpm = Math.round(60000000 / bpm); return new midiEvent({ ticks: at, code: 0xff51, value: mtrk.number_hex(bpm, 3) }); } static time_signature(at, numerator, denominator) { return new midiEvent({ ticks: at, code: 0xff58, value: [numerator, Math.floor(Math.log2(denominator)), 0x18, 0x8] }); } /** * 切换端口,以实现超过16个音轨 * 一般不需要手动调用,在mtrk.export时会自动判断与调用 * @param {number} port * @returns {midiEvent} */ static port(port = 0) { return new midiEvent({ ticks: 0, // 这种事件一定得发生在第一个 code: 0xff21, value: [port] }); } } // 一个音轨 class mtrk { // 限制数据范围 static constrain(value, min = 0, max = 127) { return Math.min(max, Math.max(min, value)); } /** * 将tick数转换为midi的时间格式 * @param {number} ticknum float,但会转换为int * @returns {number[]} midi tick array * @example mtrk.tick_hex(555555) // [0x08, 0x7A, 0x23] */ static tick_hex(ticknum) { ticknum = Math.round(ticknum).toString(2); let i = ticknum.length, j = Math.ceil(i / 7) * 7; for (; i < j; i++) ticknum = '0' + ticknum; const t = Array(); for (i = 0; i + 7 < j; i = i + 7) t.push('1' + ticknum.substring(i, i + 7)); t.push('0' + ticknum.substr(-7, 7)); for (i = 0; i < t.length; i++) t[i] = parseInt(t[i], 2); return t; } /** * 将字符串转换为UTF-8数组 * @param {string} name string * @param {number} x array's length (default:self-adaption) * @returns {number[]} byte array * @example mtrk.string_hex("example",3) // [101,120,97] */ static string_hex(str, maxBytes = -1) { const encoder = new TextEncoder(); const bytes = encoder.encode(str); if (maxBytes > 0) { const result = new Array(maxBytes).fill(0); const len = Math.min(maxBytes, bytes.length); for (let i = 0; i < len; i++) result[i] = bytes[i]; return result; } return Array.from(bytes); } /** * 将UTF-8数组转换为字符串 * @param {Array} bytes byte array * @returns {string} */ static hex_string(bytes) { const decoder = new TextDecoder(); return decoder.decode(new Uint8Array(bytes)); } /** * 将一个正整数按16进制拆分成各个位放在数组中, 最低位在数组最高位 * @param {number} num float,但会转换为int * @param {number} x array's length (default:self-adaption) * @returns {number[]} * @example mtrk.number_hex(257,5) // [0,0,0,1,1] */ static number_hex(num, x = -1) { num = Math.round(num); if (x > 0) { let Buffer = Array(x).fill(0); for (--x; x >= 0 && num != 0; x--) { Buffer[x] = num & 0xff; num = num >> 8; } return Buffer; } else { let len = 0; let num2 = num; while (num2 != 0) { num2 = num2 >> 8; len++; } let Buffer = Array(len); for (--len; len >= 0; len--) { Buffer[len] = num & 0xff; num = num >> 8; } return Buffer; } } constructor(name = "", event_list = Array()) { this.name = name; this.events = event_list; this.last_tick = 0; // 最后一个事件的时间 } /** * 向mtrk添加事件 可以传入数组或一个个传递 * @param {midiEvent || Object} event {ticks,code,value} 可以是midiEvent对象,也可以是一般对象(会转为midiEvent) * @returns event (or event list, or event list nesting) * @example m.addEvent({ticks:0,code:0x9,value:[40,100]}); m.addEvent(midiEvent.tempo(0,120)); */ addEvent(event) { if (arguments.length > 1) event = Array.from(arguments); const addevent = (e) => { if (e.ticks < 0) { if (e.ticks == -1) e.ticks = this.last_tick; else e.ticks = this.last_tick - e.ticks; } this.events.push(new midiEvent(e)); if (e.ticks > this.last_tick) this.last_tick = e.ticks; } const parseEvents = (el) => { if (Array.isArray(el)) { for (let i = 0; i < el.length; i++) parseEvents(el[i]); } else addevent(el); } parseEvents(event); return event; } /** * 对齐事件 * @param {number} tick 一个四分音符的tick数 * @param {number} accuracy int, 精度, 越大允许的最短时长越小 */ align(tick, accuracy = 4) { accuracy = tick / parseInt(accuracy); for (let i = 0; i < this.events.length; i++) { this.events[i].ticks = Math.round(this.events[i].ticks / accuracy) * accuracy; } } /** * 事件按时间排序,同时间的音符事件则按力度排序 * 其余同时事件将code大的排在前面 */ sort() { this.events.sort((a, b) => { if(a.ticks == b.ticks) { if(a.code == b.code && a.code == 9) return a.value[1] - b.value[1]; return b.code - a.code; } return a.ticks - b.ticks; }); } /** * 将mtrk转换为track_id音轨上的midi数据 * @param {number} track_id int, [0, 15] * @returns {number[]} midi binary data array */ export(track_id) { this.sort(); // 音轨名 let data = []; if (this.name.length) { data = mtrk.string_hex(this.name); data = [0, 255, 3, data.length, ...data]; } // 多于16轨的支持 let channel = track_id % 16; let port = track_id >> 4; if (port > 0) { data.push(...midiEvent.port(port).export(0, 0)); } // 事件解析 let current = 0; for (let i = 0; i < this.events.length; i++) { let temp = this.events[i]; data.push(...temp.export(current, channel)); current = Math.round(temp.ticks); // 避免误差累积 tick_hex用的是round } return [77, 84, 114, 107].concat( mtrk.number_hex(data.length + 4, 4), data, 0, 255, 47, 0 ); } /** * 将音轨转为可JSON对象 * @param {number} track_id 音轨所属轨道id (从0开始) * @returns {Object} json */ JSON(track_id) { this.sort(); const Notes = [], controls = [], Instruments = [], Tempos = [], TimeSignatures = []; for (let i = 0; i < this.events.length; i++) { let temp = this.events[i]; switch (temp.code) { case 0x9: if (temp.value[1] > 0) { // 力度不为0表示按下 let overat = temp.ticks; for (let j = i + 1; j < this.events.length; j++) { let over = this.events[j]; if (over.code == 0x9 && over.value[0] == temp.value[0]) { overat = over.ticks; if (overat > temp.ticks) { Notes.push({ ticks: temp.ticks, durationTicks: overat - temp.ticks, midi: temp.value[0], intensity: temp.value[1] }); break; } } } } break; case 0xb: controls.push({ ticks: temp.ticks, controller: temp.value[0], value: temp.value[1] }) break; case 0xc: Instruments.push({ ticks: temp.ticks, number: temp.value[0] }); break; default: // 0xffxx switch (temp.type) { case 0x51: // 速度 Tempos.push({ ticks: temp.ticks, bpm: Math.round(60000000 / ((temp.value[0] << 16) + (temp.value[1] << 8) + temp.value[2])) }); break; case 0x58: // 节拍 TimeSignatures.push({ ticks: temp.ticks, timeSignature: [temp.value[0], 1 << temp.value[1]] }); break; } break; } } return { channel: track_id, name: this.name, tempos: Tempos, controlChanges: controls, instruments: Instruments, notes: Notes, timeSignatures: TimeSignatures } } toJSON(track_id) { return this.JSON(track_id); } } class midi { static autoFix = false; // 是否自动修正异常数据;为false会抛出异常 /** * midi文件,组织多音轨 * @param {number} bpm beats per minute * @param {Array} time_signature [numerator, denominator] 4/4 -> [4,4] * @param {number} tick default 480 * @param {Array} Mtrk initial with exist mtrk list * @param {string} Name midi file name */ constructor(bpm = 120, time_signature = [4, 4], tick = 480, Mtrk = [], Name = 'untitled') { this.bpm = bpm; this.Mtrk = Mtrk; // Array this.tick = tick; // 一个四分音符的tick数 this.time_signature = time_signature; this.name = Name; } /** * 添加音轨,如果无参则创建并返回 * @param {mtrk} newtrack null则创建新音轨 * @param {number} channel_id 指定音轨位置,默认-1表示添加到最后 * @returns {mtrk} 新添加的音轨 * @example track = m.addTrack(); m2.addTrack(new mtrk("test")) */ addTrack(newtrack = null, channel_id = -1) { if (newtrack == null) newtrack = new mtrk(String(this.Mtrk.length)); if (channel_id >= 0) { if (channel_id < this.Mtrk.length) this.Mtrk.splice(channel_id, 0, newtrack); else this.Mtrk[channel_id] = newtrack; } else this.Mtrk.push(newtrack); return newtrack; } get tracks() { // 起个别名 return this.Mtrk; } /** * 对齐所有音轨 修改自身 * @param {number} accuracy 对齐精度 */ align(accuracy = 4) { for (let i = 0; i < this.Mtrk.length; i++) this.Mtrk[i].align(this.tick, accuracy); } /** * 解析midi文件,返回新的midi对象 * 由于设计时认为同一音轨只操控一个通道,因此对于一个音轨操作多个通道的midi文件会有改动 * @param {Uint8Array} midi_file midi数据 * @param {boolean} which_main 1则以音轨为主,把同一音轨的通道置为相同;2则通道为主,一个通道一个音轨;0则根据midi类型判断,midi1则音轨为主,midi0则通道为主。最终都是保证一个音轨对应一个通道 * @returns new midi object */ static import(midi_file, which_main = 0) { // 判断是否为midi文件 if (midi_file.length < 14) return null; if (midi_file[0] != 77 || midi_file[1] != 84 || midi_file[2] != 104 || midi_file[3] != 100) return null; let newmidi = new midi(120, [4, 4], 480, [new mtrk('0')], ''); // 第一轨放全局控制事件 // 读取文件头 newmidi.tick = midi_file[13] + (midi_file[12] << 8); let mtrkNum = midi_file[11] + (midi_file[10] << 8); let midtype = midi_file[9]; // 读mtrk音轨 for (let n = 0, i = 14; n < mtrkNum; n++) { // 判断是否为MTrk音轨 if (midi_file[i++] != 77 || midi_file[i++] != 84 || midi_file[i++] != 114 || midi_file[i++] != 107) { n--; i -= 3; continue; } let timeline = 0; // 时间线 let lastType = 0xC0; // 上一个midi事件类型 let lastChaneel = n - 1; // 上一个midi事件通道 let mtrklen = (midi_file[i++] << 24) + (midi_file[i++] << 16) + (midi_file[i++] << 8) + midi_file[i++] + i; let midiPort = 0; // 默认的端口号 // 读取事件 for (; i < mtrklen; i++) { // 时间间隔(tick) let flag = 0; while (midi_file[i] > 127) flag = (flag << 7) + midi_file[i++] - 128; timeline += (flag << 7) + midi_file[i++]; // 事件类型 let type = midi_file[i] & 0xf0; let channel = midi_file[i++] - type; let ichannel = n; switch (which_main) { case 1: ichannel = n; break; case 2: ichannel = (midiPort << 4) + channel; break; default: ichannel = (midtype == 0) ? ((midiPort << 4) + channel) : n; break; } if (!newmidi.Mtrk[ichannel]) newmidi.addTrack(new mtrk(), ichannel); do { flag = false; switch (type) { // 结束后指向事件的最后一个字节 case 0x90: // 按下音符 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0x9, value: [midi_file[i++], midi_file[i]] }); break; case 0x80: // 松开音符 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0x9, value: [midi_file[i++], 0] }); break; case 0xF0: // 系统码和其他格式 if (channel == 0xF) { switch (midi_file[i++]) { case 0x2f: break; case 0x03: // 给当前mtrk块同序号的音轨改名 newmidi.Mtrk[n].name = mtrk.hex_string(midi_file.slice(i + 1, i + 1 + midi_file[i])); break; case 0x21: midiPort = midi_file[i + 1]; break; //== 不break,进入default添加事件。所以这后面的都要加`if(timeline == 0)`保证能到default ==// case 0x58: if (timeline == 0) { newmidi.time_signature = [midi_file[i + 1], 1 << midi_file[i + 2]]; break; } case 0x51: if (timeline == 0) { newmidi.bpm = Math.round(60000000 / ((midi_file[i + 1] << 16) + (midi_file[i + 2] << 8) + midi_file[i + 3])); break; } default: // 没有通道的统一加到第一轨 newmidi.Mtrk[0].addEvent({ ticks: timeline, code: (0xff << 8) + midi_file[i - 1], value: Array.from(midi_file.slice(i + 1, i + 1 + midi_file[i])) }); break; } } else { // 系统码 newmidi.Mtrk[0].addEvent({ ticks: timeline, code: 0xf0, value: Array.from(midi_file.slice(i + 1, i + 1 + midi_file[i])) }); } i += midi_file[i]; break; case 0xB0: // 控制器 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0xb, value: [midi_file[i++], midi_file[i]] }); break; case 0xC0: // 改变乐器 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0xc, value: [midi_file[i]] }); break; case 0xD0: // 触后通道 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0xd, value: [midi_file[i]] }); break; case 0xE0: // 滑音 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0xe, value: [midi_file[i++], midi_file[i]] }); break; case 0xA0: // 触后音符 newmidi.Mtrk[ichannel].addEvent({ ticks: timeline, code: 0xa, value: [midi_file[i++], midi_file[i]] }); break; default: type = lastType; channel = lastChaneel flag = true; i--; break; } } while (flag); lastType = type; lastChaneel = channel; } } newmidi.name = newmidi.Mtrk[0].name; // 移除除了第一轨以外的空音轨(没有音符的音轨) for (let i = 1; i < newmidi.Mtrk.length; i++) { let temp = newmidi.Mtrk[i]; if (!temp) continue; temp = temp.events; let hasNote = false; for (let j = 0; j < temp.length; j++) { if (temp[j].code == 0x9) { hasNote = true; break; } } if (!hasNote) newmidi.Mtrk[i] = void 0; } return newmidi; } /** * 转换为midi数据 * @param {number} type midi file type [0 or 1(default)] * @returns {Uint8Array} */ export(type = 1) { if (type == 0) { // midi0创建 由于事件不记录音轨,需要归并排序输出 let Mtrks = Array(this.Mtrk.length + 1); for (let i = 0; i < this.Mtrk.length; i++) { this.Mtrk[i].sort(); Mtrks[i] = this.Mtrk[i].events; } Mtrks[this.Mtrk.length] = new mtrk("head", [ midiEvent.tempo(0, this.bpm), midiEvent.time_signature(0, this.time_signature[0], this.time_signature[1]) ]); let current = 0; let index = Array(Mtrks.length).fill(0); let data = []; while (true) { // 找到ticks最小项 let min = -1; let minticks = 0; for (let i = 0; i < index.length; i++) { if (index[i] < Mtrks[i].length) { if (min == -1 || Mtrks[i][index[i]].ticks < minticks) { min = i; minticks = Mtrks[i][index[i]].ticks; } } } if (min == -1) break; // 转为midi数据 let d = null; let temp = Mtrks[min][index[min]]; if (temp.code >= 0xf0) { if (temp.code == 0xf0) d = [0xf0, temp.value.length]; else d = [0xff, temp.type, temp.value.length]; } else d = (temp.code << 4) + min; data = data.concat(mtrk.tick_hex(temp.ticks - current), d, temp.value); // 善后 current = minticks; index[min]++; } data = [0, 255, 3, 5, 109, 105, 100, 105, 48, ...data, 0, 255, 47, 0]; // 加了音轨名和结尾 return new Uint8Array([ 77, 84, 104, 100, 0, 0, 0, 6, 0, 0, 0, 1, ...mtrk.number_hex(this.tick, 2), 77, 84, 114, 107, ...mtrk.number_hex(data.length, 4), ...data ]); } else { // 除了初始速度、初始节拍,其余ff事件全放0音轨。头音轨不在Mtrk中,export时生成 // MThd创建 const data = [ [77, 84, 104, 100, 0, 0, 0, 6, 0, 1], undefined, // 通道数 之后再填,因为数组可能空洞 mtrk.number_hex(this.tick, 2) ]; // 加入全局音轨 let headMtrk = new mtrk("head", [ midiEvent.tempo(0, this.bpm), midiEvent.time_signature(0, this.time_signature[0], this.time_signature[1]) ]); data.push(headMtrk.export(0)); // 加入其余音轨 let realChannelNum = 1; for (let i = 0; i < this.Mtrk.length; i++) { if (this.Mtrk[i]) { data.push(this.Mtrk[i].export(i)); realChannelNum++; } } data[1] = mtrk.number_hex(realChannelNum, 2); return new Uint8Array([].concat(...data)); } } /** * 将midi转换为json对象。原理:每个音轨转换为json对象并对事件进行合并 * @returns {Object} json */ JSON() { let j = { header: { name: this.name, tick: this.tick, tempos: [{ ticks: 0, bpm: this.bpm }], timeSignatures: [{ ticks: 0, timeSignature: this.time_signature }] }, tracks: [] } for (let i = 0; i < this.Mtrk.length; i++) { if (!this.Mtrk[i]) continue; let t = this.Mtrk[i].JSON(i); j.header.tempos = j.header.tempos.concat(t.tempos); j.header.timeSignatures = j.header.timeSignatures.concat(t.timeSignatures); j.tracks.push({ channel: t.channel, name: t.name, controlChanges: t.controlChanges, instruments: t.instruments, notes: t.notes }); } return j; } toJSON() { return this.JSON(); } } ================================================ FILE: lib/saver.js ================================================ /* 示例 function save() { let B = bSaver.Float32Mat2Buffer(b); let A = bSaver.Object2Buffer(a); bSaver.saveArrayBuffer(bSaver.combineArrayBuffers( [B, A] ), "test.nd"); } var result; function parse() { let input = document.createElement("input"); input.type = "file"; input.onchange = function() { let file = input.files[0]; bSaver.readBinary(file, (arrayBuffer)=>{ let [B, o] = bSaver.Buffer2Float32Mat(arrayBuffer, 0); let [A, o2] = bSaver.Buffer2Object(arrayBuffer, o); result = [A,B]; console.log(result); }) } input.click(); } */ // 保存和读取二进制数据的工具 // 每个数据段开头会有Uint32(可能多个)的长度信息, 用于保存该数据段的长度 window.bSaver = { /** * 将二维的Float32Array的Array转为可解析的一维ArrayBuffer * 要求每个Float32Array的长度相同 * @param {Array} Float32Mat 支持仅有length的对象 * @returns {ArrayBuffer} 二进制数组 开头有两个Uint32的长度信息, 用于保存每个Float32Array的长度和Float32Mat的长度 */ Float32Mat2Buffer(Float32Mat) { // 先保存两个维度的长度: 每个Float32Array的长度和Float32Mat的长度 const lengthArray = new Uint32Array([Float32Mat[0]?.length ?? 0, Float32Mat.length]); let bn = Float32Mat[0]?.byteLength ?? 0; if (bn === 0) return lengthArray.buffer; let offset = lengthArray.byteLength; const finalArrayBuffer = new ArrayBuffer(offset + bn * Float32Mat.length); new Uint32Array(finalArrayBuffer, 0, 2).set(lengthArray); // 再将每个Float32Array的数据拷贝到finalArrayBuffer中 for (const floatArray of Float32Mat) { new Float32Array(finalArrayBuffer, offset).set(floatArray); offset += bn; } return finalArrayBuffer; }, /** * 解析Float32Mat2Buffer得到的二进制数组为二维的Float32Array的Array * @param {ArrayBuffer} arrayBuffer 待解析的二进制数组 * @param {number} offset 读取的byte偏移量 * @returns {[Array, Number]} 解析后的二维Float32Array数组和读取结束后的byte偏移量 */ Buffer2Float32Mat(arrayBuffer, offset = 0) { offset = Math.ceil(offset / 4) << 2; // offset变为4的倍数 let lengthArray = new Uint32Array(arrayBuffer, offset, 2); offset += lengthArray.byteLength; let [n, N] = lengthArray; const Float32Mat = new Array(N); if (n === 0) return [Float32Mat, offset]; const mergedFloatArray = Float32Mat.raw = new Float32Array(arrayBuffer, offset, n * N); for (let i = 0, j = 0; i < N; i++, j += n) { Float32Mat[i] = mergedFloatArray.subarray(j, j + n); } return [Float32Mat, offset + mergedFloatArray.byteLength]; }, /** * 将字符串转为可解析的二进制数组 * @param {string} str 字符串 * @returns {ArrayBuffer} 二进制数组 开头有一个Uint32的长度信息记录BinaryData的长度 */ String2Buffer(str) { const jsonBinaryData = new TextEncoder().encode(str); // 用一个Uint32Array保存jsonBinaryData的长度 const lengthArray = new Uint32Array([jsonBinaryData.byteLength]); const finalArrayBuffer = new ArrayBuffer(lengthArray.byteLength + jsonBinaryData.byteLength); new Uint32Array(finalArrayBuffer, 0, 1).set(lengthArray); new Uint8Array(finalArrayBuffer, lengthArray.byteLength).set(new Uint8Array(jsonBinaryData)); return finalArrayBuffer; }, /** * 解析String2Buffer得到的二进制数组为字符串 * @param {ArrayBuffer} arrayBuffer 待解析的二进制数组 * @param {number} offset 读取的byte偏移量 * @returns {[String, Number]} 解析后的对象和读取结束后的byte偏移量 */ Buffer2String(arrayBuffer, offset = 0) { offset = Math.ceil(offset / 4) << 2; // offset变为4的倍数 const lengthArray = new Uint32Array(arrayBuffer, offset, 1); offset += lengthArray.byteLength; const strBinaryData = new Uint8Array(arrayBuffer, offset, lengthArray[0]); const str = new TextDecoder().decode(strBinaryData); return [str, offset + strBinaryData.byteLength]; }, /** * 将一个可以被JSON.stringify的对象转为可解析的二进制数组 * @param {Object} obj 可以被JSON.stringify的对象 * @returns {ArrayBuffer} 二进制数组 开头有一个Uint32的长度信息记录jsonBinaryData的长度 */ Object2Buffer(obj) { return this.String2Buffer(JSON.stringify(obj)); }, /** * 解析Object2Buffer得到的二进制数组为一个可以被JSON.stringify的对象 * @param {ArrayBuffer} arrayBuffer 待解析的二进制数组 * @param {number} offset 读取的byte偏移量 * @returns {[Object, Number]} 解析后的对象和读取结束后的byte偏移量 */ Buffer2Object(arrayBuffer, offset = 0) { let [jsonString, o] = this.Buffer2String(arrayBuffer, offset); return [JSON.parse(jsonString), o]; }, /** * 合并多个ArrayBuffer为一个ArrayBuffer * 会按4byte对齐每一个ArrayBuffer的起始位置 * @param {Array} arrayBuffers ArrayBuffer的数组 * @returns {ArrayBuffer} 合并后的ArrayBuffer */ combineArrayBuffers(arrayBuffers) { let totalByteLength = 0; const lengthArray = arrayBuffers.map((arrayBuffer) => { // 用4字节对齐,因为开头是Uint32的长度信息: start offset of Uint32Array should be a multiple of 4 let len4 = Math.ceil(arrayBuffer.byteLength / 4) << 2; totalByteLength += len4; return len4; }); const combinedArrayBuffer = new ArrayBuffer(totalByteLength); for(let i = 0, offset = 0; i < arrayBuffers.length; i++) { new Uint8Array(combinedArrayBuffer, offset).set(new Uint8Array(arrayBuffers[i])); offset += lengthArray[i]; } return combinedArrayBuffer; }, /** * 将二进制数组保存为文件 * @param {ArrayBuffer} arrayBuffer 待保存的二进制数组 * @param {string} filename 保存的文件名 */ saveArrayBuffer(arrayBuffer, filename) { // 创建一个 Blob 对象,将合并后的 ArrayBuffer 保存为二进制文件 const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' }); // 创建一个临时 URL,用于下载文件 const downloadUrl = URL.createObjectURL(blob); // 创建一个虚拟的下载链接并触发点击事件 const downloadLink = document.createElement('a'); downloadLink.href = downloadUrl; downloadLink.download = filename; downloadLink.click(); // 释放临时 URL 对象 URL.revokeObjectURL(downloadUrl); }, // 读取文件为ArrayBuffer readBinary(file, callback) { const fileReader = new FileReader(); fileReader.onload = (e) => { callback(e.target.result); }; fileReader.readAsArrayBuffer(file); } }; ================================================ FILE: lib/snapshot.js ================================================ // 基于快照的撤销重做数据结构 // 为了不改变数组大小减小开销,使用循环队列 class Snapshot extends Array { /** * 新建快照栈 * @param {number} maxLen 快照历史数 * @param {*} iniState 初始状态 */ constructor(maxLen, iniState = '') { super(maxLen); // 模型位置 从1开始计数 this.now = 1; this.size = 1; this[0] = iniState; // 实际位置 this.pointer = 0; } /** * 增加快照。在当前时间点上延展新的分支,并抛弃老的分支 * @param {*} snapshot 快照 建议是JSON字符串 */ add(snapshot) { if (this.now < this.length) this.size = ++this.now; // 没满 this.pointer = (this.pointer + 1) % this.length; // 目标位置,直接覆盖 this[this.pointer] = snapshot; } /** * 回到上一个快照状态,相当于撤销 * @returns 上一刻的快照。如果无法回退则返回null */ undo() { if (this.now <= 1) return null; this.now--; this.pointer = (this.pointer + this.length - 1) % this.length; return this[this.pointer]; } /** * 重新回到下一个状态,相当于重做 * @returns 下一刻的快照。如果下一状态则返回null */ redo() { if (this.now >= this.size) return null; this.now++; this.pointer = (this.pointer + 1) % this.length; return this[this.pointer]; } /** * 查看上一个快照状态,相当于撤销但不改变当前状态 * @returns 上一个状态的快照。如果无法回退则返回null */ lastState() { if (this.now <= 1) return null; return this[(this.pointer + this.length - 1) % this.length]; } /** * 查看下一个快照状态,相当于重做但不改变当前状态 * @returns 下一个状态的快照。如果下一状态则返回null */ nextState() { if (this.now >= this.size) return null; return this[(this.pointer + 1) % this.length]; } nowState() { return this[this.pointer]; } } ================================================ FILE: lib/tinySynth.js ================================================ // 是https://github.com/g200kg/webaudio-tinysynth的精简版 class TinySynth { static soundFont = {}; // 最终是填补了默认值的TinySynth.wave static defaultWave = { g: 0, w: "sine", t: 1, f: 0, v: 0.5, a: 0, h: 0.01, d: 0.01, s: 0, r: 0.05, p: 1, q: 1, k: 0 }; static instrument = [ /* 1-8 : Piano */ "Acoustic Grand Piano", "Bright Acoustic Piano", "Electric Grand Piano", "Honky-tonk Piano", "Electric Piano 1", "Electric Piano 2", "Harpsichord", "Clavi", /* 9-16 : Chromatic Perc */ "Celesta", "Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", /* 17-24 : Organ */ "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica", "Tango Accordion", /* 25-32 : Guitar */ "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar (muted)", "Overdriven Guitar", "Distortion Guitar", "Guitar harmonics", /* 33-40 : Bass */ "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)", "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", /* 41-48 : Strings */ "Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings", "Pizzicato Strings", "Orchestral Harp", "Timpani", /* 49-56 : Ensamble */ "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2", "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", /* 57-64 : Brass */ "Trumpet", "Trombone", "Tuba", "Muted Trumpet", "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", /* 65-72 : Reed */ "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Bassoon", "Clarinet", /* 73-80 : Pipe */ "Piccolo", "Flute", "Recorder", "Pan Flute", "Blown Bottle", "Shakuhachi", "Whistle", "Ocarina", /* 81-88 : SynthLead */ "Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3 (calliope)", "Lead 4 (chiff)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8 (bass + lead)", /* 89-96 : SynthPad */ "Pad 1 (new age)", "Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)", /* 97-104 : FX */ "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)", /* 105-112 : Ethnic */ "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bag pipe", "Fiddle", "Shanai", /* 113-120 : Percussive */ "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", /* 121-128 : SE */ "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter", "Applause", "Gunshot", ]; static wave = [ /* 1-8 : Piano */ [{ w: "sine", v: .4, d: 0.7, r: 0.1 }, { w: "triangle", v: 3, d: 0.7, s: 0.1, g: 1, a: 0.01, k: -1.2 }], [{ w: "triangle", v: 0.4, d: 0.7, r: 0.1 }, { w: "triangle", v: 4, t: 3, d: 0.4, s: 0.1, g: 1, k: -1, a: 0.01 }], [{ w: "sine", d: 0.7, r: 0.1 }, { w: "triangle", v: 4, f: 2, d: 0.5, s: 0.5, g: 1, k: -1 }], [{ w: "sine", d: 0.7, v: 0.2 }, { w: "triangle", v: 4, t: 3, f: 2, d: 0.3, g: 1, k: -1, a: 0.01, s: 0.5 }], [{ w: "sine", v: 0.35, d: 0.7 }, { w: "sine", v: 3, t: 7, f: 1, d: 1, s: 1, g: 1, k: -.7 }], [{ w: "sine", v: 0.35, d: 0.7 }, { w: "sine", v: 8, t: 7, f: 1, d: 0.5, s: 1, g: 1, k: -.7 }], [{ w: "sawtooth", v: 0.34, d: 2 }, { w: "sine", v: 8, f: 0.1, d: 2, s: 1, r: 2, g: 1 }], [{ w: "triangle", v: 0.34, d: 1.5 }, { w: "square", v: 6, f: 0.1, d: 1.5, s: 0.5, r: 2, g: 1 }], /* 9-16 : Chromatic Perc*/ [{ w: "sine", d: 0.3, r: 0.3 }, { w: "sine", v: 7, t: 11, d: 0.03, g: 1 }], [{ w: "sine", d: 0.3, r: 0.3 }, { w: "sine", v: 11, t: 6, d: 0.2, s: 0.4, g: 1 }], [{ w: "sine", v: 0.2, d: 0.3, r: 0.3 }, { w: "sine", v: 11, t: 5, d: 0.1, s: 0.4, g: 1 }], [{ w: "sine", v: 0.2, d: 0.6, r: 0.6 }, { w: "triangle", v: 11, t: 5, f: 1, s: 0.5, g: 1 }], [{ w: "sine", v: 0.3, d: 0.2, r: 0.2 }, { w: "sine", v: 6, t: 5, d: 0.02, g: 1 }], [{ w: "sine", v: 0.3, d: 0.2, r: 0.2 }, { w: "sine", v: 7, t: 11, d: 0.03, g: 1 }], [{ w: "sine", v: 0.2, d: 1, r: 1 }, { w: "sine", v: 11, t: 3.5, d: 1, r: 1, g: 1 }], [{ w: "triangle", v: 0.2, d: 0.5, r: 0.2 }, { w: "sine", v: 6, t: 2.5, d: 0.2, s: 0.1, r: 0.2, g: 1 }], /* 17-24 : Organ */ [{ w: "w9999", v: 0.22, s: 0.9 }, { w: "w9999", v: 0.22, t: 2, f: 2, s: 0.9 }], [{ w: "w9999", v: 0.2, s: 1 }, { w: "sine", v: 11, t: 6, f: 2, s: 0.1, g: 1, h: 0.006, r: 0.002, d: 0.002 }, { w: "w9999", v: 0.2, t: 2, f: 1, h: 0, s: 1 }], [{ w: "w9999", v: 0.2, d: 0.1, s: 0.9 }, { w: "w9999", v: 0.25, t: 4, f: 2, s: 0.5 }], [{ w: "w9999", v: 0.3, a: 0.04, s: 0.9 }, { w: "w9999", v: 0.2, t: 8, f: 2, a: 0.04, s: 0.9 }], [{ w: "sine", v: 0.2, a: 0.02, d: 0.05, s: 1 }, { w: "sine", v: 6, t: 3, f: 1, a: 0.02, d: 0.05, s: 1, g: 1 }], [{ w: "triangle", v: 0.2, a: 0.02, d: 0.05, s: 0.8 }, { w: "square", v: 7, t: 3, f: 1, d: 0.05, s: 1.5, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 0.2, s: 0.5 }, { w: "square", v: 1, d: 0.03, s: 2, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 0.1, s: 0.8 }, { w: "square", v: 1, a: 0.3, d: 0.1, s: 2, g: 1 }], /* 25-32 : Guitar */ [{ w: "sine", v: 0.3, d: 0.5, f: 1 }, { w: "triangle", v: 5, t: 3, f: -1, d: 1, s: 0.1, g: 1 }], [{ w: "sine", v: 0.4, d: 0.6, f: 1 }, { w: "triangle", v: 12, t: 3, d: 0.6, s: 0.1, g: 1, f: -1 }], [{ w: "triangle", v: 0.3, d: 1, f: 1 }, { w: "triangle", v: 6, f: -1, d: 0.4, s: 0.5, g: 1, t: 3 }], [{ w: "sine", v: 0.3, d: 1, f: -1 }, { w: "triangle", v: 11, f: 1, d: 0.4, s: 0.5, g: 1, t: 3 }], [{ w: "sine", v: 0.4, d: 0.1, r: 0.01 }, { w: "sine", v: 7, g: 1 }], [{ w: "triangle", v: 0.4, d: 1, f: 1 }, { w: "square", v: 4, f: -1, d: 1, s: 0.7, g: 1 }],//[{w:"triangle",v:0.35,d:1,f:1,},{w:"square",v:7,f:-1,d:0.3,s:0.5,g:1,}], [{ w: "triangle", v: 0.35, d: 1, f: 1 }, { w: "square", v: 7, f: -1, d: 0.3, s: 0.5, g: 1 }],//[{w:"triangle",v:0.4,d:1,f:1,},{w:"square",v:4,f:-1,d:1,s:0.7,g:1,}],//[{w:"triangle",v:0.4,d:1,},{w:"square",v:4,f:2,d:1,s:0.7,g:1,}], [{ w: "sine", v: 0.2, t: 1.5, a: 0.005, h: 0.2, d: 0.6 }, { w: "sine", v: 11, t: 5, f: 2, d: 1, s: 0.5, g: 1 }], /* 33-40 : Bass */ [{ w: "sine", d: 0.3 }, { w: "sine", v: 4, t: 3, d: 1, s: 1, g: 1 }], [{ w: "sine", d: 0.3 }, { w: "sine", v: 4, t: 3, d: 1, s: 1, g: 1 }], [{ w: "w9999", d: 0.3, v: 0.7, s: 0.5 }, { w: "sawtooth", v: 1.2, d: 0.02, s: 0.5, g: 1, h: 0, r: 0.02 }], [{ w: "sine", d: 0.3 }, { w: "sine", v: 4, t: 3, d: 1, s: 1, g: 1 }], [{ w: "triangle", v: 0.3, t: 2, d: 1 }, { w: "triangle", v: 15, t: 2.5, d: 0.04, s: 0.1, g: 1 }], [{ w: "triangle", v: 0.3, t: 2, d: 1 }, { w: "triangle", v: 15, t: 2.5, d: 0.04, s: 0.1, g: 1 }], [{ w: "triangle", d: 0.7 }, { w: "square", v: 0.4, t: 0.5, f: 1, d: 0.2, s: 10, g: 1 }], [{ w: "triangle", d: 0.7 }, { w: "square", v: 0.4, t: 0.5, f: 1, d: 0.2, s: 10, g: 1 }], /* 41-48 : Strings */ [{ w: "sawtooth", v: 0.4, a: 0.1, d: 11 }, { w: "sine", v: 5, d: 11, s: 0.2, g: 1 }], [{ w: "sawtooth", v: 0.4, a: 0.1, d: 11 }, { w: "sine", v: 5, d: 11, s: 0.2, g: 1 }], [{ w: "sawtooth", v: 0.4, a: 0.1, d: 11 }, { w: "sine", v: 5, t: 0.5, d: 11, s: 0.2, g: 1 }], [{ w: "sawtooth", v: 0.4, a: 0.1, d: 11 }, { w: "sine", v: 5, t: 0.5, d: 11, s: 0.2, g: 1 }], [{ w: "sine", v: 0.4, a: 0.1, d: 11 }, { w: "sine", v: 6, f: 2.5, d: 0.05, s: 1.1, g: 1 }], [{ w: "sine", v: 0.3, d: 0.1, r: 0.1 }, { w: "square", v: 4, t: 3, d: 1, s: 0.2, g: 1 }], [{ w: "sine", v: 0.3, d: 0.5, r: 0.5 }, { w: "sine", v: 7, t: 2, f: 2, d: 1, r: 1, g: 1 }], [{ w: "triangle", v: 0.6, h: 0.03, d: 0.3, r: 0.3, t: 0.5 }, { w: "n0", v: 8, t: 1.5, d: 0.08, r: 0.08, g: 1 }], /* 49-56 : Ensamble */ [{ w: "sawtooth", v: 0.3, a: 0.03, s: 0.5 }, { w: "sawtooth", v: 0.2, t: 2, f: 2, d: 1, s: 2 }], [{ w: "sawtooth", v: 0.3, f: -2, a: 0.03, s: 0.5 }, { w: "sawtooth", v: 0.2, t: 2, f: 2, d: 1, s: 2 }], [{ w: "sawtooth", v: 0.2, a: 0.02, s: 1 }, { w: "sawtooth", v: 0.2, t: 2, f: 2, a: 1, d: 1, s: 1 }], [{ w: "sawtooth", v: 0.2, a: 0.02, s: 1 }, { w: "sawtooth", v: 0.2, f: 2, a: 0.02, d: 1, s: 1 }], [{ w: "triangle", v: 0.3, a: 0.03, s: 1 }, { w: "sine", v: 3, t: 5, f: 1, d: 1, s: 1, g: 1 }], [{ w: "sine", v: 0.4, a: 0.03, s: 0.9 }, { w: "sine", v: 1, t: 2, f: 3, d: 0.03, s: 0.2, g: 1 }], [{ w: "triangle", v: 0.6, a: 0.05, s: 0.5 }, { w: "sine", v: 1, f: 0.8, d: 0.2, s: 0.2, g: 1 }], [{ w: "square", v: 0.15, a: 0.01, d: 0.2, r: 0.2, t: 0.5, h: 0.03 }, { w: "square", v: 4, f: 0.5, d: 0.2, r: 11, a: 0.01, g: 1, h: 0.02 }, { w: "square", v: 0.15, t: 4, f: 1, a: 0.02, d: 0.15, r: 0.15, h: 0.03 }, { g: 3, w: "square", v: 4, f: -0.5, a: 0.01, h: 0.02, d: 0.15, r: 11 }], /* 57-64 : Brass */ [{ w: "square", v: 0.2, a: 0.01, d: 1, s: 0.6, r: 0.04 }, { w: "sine", v: 1, d: 0.1, s: 4, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 1, s: 0.5, r: 0.08 }, { w: "sine", v: 1, d: 0.1, s: 4, g: 1 }], [{ w: "square", v: 0.2, a: 0.04, d: 1, s: 0.4, r: 0.08 }, { w: "sine", v: 1, d: 0.1, s: 4, g: 1 }], [{ w: "square", v: 0.15, a: 0.04, s: 1 }, { w: "sine", v: 2, d: 0.1, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 1, s: 0.5, r: 0.08 }, { w: "sine", v: 1, d: 0.1, s: 4, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 1, s: 0.6, r: 0.08 }, { w: "sine", v: 1, f: 0.2, d: 0.1, s: 4, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 0.5, s: 0.7, r: 0.08 }, { w: "sine", v: 1, d: 0.1, s: 4, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 1, s: 0.5, r: 0.08 }, { w: "sine", v: 1, d: 0.1, s: 4, g: 1 }], /* 65-72 : Reed */ [{ w: "square", v: 0.2, a: 0.02, d: 2, s: 0.6 }, { w: "sine", v: 2, d: 1, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 2, s: 0.6 }, { w: "sine", v: 2, d: 1, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 1, s: 0.6 }, { w: "sine", v: 2, d: 1, g: 1 }], [{ w: "square", v: 0.2, a: 0.02, d: 1, s: 0.6 }, { w: "sine", v: 2, d: 1, g: 1 }], [{ w: "sine", v: 0.4, a: 0.02, d: 0.7, s: 0.5 }, { w: "square", v: 5, t: 2, d: 0.2, s: 0.5, g: 1 }], [{ w: "sine", v: 0.3, a: 0.05, d: 0.2, s: 0.8 }, { w: "sawtooth", v: 6, f: 0.1, d: 0.1, s: 0.3, g: 1 }], [{ w: "sine", v: 0.3, a: 0.03, d: 0.2, s: 0.4 }, { w: "square", v: 7, f: 0.2, d: 1, s: 0.1, g: 1 }], [{ w: "square", v: 0.2, a: 0.05, d: 0.1, s: 0.8 }, { w: "square", v: 4, d: 0.1, s: 1.1, g: 1 }], /* 73-80 : Pipe */ [{ w: "sine", a: 0.02, d: 2 }, { w: "sine", v: 6, t: 2, d: 0.04, g: 1 }], [{ w: "sine", v: 0.7, a: 0.03, d: 0.4, s: 0.4 }, { w: "sine", v: 4, t: 2, f: 0.2, d: 0.4, g: 1 }], [{ w: "sine", v: 0.7, a: 0.02, d: 0.4, s: 0.6 }, { w: "sine", v: 3, t: 2, d: 0, s: 1, g: 1 }], [{ w: "sine", v: 0.4, a: 0.06, d: 0.3, s: 0.3 }, { w: "sine", v: 7, t: 2, d: 0.2, s: 0.2, g: 1 }], [{ w: "sine", a: 0.02, d: 0.3, s: 0.3 }, { w: "sawtooth", v: 3, t: 2, d: 0.3, g: 1 }], [{ w: "sine", v: 0.4, a: 0.02, d: 2, s: 0.1 }, { w: "sawtooth", v: 8, t: 2, f: 1, d: 0.5, g: 1 }], [{ w: "sine", v: 0.7, a: 0.03, d: 0.5, s: 0.3 }, { w: "sine", v: 0.003, t: 0, f: 4, d: 0.1, s: 0.002, g: 1 }], [{ w: "sine", v: 0.7, a: 0.02, d: 2 }, { w: "sine", v: 1, t: 2, f: 1, d: 0.02, g: 1 }], /* 81-88 : SynthLead */ [{ w: "square", v: 0.3, d: 1, s: 0.5 }, { w: "square", v: 1, f: 0.2, d: 1, s: 0.5, g: 1 }], [{ w: "sawtooth", v: 0.3, d: 2, s: 0.5 }, { w: "square", v: 2, f: 0.1, s: 0.5, g: 1 }], [{ w: "triangle", v: 0.5, a: 0.05, d: 2, s: 0.6 }, { w: "sine", v: 4, t: 2, g: 1 }], [{ w: "triangle", v: 0.3, a: 0.01, d: 2, s: 0.3 }, { w: "sine", v: 22, t: 2, f: 1, d: 0.03, s: 0.2, g: 1 }], [{ w: "sawtooth", v: 0.3, d: 1, s: 0.5 }, { w: "sine", v: 11, t: 11, a: 0.2, d: 0.05, s: 0.3, g: 1 }], [{ w: "sine", v: 0.3, a: 0.06, d: 1, s: 0.5 }, { w: "sine", v: 7, f: 1, d: 1, s: 0.2, g: 1 }], [{ w: "sawtooth", v: 0.3, a: 0.03, d: 0.7, s: 0.3, r: 0.2 }, { w: "sawtooth", v: 0.3, t: 0.75, d: 0.7, a: 0.1, s: 0.3, r: 0.2 }], [{ w: "triangle", v: 0.3, a: 0.01, d: 0.7, s: 0.5 }, { w: "square", v: 5, t: 0.5, d: 0.7, s: 0.5, g: 1 }], /* 89-96 : SynthPad */ [{ w: "triangle", v: 0.3, a: 0.02, d: 0.3, s: 0.3, r: 0.3 }, { w: "square", v: 3, t: 4, f: 1, a: 0.02, d: 0.1, s: 1, g: 1 }, { w: "triangle", v: 0.08, t: 0.5, a: 0.1, h: 0, d: 0.1, s: 0.5, r: 0.1, b: 0, c: 0 }], [{ w: "sine", v: 0.3, a: 0.05, d: 1, s: 0.7, r: 0.3 }, { w: "sine", v: 2, f: 1, d: 0.3, s: 1, g: 1 }], [{ w: "square", v: 0.3, a: 0.03, d: 0.5, s: 0.3, r: 0.1 }, { w: "square", v: 4, f: 1, a: 0.03, d: 0.1, g: 1 }], [{ w: "triangle", v: 0.3, a: 0.08, d: 1, s: 0.3, r: 0.1 }, { w: "square", v: 2, f: 1, d: 0.3, s: 0.3, g: 1, t: 4, a: 0.08 }], [{ w: "sine", v: 0.3, a: 0.05, d: 1, s: 0.3, r: 0.1 }, { w: "sine", v: 0.1, t: 2.001, f: 1, d: 1, s: 50, g: 1 }], [{ w: "triangle", v: 0.3, a: 0.03, d: 0.7, s: 0.3, r: 0.2 }, { w: "sine", v: 12, t: 7, f: 1, d: 0.5, s: 1.7, g: 1 }], [{ w: "sine", v: 0.3, a: 0.05, d: 1, s: 0.3, r: 0.1 }, { w: "sawtooth", v: 22, t: 6, d: 0.06, s: 0.3, g: 1 }], [{ w: "triangle", v: 0.3, a: 0.05, d: 11, r: 0.3 }, { w: "triangle", v: 1, d: 1, s: 8, g: 1 }], /* 97-104 : FX */ [{ w: "sawtooth", v: 0.3, d: 4, s: 0.8, r: 0.1 }, { w: "square", v: 1, t: 2, f: 8, a: 1, d: 1, s: 1, r: 0.1, g: 1 }], [{ w: "triangle", v: 0.3, d: 1, s: 0.5, t: 0.8, a: 0.2, p: 1.25, q: 0.2 }, { w: "sawtooth", v: 0.2, a: 0.2, d: 0.3, s: 1, t: 1.2, p: 1.25, q: 0.2 }], [{ w: "sine", v: 0.3, d: 1, s: 0.3 }, { w: "square", v: 22, t: 11, d: 0.5, s: 0.1, g: 1 }], [{ w: "sawtooth", v: 0.3, a: 0.04, d: 1, s: 0.8, r: 0.1 }, { w: "square", v: 1, t: 0.5, d: 1, s: 2, g: 1 }], [{ w: "triangle", v: 0.3, d: 1, s: 0.3 }, { w: "sine", v: 22, t: 6, d: 0.6, s: 0.05, g: 1 }], [{ w: "sine", v: 0.6, a: 0.1, d: 0.05, s: 0.4 }, { w: "sine", v: 5, t: 5, f: 1, d: 0.05, s: 0.3, g: 1 }], [{ w: "sine", a: 0.1, d: 0.05, s: 0.4, v: 0.8 }, { w: "sine", v: 5, t: 5, f: 1, d: 0.05, s: 0.3, g: 1 }], [{ w: "square", v: 0.3, a: 0.1, d: 0.1, s: 0.4 }, { w: "square", v: 1, f: 1, d: 0.3, s: 0.1, g: 1 }], /* 105-112 : Ethnic */ [{ w: "sawtooth", v: 0.3, d: 0.5, r: 0.5 }, { w: "sawtooth", v: 11, t: 5, d: 0.05, g: 1 }], [{ w: "square", v: 0.3, d: 0.2, r: 0.2 }, { w: "square", v: 7, t: 3, d: 0.05, g: 1 }], [{ w: "triangle", d: 0.2, r: 0.2 }, { w: "square", v: 9, t: 3, d: 0.1, r: 0.1, g: 1 }], [{ w: "triangle", d: 0.3, r: 0.3 }, { w: "square", v: 6, t: 3, d: 1, r: 1, g: 1 }], [{ w: "triangle", v: 0.4, d: 0.2, r: 0.2 }, { w: "square", v: 22, t: 12, d: 0.1, r: 0.1, g: 1 }], [{ w: "sine", v: 0.25, a: 0.02, d: 0.05, s: 0.8 }, { w: "square", v: 1, t: 2, d: 0.03, s: 11, g: 1 }], [{ w: "sine", v: 0.3, a: 0.05, d: 11 }, { w: "square", v: 7, t: 3, f: 1, s: 0.7, g: 1 }], [{ w: "square", v: 0.3, a: 0.05, d: 0.1, s: 0.8 }, { w: "square", v: 4, d: 0.1, s: 1.1, g: 1 }], /* 113-120 : Percussive */ [{ w: "sine", v: 0.4, d: 0.3, r: 0.3 }, { w: "sine", v: 7, t: 9, d: 0.1, r: 0.1, g: 1 }], [{ w: "sine", v: 0.7, d: 0.1, r: 0.1 }, { w: "sine", v: 22, t: 7, d: 0.05, g: 1 }], [{ w: "sine", v: 0.6, d: 0.15, r: 0.15 }, { w: "square", v: 11, t: 3.2, d: 0.1, r: 0.1, g: 1 }], [{ w: "sine", v: 0.8, d: 0.07, r: 0.07 }, { w: "square", v: 11, t: 7, r: 0.01, g: 1 }], [{ w: "triangle", v: 0.7, t: 0.5, d: 0.2, r: 0.2, p: 0.95 }, { w: "n0", v: 9, g: 1, d: 0.2, r: 0.2 }], [{ w: "sine", v: 0.7, d: 0.1, r: 0.1, p: 0.9 }, { w: "square", v: 14, t: 2, d: 0.005, r: 0.005, g: 1 }], [{ w: "square", d: 0.15, r: 0.15, p: 0.5 }, { w: "square", v: 4, t: 5, d: 0.001, r: 0.001, g: 1 }], [{ w: "n1", v: 0.3, a: 1, s: 1, d: 0.15, r: 0, t: 0.5 }], /* 121-128 : SE */ [{ w: "sine", t: 12.5, d: 0, r: 0, p: 0.5, v: 0.3, h: 0.2, q: 0.5 }, { g: 1, w: "sine", v: 1, t: 2, d: 0, r: 0, s: 1 }, { g: 1, w: "n0", v: 0.2, t: 2, a: 0.6, h: 0, d: 0.1, r: 0.1, b: 0, c: 0 }], [{ w: "n0", v: 0.2, a: 0.05, h: 0.02, d: 0.02, r: 0.02 }], [{ w: "n0", v: 0.4, a: 1, d: 1, t: 0.25 }], [{ w: "sine", v: 0.3, a: 0.1, d: 1, s: 0.5 }, { w: "sine", v: 4, t: 0, f: 1.5, d: 1, s: 1, r: 0.1, g: 1 }, { g: 1, w: "sine", v: 4, t: 0, f: 2, a: 0.6, h: 0, d: 0.1, s: 1, r: 0.1, b: 0, c: 0 }], [{ w: "square", v: 0.3, t: 0.25, d: 11, s: 1 }, { w: "square", v: 12, t: 0, f: 8, d: 1, s: 1, r: 11, g: 1 }], [{ w: "n0", v: 0.4, t: 0.5, a: 1, d: 11, s: 1, r: 0.5 }, { w: "square", v: 1, t: 0, f: 14, d: 1, s: 1, r: 11, g: 1 }], [{ w: "sine", t: 0, f: 1221, a: 0.2, d: 1, r: 0.25, s: 1 }, { g: 1, w: "n0", v: 3, t: 0.5, d: 1, s: 1, r: 1 }], [{ w: "sine", d: 0.4, r: 0.4, p: 0.1, t: 2.5, v: 1 }, { w: "n0", v: 12, t: 2, d: 1, r: 1, g: 1 }], ]; /** * 填充音色默认参数 * @param {Object} options 配置选项 * @param {number} [options.g=0] - output destination 0=final output / n=FM to specified osc即将FM效果应用在第几个osc上 * @param {string} [options.w="sine"] - wave type 波形类型 sine/square/sawtooth/triangle/w9999 * @param {number} [options.t=1] - tune factor according to note# * @param {number} [options.f=0] - delta频率 在基频上面加的 f' = f0*t+f * @param {number} [options.v=0.5] - volume 音量 0~1 * @param {number} [options.a=0] - attack time in seconds * @param {number} [options.h=0.01] - hold time in seconds * @param {number} [options.d=0.01] - decay time in seconds * @param {number} [options.s=0] - sustain level 声音在按键持续按下期间的音量 * @param {number} [options.r=0.05] - release time in seconds * @param {number} [options.p=1] - pitch bend 频率变化因数(乘) * @param {number} [options.q=1] - pitch bend speed factor in seconds 从freq到freq*p所需秒数 * @param {number} [options.k=0] - volume key tracking factor 在真实的乐器中,音量往往会随着音高的变化而变化 */ static initSoundFont({ g, w, t, f, v, a, h, d, s, r, p, q, k } = TinySynth.defaultWave) { // 默认的波形参数,用于填充每个基本波中缺失的默认参数 const defp = { g: g, w: w, t: t, f: f, v: v, a: a, h: h, d: d, s: s, r: r, p: p, q: q, k: k }; for (let i = 0; i < TinySynth.instrument.length; i++) { // 用的是复制,目的是防止修改TinySynth.wave。此函数可多次调用,改变全局音色 TinySynth.soundFont[TinySynth.instrument[i]] = Array.from(TinySynth.wave[i], (v) => Object.assign({}, defp, v)); } console.log("音色库初始化完毕"); } static initOneSoundFont(id, { g, w, t, f, v, a, h, d, s, r, p, q, k } = TinySynth.defaultWave) { const defp = { g: g, w: w, t: t, f: f, v: v, a: a, h: h, d: d, s: s, r: r, p: p, q: q, k: k }; TinySynth.soundFont[TinySynth.instrument[id]] = Array.from(TinySynth.wave[id], (v) => Object.assign({}, defp, v)); } static midi_instrument(id) { return TinySynth.soundFont[TinySynth.instrument[id]]; } constructor(actx = new AudioContext(), loadAll = false) { if (loadAll) { TinySynth.initSoundFont(); Object.defineProperty(this, "instrument", { set: function (id) { this._instrument = id; }, get: function () { return this._instrument; } }); console.log("模式: 初始化所有音色"); } else { Object.defineProperty(this, "instrument", { set: function (id) { const name = TinySynth.instrument[id]; if (!TinySynth.soundFont[name]) TinySynth.initOneSoundFont(id); this._instrument = id; }, get: function () { return this._instrument; } }); console.log("模式: 运行时加载音色"); // 初始时大约能小3M运行内存 } this.channel = []; // 维护一个数组,用于存放所有的channel。如果要改变顺序需要外部更改 this.notes = []; // 存放所有正在playing的note this.instrument = 0; this.audioContext = actx; const check = () => { this.checkStop(); window.requestAnimationFrame(check); } window.requestAnimationFrame(check); } get audioContext() { return this.actx; } set audioContext(actx) { this.actx = actx; this.out = this.actx.createGain(); // 总音量 this.comp = this.actx.createDynamicsCompressor(); this.out.connect(this.comp); this.comp.connect(actx.destination); for (const ch of this.channel) { ch.out = actx.createGain(); } // 不在默认波形中的波形集合 this.wave = { "w9999": actx.createPeriodicWave(new Float32Array(5), new Float32Array([0, 9, 9, 9, 9])) }; // 噪声 var blen = this.actx.sampleRate >> 1; this.noiseBuf = { n0: this.actx.createBuffer(1, blen, this.actx.sampleRate), n1: this.actx.createBuffer(1, blen, this.actx.sampleRate) }; let dn = this.noiseBuf.n0.getChannelData(0); let dr = this.noiseBuf.n1.getChannelData(0); for (let i = 0; i < blen; i++) { dn[i] = Math.random() * 2 - 1;// 范围[-1, 1],白噪声 } // 生成一个包含64*2个不同频率的正弦波的音频缓冲区 for (let jj = 0; jj < 64; ++jj) { const r1 = Math.random() * 10 + 1; const r2 = Math.random() * 10 + 1; for (let i = 0; i < blen; ++i) { // 频率是r1和r2 let dd = Math.sin((i / blen) * 2 * Math.PI * 440 * r1) * Math.sin((i / blen) * 2 * Math.PI * 440 * r2); dr[i] += dd / 8; } } } /** * 平方律,根据增益获取音量,正常范围0~127 */ get volume() { return Math.round(Math.sqrt(this.out.gain.value * 16129)); } /** * 平方律,根据音量设置增益 * @param {number} v 自然数音量 */ set volume(v) { this.out.gain.value = v * v / 16129; } /** * 创建一个节点 * @param {number} at 插入在native channel的位置,undefined表示最后,负数表示倒数 * @returns {Object} {out: GainNode} */ addChannel(at = this.channel.length, instrument = 0, gain = 1) { if (!this.channel) return null; // 防止此函数返回的obj调用 const out = this.actx.createGain(); const ch = {out: out}; out.gain.value = gain; out.connect(this.out); Object.setPrototypeOf(ch, this); ch.instrument = instrument; // 触发setter this.channel.splice(at, 0, ch); return ch; } /** * 播放声音 * @param {Object} options 音符播放参数 * @param {number} [options.id] - channel的id,如果不传或违规则用自身 决定了音色 * @param {number} [options.f=440] - 发生频率 * @param {number} [options.v=127] - 力度,最大127 会按平方律变为音量 * @param {number} [options.t=0] - 发声时间(秒) 如果小于零则在this.actx.currentTime基础上加其绝对值 * @param {number} [options.last=9999] - 持续时间(秒) * @returns {Object} note = {ch, end, gain, release} */ play({ id, f = 440, v = 127, t = 0, last = 9999 } = {}) { if (last <= 0) return; const ch = id === void 0 ? this : (this.channel && this.channel[id] ? this.channel[id] : this); const instrument = TinySynth.soundFont[TinySynth.instrument[ch.instrument]]; const osc = new Array(instrument.length); const gain = new Array(instrument.length); const freq = new Array(instrument.length); const release = new Array(instrument.length); if (t < 0) t = this.actx.currentTime - t; else t = t < this.actx.currentTime ? this.actx.currentTime : t; // 共用的变量 let out, A_rate, volume, o; for (let i = 0; i < instrument.length; i++) { const p = instrument[i]; if (p.g == 0) { // 0表明是发声的 out = ch.out; A_rate = v * v / 16129; // 平方律设置归一化振幅 freq[i] = f * p.t + p.f; } else if (p.g > 0) { // FM调制 if (osc[p.g - 1].frequency) { out = osc[p.g - 1].frequency; A_rate = freq[p.g - 1]; } else { // 如果是噪声,则osc是一个bufferSource,没有frequency属性 out = osc[p.g - 1].playbackRate; A_rate = freq[p.g - 1] / 440; } freq[i] = freq[p.g - 1] * p.t + p.f; } else { // AM调制 out = gain[-p.g - 1].gain; A_rate = 1; freq[i] = freq[p.g - 1] * p.t + p.f; } // 振荡器 波形 if (p.w[0] == 'n') { // 噪声 o = this.actx.createBufferSource(); o.buffer = this.noiseBuf[p.w]; o.loop = true; o.playbackRate.value = freq[i] / 440; if (p.p != 1) o.playbackRate.setTargetAtTime(freq[i] * p.p / 440, t, p.q); } else { o = this.actx.createOscillator(); o.frequency.value = freq[i]; if (p.p != 1) o.frequency.setTargetAtTime(freq[i] * p.p, t, p.q) if (p.w[0] == 'w') o.setPeriodicWave(this.wave[p.w]); else o.type = p.w; } osc[i] = o; volume = A_rate * p.v; if (p.k) volume *= Math.pow(f / 261.6, p.k); // 261.6是中央C的频率 k一般是负数,表示音越高,音量越小 release[i] = p.r; const g = this.actx.createGain(); if (p.a) { // 包络的A g.gain.value = 0; g.gain.setValueAtTime(0, t); g.gain.linearRampToValueAtTime(volume, t + p.a); } else g.gain.setValueAtTime(volume, t); // 包络的H、D和S g.gain.setTargetAtTime(p.s * volume, t + p.a + p.h, p.d); gain[i] = g; o.connect(g); g.connect(out); o.start(t); } const note = { // 用于停止 ch: ch, end: t + last, // end表示结束时间,恒大于零,如果小于零表示已经停止(手动停止),不需要再次停止 gain: gain, osc: osc, release: release }; this.notes.push(note); return note; } stop(nt, t = 0) { if (t < 0) t = this.actx.currentTime - t; else t = t < this.actx.currentTime ? this.actx.currentTime : t; let promises = nt.osc.map((osc, i) => { return new Promise(resolve => { osc.onended = resolve; nt.gain[i].gain.cancelScheduledValues(t); // 包络的R nt.gain[i].gain.setTargetAtTime(0, t, nt.release[i]); // setTargetAtTime 只会逼近不会到0 多等一会 osc.stop(t + nt.release[i] * 2); nt.gain[i].gain.cancelScheduledValues(t + nt.release[i] * 2); }); }); Promise.all(promises).then(() => { nt.end = -1; // 标记为已经停止 // 断开连接以GC for (let i = 0; i < nt.osc.length; i++) { nt.osc[i].disconnect(); nt.gain[i].disconnect(); } }); // 在所有osc都结束后的操作 } checkStop() { // 自动回收 一直开启 const t = this.actx.currentTime; for (let i = this.notes.length - 1; i >= 0; i--) { const nt = this.notes[i]; if (nt.end < t) { if (nt.end > 0) this.stop(nt); // 手动停止则end<0但仍然留在notes中,不需要再次停止,直接删除 this.notes.splice(i, 1); } } } stopAll() { for (let i = this.notes.length - 1; i >= 0; i--) { this.stop(this.notes[i]); } this.notes.length = 0; } } ================================================ FILE: plugins/chordEst.js ================================================ window.plugins ??= []; window.plugins.push(function (app) { // 和弦识别 var chords = null; const chordEst = () => { let hasHarmonic = !!app.Spectrogram.harmonic; console.time("和弦分析"); const chordest = new ChordEst(hasHarmonic ? 0.3 : 0.1, 0.1, Math.pow(0.82, app.dt / 1000)); // 1s后切换和弦的概率是0.82 const buffer = new Float32Array(12); let buffer2 = hasHarmonic ? new Float32Array(84) : null; for (let t = 0; t < app.Spectrogram.spectrogram.length; t++) { let spec = app.Spectrogram.spectrogram[t]; if (hasHarmonic) { for (let i = 0; i < spec.length; i++) buffer2[i] = Math.max(0, spec[i] - app.Spectrogram.harmonic[t][i]); spec = buffer2; } chordest.step(chordest.chroma([spec], buffer)); } const c = chordest.decode(); const results = []; let lastChord = null; for (let i = 0; i < c.length; i++) { if (c[i] !== lastChord) { results.push({ at: i, chord: c[i] }); lastChord = c[i]; } } console.timeEnd("和弦分析"); ChordEst.octaveW = null; chords = results; app.makeActDirty(); }; const render = (canvas) => { if (!chords) return; const ctx = canvas.ctx; let x = 0; { let left = 0, right = chords.length - 1; while (left <= right) { const mid = Math.floor((left + right) / 2); if (chords[mid].at < app.idXstart) { x = mid; left = mid + 1; } else right = mid - 1; } } const fill1Start = [], fill2Start = []; for (; x < chords.length && chords[x].at < app.idXend; x++) { if (chords[x].chord === 'N') continue; let f = x & 1 ? fill1Start : fill2Start; let xstart = Math.max(0, chords[x].at * app._width - app.scrollX); let xend = Math.min(canvas.width, (chords[x + 1]?.at ?? app.xnum) * app._width - app.scrollX); f.push({ xstart, xend, chord: chords[x].chord }); } let ystart = canvas.height - app._height; ctx.fillStyle = '#8400ff55'; for (const { xstart, xend, chord } of fill1Start) ctx.fillRect(xstart, ystart, xend - xstart, app._height); ctx.fillStyle = '#dd00ff55'; for (const { xstart, xend, chord } of fill2Start) ctx.fillRect(xstart, ystart, xend - xstart, app._height); ctx.fillStyle = 'black'; ystart = canvas.height - 1; for (const { xstart, xend, chord } of fill1Start) ctx.fillText(chord, xstart, ystart); for (const { xstart, xend, chord } of fill2Start) ctx.fillText(chord, xstart, ystart); }; // 注册 const tgtLabel = "分析"; for (const t of window.menu.tabs) { if (t.dataset.name != tgtLabel) continue; const ul = t.item; const li = document.createElement('li'); li.classList.add('pointer'); li.innerText = "和弦分析"; // 插入到“去除谐波”之后 let inserted = false; for (let i = 0; i < ul.children.length; i++) { if (ul.children[i].innerText && ul.children[i].innerText.includes('去除谐波')) { if (ul.children[i].nextSibling) ul.insertBefore(li, ul.children[i].nextSibling); else ul.appendChild(li); inserted = true; break; } } !inserted && ul.appendChild(li); li.onclick = function (e) { if (!app.Spectrogram._spectrogram || app.midiMode) { alert("请先导入音频!"); return; } chordEst(); e.stopPropagation(); e.target.blur(); }; break; } window.app.layers.action.register(render); console.log('plugin "chordEst" loaded'); }); if (window.app) { window.plugins.forEach(plugin => plugin(window.app)); window.plugins = null; } /** * @abstract 和弦识别类 * 参考NNLS-Chroma这个Vamp插件,并做了简化(删去了NNLS&白化)与增强(乐理规则的转移概率调整) * 单帧和弦识别使用Chorma向量的余弦匹配(声学模型); 多帧使用HMM(语言模型) */ class ChordEst { /** * 和弦字典 包含和弦名称、和弦模板向量 * @type {Array<{name: string, vec: Float32Array}>} with .raw as the raw buffer of all chord vecs concatenated together */ chordDict; // [{name, chroma}] logPriorP; // 先验概率 logTransP; // 转移概率 states = []; // {scores: Float32Array, ptrs: Int16Array} /** * 构建和弦模板 转移概率 * @param {number} harmonicDecay 谐波拟合的衰减 * @param {number} P_N 无和弦的相对概率 * @param {number} P_keep 保持当前和弦的概率 */ constructor(harmonicDecay = 0.3, P_N = 0.1, P_keep = 0.98) { class ChordPattern { static MIDI_NOTES = [0, 2, 4, 5, 7, 9, 11]; static getMidi(je) { let base = 0, acci = 0; for (let char of je) { if (char === 'b') acci -= 1; else if (char === '#') acci += 1; else base = ChordPattern.MIDI_NOTES[(parseInt(char) - 1) % 7] || 0; } return (base + acci + 12) % 12; } constructor(pattern, prob = 1.) { // this.pattern: [0, 4, 7] this.pattern = pattern.map(ChordPattern.getMidi); this.prob = prob; } } // 构建和弦字典 const patternDict = { "": new ChordPattern(['1', '3', '5'], 1), // 大三和弦 - 基础 "m": new ChordPattern(['1', 'b3', '5'], 0.9), // 小三和弦 - 基础 "dim": new ChordPattern(['1', 'b3', 'b5'], 0.1), // 减三 - 过渡性 "aug": new ChordPattern(['1', '3', '#5'], 0.1), // 增三 - 罕见色彩 "sus4": new ChordPattern(['1', '4', '5'], 0.04), // 挂四 - 过渡性和弦 "sus2": new ChordPattern(['1', '2', '5'], 0.04), // 挂二 - 现代流行 "7": new ChordPattern(['1', '3', '5', 'b7'], 0.01), // 属七 - 功能性强 "m7": new ChordPattern(['1', 'b3', '5', 'b7'], 0.01), // 小七 - 爵士/R&B常见 "maj7": new ChordPattern(['1', '3', '5', '7'], 0.005), // 大七 - 色彩性 "dim7": new ChordPattern(['1', 'b3', 'b5', 'bb7'], 0.004), // 减七 - 古典/爵士过渡 "m7b5": new ChordPattern(['1', 'b3', 'b5', 'b7'], 0.003), // 半减七 - 爵士ii级 "add9": new ChordPattern(['1', '3', '5', '9'], 0.003), // 加九 - 色彩性 "mM7": new ChordPattern(['1', 'b3', '5', '7'], 0.001), // 小大七 - 极罕见 "maj9": new ChordPattern(['1', '3', '5', '7', '9'], 0.0002), // 大九 - 复杂 }; { // 归一化概率 let sum = 0; for (const ptn in patternDict) sum += patternDict[ptn].prob; sum = (1 - P_N) / (sum * 12); for (const ptn in patternDict) patternDict[ptn].prob *= sum; } const ptnKey = Object.keys(patternDict); const numPtn = ptnKey.length; const validChordNum = numPtn * 12; const chordNum = validChordNum + 1; // 包含无和弦 [this.chordDict, this.logPriorP] = (() => { function initHarmonicTemplate(s = 0.6, harmonics = 9) { const a = new Float32Array(12); for (let h = 1, w = 1; h <= harmonics; h++, w *= s) { let bin = Math.log2(h) * 12; let l = Math.floor(bin); let r = Math.ceil(bin); let frac = bin - l; a[l % 12] += w * (1 - frac); a[r % 12] += w * frac; } return a; } const tmpl = initHarmonicTemplate(harmonicDecay); const Chord = (name, ptn, buf, amp = 1) => { // 施加谐波模板 let sum = 0; for (let i = 0; i < 12; i++) { for (let j = 0; j < 12; j++) buf[i] += ptn[j] * tmpl[(i - j + 12) % 12]; sum += buf[i] * buf[i]; } // 归一化 sum = amp / Math.sqrt(sum); for (let i = 0; i < 12; i++) buf[i] *= sum; return { name, vec: buf }; } const Roots = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']; const vec = new Float32Array(12); const result = Array(chordNum); const buffer = result.raw = new Float32Array(chordNum * 12); const priorP = new Float32Array(chordNum); const normAmp = { 4: 0.98, 5: 0.95, 6: 0.93 }; let i = 0; // 存储结构: 相同模式的放一起 for (const suffix of ptnKey) { const pattern = patternDict[suffix]; priorP.fill(Math.log(pattern.prob), i, i + 12); const amp = normAmp[pattern.pattern.length]; for (let root = 0; root < 12; root++) { vec.fill(0); for (const interval of pattern.pattern) vec[(root + interval) % 12] = 1; result[i] = Chord(Roots[root] + suffix, vec, buffer.subarray(i * 12, (i + 1) * 12), amp); i++; } } // 无和弦 result[i] = Chord("N", vec.fill(1), buffer.subarray(i * 12, (i + 1) * 12), 0.8); priorP[i] = Math.log(P_N); return [result, priorP]; })(); // 转移概率 this.logTransP = ((P_STAY = P_keep) => { const getIdFromName = (nameList) => nameList.map(name => ptnKey.indexOf(name)); const STABLE = getIdFromName(["", "m", "m7", "maj7", "add9", "maj9"]); const TENSION = getIdFromName(["7", "dim", "m7b5", "dim7", "aug", "mM7"]); const SUSPENSE = getIdFromName(["sus4", "sus2"]); const pMat = Array(chordNum); const lt = pMat.raw = new Float32Array(chordNum * chordNum); for (let i = 0; i < chordNum; i++) { const row = pMat[i] = lt.subarray(i * chordNum, (i + 1) * chordNum); if (i === validChordNum) { // 从无和弦切换到别的状态 row.set(this.logPriorP); this.logPriorP = row; // 复用 continue; } let sumScore = 0; let r1 = i % 12, p1 = i / 12 | 0;// 根音 模式 // 遍历每一个转移的可能 for (let j = 0; j < chordNum; j++) { if (i === j) continue; // 自转移单独处理 let r2, p2, score; if (j < validChordNum) { r2 = j % 12; p2 = j / 12 | 0; score = patternDict[ptnKey[p2]].prob; } else { r2 = p2 = -1; score = P_N; // 进入N状态的概率 } if (r1 !== -1 && r2 !== -1) { const interval = (r2 - r1 + 12) % 12; // --- 乐理规则增强 --- // 强功能进行:上行纯四度 (+5) if (interval === 5) { score *= 5.0; if (TENSION.includes(p1) && STABLE.includes(p2)) score *= 2.0; // V7 -> I 逻辑 } // 下行三度进行:(-3 或 -4) else if (interval === 8 || interval === 9) { score *= 3.0; // I -> vi 或 I -> iii } // 上行二度:(+2) else if (interval === 2) { score *= 2.5; // IV -> V 逻辑 } // 挂留解决:同根音 else if (interval === 0 && SUSPENSE.includes(p1) && STABLE.includes(p2)) { score *= 10.0; // sus -> Major/Minor 极高概率 } // 减/增和弦倾向解决 else if (interval === 1 && ptnKey[p1] === "dim7") { // dim7 -> 半音上行 score *= 4.0; } // 惩罚:避免无意义的频繁模式切换(根音不变时) else if (interval === 0 && p1 !== p2) { const n1 = patternDict[ptnKey[p1]].pattern.length; const n2 = patternDict[ptnKey[p2]].pattern.length; if (n2 < n1) score *= 0.9; // 变向更简单的和弦,惩罚极小 else score *= 0.1; // 变向更复杂的和弦,保持高惩罚 } } row[j] = score; sumScore += score; } // 归一化并取 Log const scale = (1 - P_STAY) / sumScore; for (let j = 0; j < chordNum; j++) { row[j] = Math.log(i === j ? P_STAY : row[j] * scale); } } return pMat; })(); ChordEst.initOctaveW(); } /** * Viterbi 单步处理 * @param {Float32Array} obs 长度为12的观测Chroma向量 (应先归一化) */ step(obs) { const n = this.chordDict.length; const likelihood = new Float32Array(n); const ptrs = new Uint16Array(n); // 发射概率 let p_sum = 0; for (let i = 0; i < n; i++) { let dot = 0; const v = this.chordDict[i].vec; for (let k = 0; k < 12; k++) dot += obs[k] * v[k]; if (dot < 0) dot = 0; let p = Math.pow(dot, 5); // 使用高次幂拉开差距 p_sum += p; likelihood[i] = p == 0 ? -Infinity : Math.log(p); } if (p_sum < 1e-4) { // 如果所有和弦的似然都很小,则认为是无和弦状态 likelihood.fill(-Infinity); likelihood[this.chordDict.length - 1] = 0; } else { // 否则正常归一化似然 p_sum = Math.log(p_sum); for (let i = 0; i < n; i++) { if (likelihood[i] > -Infinity) likelihood[i] -= p_sum; } } if (this.states.length === 0) { // 第一帧使用先验 for (let i = 0; i < n; i++) likelihood[i] += this.logPriorP[i]; } else { const prevScores = this.states[this.states.length - 1].scores; for (let j = 0; j < n; j++) { let maxS = -Infinity; let maxIdx = 0; // 遍历上一帧所有状态 i 转移到当前状态 j for (let i = 0; i < n; i++) { const s = prevScores[i] + this.logTransP[i][j]; if (s > maxS) maxS = s, maxIdx = i; } likelihood[j] += maxS; ptrs[j] = maxIdx; } } this.states.push({ scores: likelihood, ptrs }); } /** * 回溯得到最终和弦序列 * @returns {Array} 和弦名称序列 */ decode() { if (this.states.length === 0) return []; const n = this.chordDict.length; const T = this.states.length; const result = new Array(T); // 找到最后一帧得分最高的 let lastScores = this.states[T - 1].scores; let curr = 0, maxS = -Infinity; for (let i = 0; i < n; i++) { if (lastScores[i] > maxS) maxS = lastScores[i], curr = i; } // 回溯 for (let t = T - 1; t >= 0; t--) { result[t] = this.chordDict[curr].name; curr = this.states[t].ptrs[curr]; } // 清理状态以便下次识别 this.states = []; return result; } // 频谱到chroma的权重 static octaveW; static initOctaveW() { if (ChordEst.octaveW) return; const W = this.octaveW = new Float32Array(84); const T = 84; // const T = 84 * 6 / 5; let w = 2 * Math.PI / T; // let b = -Math.PI * 2 / 3; let b = -Math.PI; for (let i = 0; i < 84; i++) { // 往低频靠近 W[i] = (Math.cos(w * i + b) + 1) / Math.pow(2, i / 24); } let sum = 0; for (let c of W) sum += c; sum = 12 / sum; for (let i = 0; i < W.length; i++) W[i] *= sum; } /** * 从频谱中得到Chroma能量向量 * @param {Array} spect84 多个长84的 幅度 * @param {Float32Array} buffer 长12 * @return {Float32Array} 长度为12的Chroma向量 */ chroma(spect84, buffer = null) { if (buffer == null) buffer = new Float32Array(12); else buffer.fill(0); const W = ChordEst.octaveW; for (const f of spect84) { for (let k = 0; k < 84; k++) { buffer[k % 12] += f[k] * f[k] * W[k]; } } for (let i = 0; i < 12; i++) buffer[i] = buffer[i] / spect84.length; return buffer; } } ================================================ FILE: plugins/pitchName.js ================================================ window.plugins ??= []; window.plugins.push(function (app) { // 显示音高 var pitchName = null; const showPitchName = (ifshow) => { if (ifshow) { app.layerContainer.addEventListener('mousemove', app._trackMouseX); pitchName = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']; } else { app.layerContainer.removeEventListener('mousemove', app._trackMouseX); pitchName = null; } }; const render = ({ctx}) => { let h = app.Keyboard.highlight; if (pitchName && h >= 0) { ctx.fillStyle = 'black'; ctx.fillText( `${pitchName[h % 12]}${Math.floor(h / 12) - 1}`, app._mouseX - app._height * 1.5, app.layers.height - (h - 24) * app._height + app.scrollY - (app._height >> 3) ); } }; // 注册UI和绘制 const tgtLabel = "设置"; for (const t of window.menu.tabs) { if (t.dataset.name != tgtLabel) continue; const ul = t.item; const li = document.createElement('li'); li.innerHTML = ``; ul.appendChild(li); li.querySelector('input').onchange = function (e) { showPitchName(this.checked); e.stopPropagation(); e.target.blur(); }; break; } window.app.layers.action.register(render); console.log('plugin "pitchName" loaded'); }); if (window.app) { window.plugins.forEach(plugin => plugin(window.app)); window.plugins = null; } ================================================ FILE: style/askUI.css ================================================ /* 依赖:style.css中的.card和.hvCenter*/ .request-cover { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: #6c6c6c78; z-index: 99; opacity: 1; transition: opacity 0.2s ease-in-out; } .request-cover .card { position: fixed; width: auto; height: auto; background-color: rgb(37, 38, 45);; padding: 1em; overflow: hidden; color: rgb(235, 235, 235); } .request-cover .title { font-size: 1.2em; font-weight: bold; color: white; } /* 无特殊情况用label,特殊情况用span */ .request-cover span.title { overflow: hidden; display: inline-block; max-width: 11em; min-width: 8em; white-space: nowrap; text-overflow: ellipsis; vertical-align: middle; } .request-cover span.title:hover { overflow: visible; white-space: normal; z-index: 100; max-width: none; } .card.hvCenter .layout { display: flex; justify-content: space-between; align-items: center; padding: 5px 8px 5px 8px; margin: 0.2em; background: inherit; color: inherit; } .card.hvCenter .layout-first { margin-top: calc(0.2em + 5px); } .request-cover .card.hvCenter button { margin: 0 0.25em; border: none; border-radius: 0.2em; padding: 0.5em 1em; cursor: pointer; outline: none; color: inherit; } .request-cover .ui-confirm { flex: 1; background: rgb(60, 87, 221); color: white; } .request-cover .ui-cancel { flex: 1; background-color: #2e3039; color: white; } .card.hvCenter input, .card.hvCenter select { flex: 1; background: inherit; border: 1px solid rgb(54, 58, 69); border-radius: 0.25em; color: inherit; margin: 0 0.8em; padding-left: 0.6em; padding: 0.35em 0em 0.3em 0.5em; } /* 进度条 */ .porgress-track { display: block; width: 16em; height: 1em; border-radius: 2em; background-color: #1e1f24; overflow: hidden; } .porgress-value { width: 0; height: inherit; background-color: #761fc8; } ================================================ FILE: style/channelDiv.css ================================================ /* 可拖拽的列表 */ .drag_list { --bg-color: var(--theme-middle); --li-hover: var(--theme-light); } .drag_list .takeplace { height: 8em; } /* 列表本体 */ ul.drag_list { height: 100%; list-style: none; background-color: var(--bg-color); padding: 0; margin: 0; overflow: auto; } ul.drag_list::-webkit-scrollbar { width: 12px; } ul.drag_list::-webkit-scrollbar-thumb { background-color: rgb(50, 53, 62); border: 3px solid rgb(37, 38, 45); border-radius: 6px; } ul.drag_list::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background-color: rgb(37, 38, 45); } ul.drag_list li.drag_list-item { width: 100%; transition: 0.3s; } ul.drag_list li.moving { position: relative; } ul.drag_list li.moving::before { content: ""; position: absolute; z-index: 2; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--bg-color); border: 0.125em dashed #ccc; border-radius: 0.3em; /* 和列表项保持一致 */ margin: 0 0.6em; } /* 列表项 */ .channel-Container { position: relative; background-color: transparent; border-radius: 0.32em; margin: 0.6em; border-left: 0.5em solid; border-color: var(--tab-color); padding: 0.4em; } .channel-Container:hover { background-color: var(--li-hover); } .channel-Container.selected { background-color: var(--li-hover); } /* 序号 */ .channel-Container::after { content: attr(data-tab-index); position: absolute; bottom: 0.32em; right: 0.32em; background-color: transparent; font-size: 0.5em; color: #a5abba; z-index: 1; } .channel-Container .upper { display: flex; flex-direction: row; align-items: center; } /* 音轨名 */ .channel-Name { overflow: hidden; /* 隐藏超出容器的内容 */ white-space: nowrap; /* 不换行 */ text-overflow: ellipsis;/* 超出部分用省略号表示 */ flex: 1; font-size: 1em; font-weight: bold; color: white; cursor: pointer; } /* 快捷按钮 */ .channel-Tab { display: flex; /* 消除子block之间的间隙 */ flex: 0 1 auto; } .upper .tab { border-radius: 50%; width: 1.8em; height: 1.8em; text-align: center; display: inline; background-color: transparent; border: none; color: var(--tab-color); } .channel-Container .tab:hover { background-color: #363944; } /* 乐器选择 */ .channel-Instrument { display: inline-block; font-size: 0.9em; color: white; overflow: hidden; } ================================================ FILE: style/contextMenu.css ================================================ .contextMenuCard { min-width: 100px; padding: 3px 5px; margin: 2px; background-color: #ffffff; border: 1px solid #dadce0; border-radius: 4px; box-shadow: 1px 1px 2px #878787; position: fixed; user-select: none; z-index: 100; } .contextMenuCard:focus { outline: none; } .contextMenuCard li { list-style: none; margin: 2px 0px; cursor: pointer; min-height: 26px; padding: 0px 8px; color: black; } .contextMenuCard li:hover { background-color: #f5f5f5; } ================================================ FILE: style/icon/iconfont.css ================================================ @font-face { font-family: "iconfont"; /* Project id 4420000 */ src: url('iconfont.woff2?t=1774196575181') format('woff2'), url('iconfont.woff?t=1774196575181') format('woff'), url('iconfont.ttf?t=1774196575181') format('truetype'); } .iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-xifu:before { content: "\e614"; } .icon-xifu1:before { content: "\e730"; } .icon-lock:before { content: "\e76f"; } .icon-unlock:before { content: "\e879"; } .icon-file:before { content: "\e63d"; } .icon-analysis:before { content: "\e600"; } .icon-pageTurns:before { content: "\e6d5"; } .icon-repeat:before { content: "\e628"; } .icon-mixer:before { content: "\e660"; } .icon-setting:before { content: "\e673"; } .icon-list:before { content: "\e603"; } .icon-pen-l:before { content: "\e64d"; } .icon-select:before { content: "\ea60"; } .icon-range:before { content: "\e63c"; } .icon-eyeslash-fill:before { content: "\e7aa"; } .icon-eye-fill:before { content: "\e7ab"; } .icon-close_volume:before { content: "\e6a0"; } .icon-volume:before { content: "\e6a3"; } ================================================ FILE: style/myRange.css ================================================ .myrange { margin: 0; padding: 0; box-sizing: border-box; display: inline-flex; align-items: center; color: inherit; } .myrange span { color: inherit; cursor: pointer; user-select: none; } /* === 各浏览器中统一滑动条 === */ .myrange input[type="range"] { -webkit-appearance: none; appearance: none; margin: 0 5px 0 0; padding: 0; outline: none; border: none; background: rgb(60, 87, 221); height: 6px; border-radius: 10px; transform: translateY(1px); } .myrange input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; background: rgb(60, 87, 221); width: 16px; height: 16px; border: none; border-radius: 50%; box-shadow: 0px 3px 6px 0px rgba(255, 255, 255, 0.15); } .myrange input[type="range"]::-moz-range-thumb { background: rgb(60, 87, 221); width: 16px; height: 16px; border: none; border-radius: 50%; box-shadow: 0px 3px 6px 0px rgba(255, 255, 255, 0.15); } /* 解决Firefox中虚线显示在周围的问题 */ .myrange input[type="range"]::-moz-focus-outer { border: 0; } .myrange input[type="range"]:active::-webkit-slider-thumb { box-shadow: 0px 5px 10px -2px rgba(0, 0, 0, 0.3); } /* === 滑动条end === */ /* 隐藏数值的滑动条 */ .hidelabelrange { position: relative; } .hidelabelrange span.thelabel { position: absolute; z-index: 1; padding: 3px 6px; background-color: #373943; box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.15); color: white; font-size: 12px; border-radius: 4px; top: 7px; transform: translateX(-50%) translateY(50%); } .hidelabelrange span.thelabel::after { content: ''; position: absolute; z-index: -1; width: 10px; height: 10px; background-color: #373943; top: -3px; left: 50%; transform: translateX(-50%) rotate(45deg); } .fullRange { flex: 1; width: 100%; input { width: 100%; } } ================================================ FILE: style/siderMenu.css ================================================ .siderTabs { --tab-width: 48px; width: var(--tab-width); height: 100%; background-color: var(--theme-dark); position: relative; z-index: 1; } .siderTab { color: var(--theme-text); width: var(--tab-width); height: var(--tab-width); position: relative; cursor: pointer; } /* 图标位置与大小 */ .siderTab::before { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: calc(var(--tab-width) * 0.5); } .siderTab.selected { color: white; background-color: var(--theme-middle); border-left: white solid 2px; } .siderTab.selected { color: white; background-color: var(--theme-middle); border-left: white solid 2px; } .siderTab:hover { color: white; } .siderTab::after { content: attr(data-name); font-size: calc(var(--tab-width) * 0.25); color: var(--theme-text); background-color: var(--theme-light); white-space: nowrap; padding: 4px 8px; position: absolute; z-index: 3; top: calc(var(--tab-width) * 0.5); left: calc(var(--tab-width) + 2px); transform: translateY(-50%); border-radius: 4px; border: var(--theme-dark) solid 2px; display: none; } .siderTab:hover::after { display: block; } /* 展示内容 */ .siderContent { background-color: transparent; width: 206px; height: 100%; overflow: hidden; } .siderBar { opacity: 0; transition: 0.3s; width: 4px; margin-left: -2px; margin-right: -2px; height: 100%; background-color: royalblue; cursor: ew-resize; user-select: none; position: relative; z-index: 2; } .siderBar:hover { opacity: 1; } .siderContent .siderItem { background-color: var(--theme-middle); width: 100%; height: 100%; } /* siderItem不提供内边距,用paddingbox类实现 */ .paddingbox { box-sizing: border-box; padding: 0.4em 0.8em; overflow: auto; } .siderItem h3 { margin: 0; padding: 0; } ================================================ FILE: style/style.css ================================================ :root { --theme-light: #2e3039; --theme-middle: #25262d; --theme-dark: #1e1f24; --theme-text: #8e95a6; } * { margin: 0; padding: 0; user-select: none; } html, body { height: 100%; font-size: 16px; color: var(--theme-text); background-color: var(--theme-dark); overflow: hidden; } @media (max-width: 1084px) { .logo3 { display: none !important; } } @media (max-width: 1036px) { .logo2 { display: none !important; } } @media (max-width: 983px) { .logo1 { display: none !important; } .tools { justify-content: space-around !important; } } @media (max-width: 792px) { .rangeBox:has(#speedControl) { display: none; } } canvas { display: block; margin: 0; border: none; } ul { list-style: none; } button { background-color: var(--theme-dark); border: none; cursor: pointer; color: var(--theme-text); font-size: 16px; } /* flex */ .f { display: flex; } .fc { display: flex; flex-direction: column; } .fr { display: flex; flex-direction: row; } /* width full */ .wf { width: 100%; } .dragIn::before { content: "Drag and drop your file here"; display: flex; justify-content: center; align-items: center; position: absolute; z-index: 98; width: 100%; height: 100%; background-color: #1e1f24bb; border: var(--theme-text) 3px dashed; box-sizing: border-box; font-size: 2em; } .card { box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); border-radius: 10px; } .hvCenter { top: 50%; left: 50%; transform: translate(-50%, -50%); } #scrollbar-track { margin: 0; padding: 0; border: none; position: relative; height: 1em; background-color: rgb(37, 38, 45); } #scrollbar-thumb { margin: 0; padding: 0; border: none; position: absolute; height: 100%; width: 50px; background-color: rgb(69, 72, 81); cursor: ew-resize; } #play-btn { background-color: var(--theme-middle); color: var(--theme-text); border: none; border-right: var(--theme-dark) solid 3px; position: relative; font-size: 0.8em; cursor: pointer; } .flexfull { flex: 1; /* 下面这行必须加 不然被画布撑开了就缩不回去了 */ overflow: hidden; } #main-layers { position: relative; canvas { position: absolute; top: 0; left: 0; } } .tools { background-color: transparent; display: flex; justify-content: space-between; align-items: center; padding: 2px; position: relative; z-index: 1; } .top-logo { height: 36px; padding: 0 8px; cursor: pointer; } /* 可以套在外面的盒子,盒子中可以放属性名 */ .rangeBox { height: 1em; line-height: 1em; display: flex; flex-direction: row; align-items: center; justify-content: left; margin: 0.25em; } /* 工具选择 */ .switch-bar { display: inline-block; background-color: transparent; /* 消除因为换行和缩进带来的间隔 */ white-space: nowrap; font-size: 0; } .switch-bar button { color: white; padding: 0.5em 0.6em; border-radius: 0; background: rgb(50, 53, 62); position: relative; z-index: 0; /* 恢复默认大小 */ font-size: 16px; } .switch-bar button:first-child { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } .switch-bar button:last-child { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } .switch-bar .selected { background-color: rgb(60, 87, 221); } /* 下方标签 */ .labeled { position: relative; } .labeled::after { content: attr(data-tooltip); font-size: 12px; color: var(--theme-text); background-color: var(--theme-light); white-space: pre; padding: 4px 8px; position: absolute; z-index: 2; bottom: 0; left: 50%; transform: translateY(105%) translateX(-50%); border-radius: 4px; border: var(--theme-dark) solid 2px; display: none; } .labeled:hover::after { display: block; } /* 用列表组织的菜单 */ .btn-ul li { margin: 0 -0.3em; padding: 0.6em; border-radius: 4px; } .btn-ul li:hover { background-color: var(--theme-light) !important; color: white !important; } .btn-ul button { padding: 0.25em 0.6em; margin-bottom: 0.3em; border-radius: 6px; border: black solid 2px; } .btn-ul button:hover { color: white; } .btn-ul button:active { background-color: black; } textarea { width: calc(100% - 0.5em); height: 100%; padding: 0.3em; border: none; border-radius: 6px; background-color: var(--theme-dark); color: var(--theme-text); resize: vertical; } /* EQ控制面板 */ #EQcontrol { display: flex; flex-direction: column; align-items: center; margin-bottom: 1em; } #EQcontrol h5 { /* 频率值 */ margin: 0.4em 0 0 0; padding: 0; } #EQcontrol .myrange { width: 100%; margin: 0 0 0.3em 0; } #EQcontrol input { width: 100%; } /* 漂亮的滑动条 */ .niceScroll { overflow: auto; } .niceScroll::-webkit-scrollbar { width: 12px; } .niceScroll::-webkit-scrollbar-thumb { background-color: rgb(50, 53, 62); border: 3px solid rgb(37, 38, 45); border-radius: 6px; } .niceScroll::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background-color: rgb(37, 38, 45); } /* 分析面板 */ .tonalityResult { width: 100%; border-left: white 1px solid; } .tonalityResult div { color: var(--theme-dark); height: 1em; font-size: 1em; line-height: 1em; border-top-right-radius: 4px; border-bottom-right-radius: 4px; } /* 设置面板 */ #settingPannel button { margin: 0; } #settingPannel li { display: flex; flex-direction: row; justify-content: center; align-items: center; flex-wrap: wrap; position: relative; } #settingPannel li::after { content: attr(data-value); position: absolute; right: 0; bottom: 0; font-size: 10px; } #settingPannel li button:first-of-type { font-family: monospace; margin-right: 0.2em; } #settingPannel li button:last-of-type { font-family: monospace; margin-left: 0.2em; } #repeatRange { display: flex; flex-wrap: nowrap; align-items: center; justify-content: center; width: 100%; margin: 0.4em 0; } #repeatRange input[type="text"] { width: 46%; border-radius: 4px; padding-left: 4px; border: none; border: black solid 1px; font-size: 0.9em; color: var(--theme-text); background: var(--theme-dark); } #repeatRange input[type="text"]:focus { color: white; } canvas.selecting { cursor: ew-resize; } .pointer { cursor: pointer; } .dim-text { color: var(--theme-text) !important; } ================================================ FILE: ui/channelDiv.js ================================================ /** * 可拖动列表 * @param {*} takeplace 占位符是否起作用,用于拖拽到最后还留有一段空间 * @returns {HTMLDivElement} 一个可以拖动元素的ul */ function dragList(takeplace = true) { let list = document.createElement('ul'); list.classList.add('drag_list'); // 为了编写方便,占位符一直存在 list.innerHTML = `
`; // 由于占位的存在,所以不能用原来的children获取li。对外屏蔽这个占位 Object.defineProperty(list, 'children', { get: function () { // querySelectorAll 方法返回的是一个 NodeList 对象,而不是一个真正的数组 return Array.from(this.querySelectorAll('li')); } }); let dragging = null; list.ondragstart = (e) => { dragging = e.target; setTimeout(() => { // 为了让拖拽的dom还保持原有样式,所以延迟添加moving样式 e.target.classList.add('moving'); }, 0); e.dataTransfer.effectAllowed = 'move'; }; // 以下两个事件使用addEventListener,用于后续添加新的事件 list.addEventListener('dragover', (e) => { e.preventDefault(); let target = e.target; // 防止因为拖拽到li的子元素而判断为不是拖拽到li while (target.nodeName !== 'LI') { target = target.parentNode; if (!target) return; } if (target != dragging) { const rect = target.getBoundingClientRect() let rectHalfPosition = rect.y + (rect.height >> 1); // 计算目标的中间在屏幕中的坐标 if (e.clientY > rectHalfPosition) { // 在目标元素下方插入 list.insertBefore(dragging, target.nextElementSibling); // 从下向上拖动 } else { // 在目标元素上方插入 list.insertBefore(dragging, target); } } }); list.addEventListener('dragend', (e) => { e.target.classList.remove('moving'); }); // 添加元素将用li包裹 list.appendChild = function (node, at = -1) { let ITEM = document.createElement('li'); ITEM.draggable = true; ITEM.classList.add('drag_list-item'); ITEM.appendChild(node); if (at < 0) { this.insertBefore(ITEM, this.lastElementChild); } else { // 只关注li const liElements = this.querySelectorAll('li'); if (at >= 0 && at < liElements.length) { this.insertBefore(ITEM, liElements[at]); } else { this.insertBefore(ITEM, this.lastElementChild); } } }; list.clear = function () { const takeplace = this.lastElementChild; this.innerHTML = ''; Node.prototype.appendChild.call(this, takeplace); } // 动画的原理是,先用translate变到之前的位置,然后通过设置translate=none变回来。但是涉及动画时反复触发的问题,所以没做 // transtition的时候获取的坐标是最终值,所以也不能中途转向 return list; } // 为了可读性、隔离性、模块化,使用此类包裹HTMLDivElement // 会抛出事件: lock visible mute 在三个值被set时触发 class ChannelItem extends HTMLDivElement { /** * 实际并不使用构造函数 此函数只是表明有哪些属性可用 */ constructor() { super(); this.nameDiv = null; this.instrumentDiv = null; this.lockButton = null; this.visibleButton = null; this.muteButton = null; // 用ChannelList.addChannel添加时会注入ch属性,存储了对应的合成器音轨 因为合成器是ChannelList的成员 this.ch = null; } /** * 通过更改原型链实现构造 * @param {string} name * @param {string} color * @returns {ChannelItem} */ static new(name = "channel", color = "red", instrument = "Piano", visible = true, mute = false, lock = false) { let tempDiv = document.createElement('div'); tempDiv.innerHTML = `
${name}
${instrument}
`; // 可以通过设置style的--tab-color改颜色;data-tab-index用于显示序号 let container = tempDiv.firstElementChild; // 不能用firstChild因为获取的是文本节点 container.nameDiv = tempDiv.querySelector('.channel-Name'); container.instrumentDiv = tempDiv.querySelector('.channel-Instrument'); const buttons = tempDiv.querySelectorAll('.tab'); container.lockButton = buttons[0]; container.visibleButton = buttons[1]; container.muteButton = buttons[2]; container.lockButton.addEventListener('click', (e) => { e.stopPropagation(); container.lock = !container.lock; container.lockButton.blur(); }); container.visibleButton.addEventListener('click', (e) => { e.stopPropagation(); container.visible = !container.visible; container.lock = !container.visible; // 先执行本函数的目的再联动lock container.visibleButton.blur(); }); container.muteButton.addEventListener('click', (e) => { e.stopPropagation(); container.mute = !container.mute; container.muteButton.blur(); }); // 设置原型链为ChannelItem Object.setPrototypeOf(container, ChannelItem.prototype); container.lock = lock; container.visible = visible; container.mute = mute; return container; } get name() { return this.nameDiv.innerHTML; } set name(channelName) { this.nameDiv.innerHTML = channelName; } get instrument() { return this.instrumentDiv.innerHTML; } set instrument(instrument) { this.instrumentDiv.innerHTML = instrument; } get color() { return this.style.getPropertyValue('--tab-color'); } set color(color) { this.style.setProperty('--tab-color', color); } get lock() { return this.lockButton.dataset.state === 'lock'; } set lock(lock) { if (typeof lock !== 'boolean') lock = lock === "lock"; if (lock) { this.lockButton.dataset.state = 'lock'; this.lockButton.classList.remove('icon-unlock'); this.lockButton.classList.add('icon-lock'); } else { this.lockButton.dataset.state = 'unlock'; this.lockButton.classList.remove('icon-lock'); this.lockButton.classList.add('icon-unlock'); } this.dispatchEvent(new Event('lock', { bubbles: true })); } get visible() { // true为可见 return this.visibleButton.dataset.state === 'visible'; } set visible(visible) { if (typeof visible !== 'boolean') visible = visible === "visible"; if (visible) { this.visibleButton.dataset.state = 'visible'; this.visibleButton.classList.remove('icon-eyeslash-fill'); this.visibleButton.classList.add('icon-eye-fill'); } else { this.visibleButton.dataset.state = 'invisible'; this.visibleButton.classList.remove('icon-eye-fill'); this.visibleButton.classList.add('icon-eyeslash-fill'); } this.dispatchEvent(new Event('visible', { bubbles: true })); } get mute() { // true为静音 return this.muteButton.dataset.state === 'mute'; } set mute(mute) { if (typeof mute !== 'boolean') mute = mute === "mute"; if (mute) { this.muteButton.dataset.state = 'mute'; this.muteButton.classList.remove('icon-volume'); this.muteButton.classList.add('icon-close_volume'); } else { this.muteButton.dataset.state = 'nomute'; this.muteButton.classList.remove('icon-close_volume'); this.muteButton.classList.add('icon-volume'); } this.dispatchEvent(new Event('mute', { bubbles: true })); } /** * 从0开始,表示第几项;但显示时从1开始。需要外部维护 */ get index() { return parseInt(this.dataset.tabIndex) - 1; } set index(index) { this.dataset.tabIndex = index + 1; } toJSON() { // 用于序列化,以实现撤销 return { name: this.name, color: this.color, instrument: this.instrument, lock: this.lock, visible: this.visible, mute: this.mute }; } } /** * 依赖:contextMenu dragList ChannelItem tinySynth * 事件:(按发生的顺序排) * remove(detail):发生于删除之前、归还颜色之后 * reorder(detail):发生于有序号变化时,最后一个ChannelItem的删除和新增不会触发 * * setted: 通过UI修改了channel属性后触发 */ class ChannelList extends EventTarget { // 颜色是对通道的特异性标识 static colorList = [ "#FF4500", /*橙红色*/ "#FFD700", /*金色*/ "#32CD32", /*酸橙绿*/ "#00BFFF", /*深天蓝色*/ "#FF6347", /*番茄色*/ "#FF1493", /*深粉红色*/ "#7FFF00", /*查特酸橙绿*/ "#1E90FF", /*道奇蓝*/ "#FFA500", /*橙色*/ "#EE82EE", /*紫罗兰*/ "#ADFF2F", /*绿黄色*/ "#87CEFA", /*亮天蓝色*/ "#FF69B4", /*热情粉红色*/ "#00FA9A", /*中春绿色*/ "#FFB6C1", /*浅粉红色*/ "#20B2AA", /*浅海洋绿*/ "#FF8C00", /*深橙色*/ "#BA55D3", /*中紫罗兰色*/ "#9ACD32", /*黄绿色*/ "#4682B4", /*钢蓝色*/ "#8A2BE2", /*蓝紫色*/ "#5F9EA0", /*军蓝色*/ "#D2691E", /*巧克力色*/ "#6495ED", /*矢车菊蓝*/ "#DC143C", /*猩红色*/ "#00FFFF", /*青色*/ "#00008B", /*深蓝色*/ "#FF7F50" /*珊瑚色*/ ]; /** * 判断是否点击在channelItem上 * 必须被
  • 包裹才能生效 因此耦合了dragList和dom结构 * @param {HTMLElement} target 一般是e.target * @returns 如果点击在channelItem上,返回channelItem的container,否则返回null */ static whichItem(target) { const li = target.tagName === 'LI' ? target : target.closest('li'); if (li && li.firstElementChild.classList.contains('channel-Container')) { return li.firstElementChild; } else return null; } static judgeClick(e) { return ChannelList.whichItem(e.target); } /** * 初始画可拖拽音轨列表 * @param {HTMLDivElement} div * @param {TinySynth} synthesizer 合成器实例 */ constructor(div, synthesizer) { super(); this.synthesizer = synthesizer; this.colorMask = 0; // 用于表示哪些颜色已经被占用 for (let i = 0; i < ChannelList.colorList.length; i++) { this.colorMask |= (1 << i); } const list = dragList(); list.addEventListener('dragend', this.updateRange.bind(this)); this.selected = null; list.addEventListener('click', e => { this.selectChannel(e.target); }); this.container = list; this.channel = []; // 由updateRange维护 作用是根据id快速定位ChannelItem 屏蔽了li的包裹 this.addChannel(); // 默认有一个 div.appendChild(list); // 右键菜单 this.contextMenu = new ContextMenu([ // 在空白部分右击 { name: '添加音轨', callback: () => { this.addChannel(); }, onshow: e => !ChannelList.whichItem(e.target) && this.colorMask }, { name: '全部隐藏', callback: () => { this.channel.forEach(ch => ch.visible = false); }, onshow: e => !ChannelList.whichItem(e.target), }, { name: '全部显示', callback: () => { this.channel.forEach(ch => ch.visible = true); }, onshow: e => !ChannelList.whichItem(e.target), }, { name: '全部静音', callback: () => { this.channel.forEach(ch => ch.mute = true); }, onshow: e => !ChannelList.whichItem(e.target), }, { name: '全部发声', callback: () => { this.channel.forEach(ch => ch.mute = false); }, onshow: e => !ChannelList.whichItem(e.target), }, // 在列表项上点击 { name: '属性设置', callback: (e) => { let id = parseInt(ChannelList.whichItem(e.target).dataset.tabIndex) - 1; this.selectChannel(id); // 传id计算量小一点 this.settingPannel(id); }, onshow: ChannelList.judgeClick }, { name: '在上方插入音轨', callback: (e) => { let id = parseInt(ChannelList.whichItem(e.target).dataset.tabIndex) - 1; this.addChannel(id); }, onshow: ChannelList.judgeClick }, { name: '在下方插入音轨', callback: (e) => { let id = parseInt(ChannelList.whichItem(e.target).dataset.tabIndex); this.addChannel(id); }, onshow: ChannelList.judgeClick }, { name: '删除该轨', callback: (e) => { this.removeChannel(ChannelList.whichItem(e.target)); }, onshow: ChannelList.judgeClick } ]); list.addEventListener('contextmenu', (e) => { e.preventDefault(); this.contextMenu.show(e); }); ChannelItem.prototype.toJSON = this._toJSON; } /** * 根据ui维护this.channel和channelItem.dataset.tabIndex * 如果发生变化会触发事件:reorder,detail为老顺序->新顺序的变换关系,类似状态转移矩阵 * “新增在最后一个”和“删除最后一个”不会触发reorder */ updateRange() { let change = false; let children = Array.from(this.container.children); let indexMap = new Array(children.length + 1); // 防止重新分配空间 加一是为了兼容删除一个后的reorder this.synthesizer.channel = new Array(children.length); this.channel = new Array(children.length); for (let i = 0; i < children.length; i++) { const channel = children[i].firstElementChild; let oldIndex = channel.index; indexMap[oldIndex] = i; // 如果在at插入了新的ChannelItem,由于其序号已经对应好,所以不会触发change;且原来在at的元素被推到了(at+1),会覆盖其对indexMap[at]的更改 if (oldIndex !== i) change = true; channel.dataset.tabIndex = i + 1; this.channel[i] = channel; this.synthesizer.channel[i] = channel.ch; } if (change) this.dispatchEvent(new CustomEvent("reorder", { detail: indexMap })); } /* 颜色管理 begin */ borrowColor() { for (let i = 0; i < ChannelList.colorList.length; i++) { if (this.colorMask & (1 << i)) { this.colorMask ^= (1 << i); return ChannelList.colorList[i]; } } return null; } borrowTheColor(color) { for (let i = 0; i < ChannelList.colorList.length; i++) { if (ChannelList.colorList[i] === color) { if (this.colorMask & (1 << i)) { this.colorMask ^= (1 << i); return color; } else return null; } } return null; } returnColor(color) { for (let i = 0; i < ChannelList.colorList.length; i++) { if (ChannelList.colorList[i] === color) { this.colorMask |= (1 << i); return; } } } /* 颜色管理 end */ /** * 增加一个channel,触发add事件,发生于插入之后 * 然后可能会触发reorder事件,取决于是否插入最后一个 * 最后触发added事件 * @param {number} at 插入音轨的序号 * @returns {ChannelItem} */ addChannel(at = this.channel.length) { // 用于一个个添加 if (!this.colorMask) { alert(`最多只能添加${ChannelList.colorList.length}个轨道!`); return; } const ch = ChannelItem.new('某音轨', this.borrowColor(), TinySynth.instrument[0]); ch.index = at; ch.ch = this.synthesizer.addChannel(at); this.container.appendChild(ch, at); ch.click(); this.dispatchEvent(new CustomEvent("add", { detail: ch })); this.updateRange(); this.dispatchEvent(new Event("added")); return ch; } /** * 删除一个channel,触发remove事件,发生于删除之前、归还颜色之后 * 然后可能会触发reorder事件,取决于是否删除最后一个 * 最后触发removed事件 * remove事件必须在reorder之前,因为reorder会触发重新映射,之后就不能根据原有的索引删除音符了 * 此外由于reorder的不稳定触发(会触发存档操作),使用时需要提前清除reorder的回调 * @param {ChannelItem || Number} node 节点的序号或者节点或其子元素 */ removeChannel(node) { const channel = typeof node === 'number' ? this.channel[node] : ChannelList.whichItem(node); if (!channel) return; this.returnColor(channel.color); this.dispatchEvent(new CustomEvent("remove", { detail: channel })); this.synthesizer.channel.splice(channel.index, 1); if (this.selected === channel) this.selected = null; // 之所以要parentNode是因为dragList中添加项会用
  • 包裹 // 而this.channel[node]是channelItem(在上一次的updateRange中根据container.children赋值,赋值时使用了firstElementChild) channel.parentNode.remove(); this.updateRange() // 可能会触发reorder事件 this.dispatchEvent(new Event("removed")); } /** * 设置选中的channel的样式 * @param {ChannelItem || Number} node 节点的序号或者节点或其子元素 * @returns {ChannelItem} 如果无该项则返回null */ selectChannel(node) { const channel = typeof node === 'number' ? this.channel[node] : ChannelList.whichItem(node); if (channel && channel !== this.selected) { if (this.selected) this.selected.classList.remove('selected'); this.selected = channel; channel.classList.add('selected'); return channel; } return null; } /** * 打开ch的设置面板 * @param {number} chid 音轨序号 */ settingPannel(chid) { const ch = this.channel[chid]; const originConfig = JSON.stringify(ch); let tempDiv = document.createElement('div'); tempDiv.innerHTML = `
    音轨名:
    音量: 
    音色: 
    `; const card = tempDiv.firstElementChild; const btns = card.getElementsByTagName('button'); card.addEventListener('keydown', (e) => { if (e.keyCode === 13) btns[1].click(); // 回车则点击btns[1] }); const close = () => { // 渐变消失 card.style.opacity = 0; setTimeout(()=>card.remove(), 200); // 如果有修改则触发事件以存档 const newConfig = JSON.stringify(ch); if (originConfig !== newConfig) this.dispatchEvent(new Event('setted')); } btns[0].addEventListener('click', close); btns[1].addEventListener('click', () => { ch.name = inputs[0].value; ch.ch.volume = parseInt(inputs[1].value); let inst = parseInt(inputs[2].value); ch.ch.instrument = inst; ch.instrument = TinySynth.instrument[inst]; close(); }); const inputs = card.querySelectorAll('[name="ui-ask"]'); inputs[0].value = ch.name; inputs[1].value = ch.ch.volume; // 给select添加选项 for (let i = 0; i < 128; i++) { const option = document.createElement('option'); option.value = i; option.innerHTML = TinySynth.instrument[i]; if (ch.ch.instrument === i) option.selected = true; inputs[2].appendChild(option); } document.body.insertBefore(card, document.body.firstChild); card.tabIndex = 0; card.focus(); } _toJSON() { return { // 篡改ChannelItem的原型方法,使保存的乐器是序号,并能保存音量 name: this.name, color: this.color, lock: this.lock, visible: this.visible, mute: this.mute, instrument: this.ch.instrument, volume: Math.round(Math.sqrt(this.ch.out.gain.value * 16129)), selected: this.classList.contains('selected') ? 1 : undefined }; } /** * 从数组中创建列表,用于撤销 不会(不能)调用updateRange * @param {Array} array */ fromArray(array) { let len = array.length; if (len > ChannelList.colorList.length) { console.warn(`轨道数超过最大值${ChannelList.colorList.length}!将忽略多余的轨道。`); len = ChannelList.colorList.length; } this.synthesizer.channel.length = 0; this.container.clear(); this.channel = new Array(len); this.colorMask = 0xFFFF; let failed = 0x0000; for (let i = 0; i < len; i++) { const item = array[i]; let color = this.borrowTheColor(item.color); if (!color) { color = ''; failed &= (1 << i); } const ch = ChannelItem.new(item.name, color, TinySynth.instrument[item.instrument], item.visible, item.mute, item.lock); ch.ch = this.synthesizer.addChannel(i, item.instrument, item.volume * item.volume / 16129); this.channel[i] = ch; ch.dataset.tabIndex = i + 1; if (item.selected) ch.click(); this.container.appendChild(ch); } if (failed) { console.warn('颜色冲突或超出范围!将自动分配违规颜色。'); for (let i = 0; i < len; i++) { if (failed & (1 << i)) { this.channel[i].color = this.borrowColor(); } } } } } ================================================ FILE: ui/contextMenu.js ================================================ class ContextMenu { /** * 创建菜单 * @param {Array} items [{ * name: "菜单项", * callback: (e_father, e_self) => { // 点击菜单项时调用的函数,传参是(触发右键菜单的事件,点击本项的事件) * return false/true; * }, // 返回false(或不返回)表示删除菜单,返回true表示不删除菜单 * onshow: function (e) { // 在菜单项显示前调用,传参是触发右键菜单的事件 * // this指向菜单项对象,可以修改其属性 * return true/false; * }, // 返回true/false控制本项是否显示 * event: "click" // 确认触发本项的事件,默认是click * },...] * @param {boolean} mustShow 如果菜单项为空,是否显示 */ constructor(items = [], mustShow = false) { this.items = items; this.mustShow = mustShow; } addItem(name, callback, onshow = null, event = "click") { let existingItem = this.items.find(item => item.name === name); if (existingItem) existingItem.callback = callback; else this.items.push({ name: name, callback: callback, onshow: onshow, event: event }); } removeItem(name) { for (let i = 0; i < this.items.length; i++) { if (this.items[i].name === name) { this.items.splice(i, 1); break; } } } show(e) { const contextMenuCard = document.createElement('ul'); contextMenuCard.classList.add('contextMenuCard'); contextMenuCard.oncontextmenu = () => false; // 禁用右键菜单 this.items.forEach(item => { if (item.onshow) if (!item.onshow(e)) return; const listItem = document.createElement('li'); listItem.innerHTML = item.name; // 从textContent改为innerHTML,可以使用html标签嵌套 listItem.addEventListener(item.event || 'click', (e_self) => { if (!item.callback(e, e_self)) { contextMenuCard.onblur = null; // 如果没有这行,onblur会在contextMenuCard被item删除后再次触发删除,引发报错 contextMenuCard.remove(); } }); contextMenuCard.appendChild(listItem); }); if (contextMenuCard.children.length === 0 && !this.mustShow) return; contextMenuCard.style.top = `${e.clientY}px`; contextMenuCard.style.left = `${e.clientX}px`; // 添加blur事件监听器 contextMenuCard.tabIndex = -1; // 使元素可以接收焦点 contextMenuCard.onblur = (e) => { // 如果在contextMenuCard内部点击,就不删除contextMenuCard if (e.relatedTarget && e.relatedTarget.classList.contains('contextMenuCard')) { e.stopPropagation(); return; } contextMenuCard.remove(); } setTimeout(() => { document.body.appendChild(contextMenuCard); // 使元素立即获取焦点(要设置css:focue属性:outline:none;) contextMenuCard.focus(); }, 0); // 延时是因为让show可以被mousedown事件调用(否则mousedown触发后再触发contextmenu将导致菜单消失) } } ================================================ FILE: ui/myRange.js ================================================ class myRange extends HTMLInputElement { /** * 设置原型并初始化 * @param {HTMLInputElement} ele * @returns {myRange} */ static new(ele) { Object.setPrototypeOf(ele, myRange.prototype); myRange.prototype.init.call(ele); return ele; } /** * 设置一个容器 * 执行了构造函数的内容 */ init() { this.default = super.value; // 默认值在html中设置 this.container = document.createElement('div'); this.container.classList.add('myrange'); this.insertAdjacentElement('beforebegin', this.container); // 将当前元素插入到容器中 this.container.appendChild(this); this.addEventListener('click', this.blur); // 极速取消焦点 防止空格触发 } set value(v) { super.value = v; this.dispatchEvent(new Event('input')); } get value() { return super.value; } reset() { this.value = this.default; return this; // 可以链式调用,比如let r = myRange.new(document.querySelector('input')).reset(); } } class LableRange extends myRange { static new(ele) { Object.setPrototypeOf(ele, LableRange.prototype); LableRange.prototype.init.call(ele); return ele; } /** * 添加一个容器、标签 */ init() { super.init(); this.container.classList.add('labelrange'); // 设置标签显示当前值 this.label = document.createElement('span'); this.label.className = "thelabel"; this.insertAdjacentElement('afterend', this.label); // 设置label的宽度固定为range的最大值的宽度 if (!this.max) this.max = 100; let maxStepStr = (this.max - this.step).toFixed(10).replace(/\.?0+$/, ''); // 限制小数位数并去除末尾的零 let len = Math.max(this.max.toString().length, maxStepStr.length); this.label.style.width = `${len}ch`; this.addEventListener('input', () => { this.updateLabel(); // 【不直接传函数,可以篡改this.updateLabel】 }); // 标签的另一个作用:重置range的值 this.label.addEventListener('click', this.reset.bind(this)); // 【没有初始化label,需要用户手动调用reset()】 } updateLabel() { this.label.textContent = super.value; } } class hideLableRange extends myRange { static _expand = 16; // 和css有关 滑块的宽度 static new(ele) { Object.setPrototypeOf(ele, hideLableRange.prototype); hideLableRange.prototype.init.call(ele); return ele; } /** * 添加一个容器、标签 */ init() { super.init(); this.container.classList.add('hidelabelrange'); // 设置标签显示当前值 this.label = document.createElement('span'); this.label.className = "thelabel"; this.insertAdjacentElement('afterend', this.label); this.addEventListener('input', () => { this.updateLabel(); // 【不直接传函数,可以篡改this.updateLabel】 }); // 标签的另一个作用:重置range的值 this.label.addEventListener('click', this.reset.bind(this)); // 【没有初始化label,需要用户手动调用reset()】 // 滑动时显示label this.label.style.display = 'none'; this.addEventListener('focus', function () { this.label.style.display = 'block'; }); this.addEventListener('blur', function () { this.label.style.display = 'none'; }); this.addEventListener('input', this.labelPosition); } updateLabel() { this.label.textContent = super.value; } labelPosition() { let rangeRect = this.getBoundingClientRect(); let rangeWidth = rangeRect.width - hideLableRange._expand; this.label.style.left = `${((this.value - this.min) / (this.max - this.min)) * rangeWidth + (hideLableRange._expand >> 1)}px`; } } ================================================ FILE: ui/siderMenu.js ================================================ class SiderContent extends HTMLDivElement { static new(ele, minWidth) { Object.setPrototypeOf(ele, SiderContent.prototype); SiderContent.prototype.init.call(ele, minWidth); return ele; } init(minWidth) { this.resize = this._resize.bind(this); this.mouseup = this._mouseup.bind(this); this.mousedown = this._mousedown.bind(this); this.classList.add('siderContent'); this.minWidth = minWidth; this.judge = (minWidth >> 1) + this.getBoundingClientRect().left; this.style.width = minWidth + 'px'; const bar = document.createElement('div'); bar.className = 'siderBar'; this.insertAdjacentElement('afterend', bar); bar.addEventListener('mousedown', this.mousedown); this.bar = bar; } _mousedown(e) { if (e.button) return; document.addEventListener('mousemove', this.resize); document.addEventListener('mouseup', this.mouseup); } _resize(e) { if (e.clientX < this.judge) this.display = 'none'; else { let rect = this.getBoundingClientRect(); let w = e.clientX - rect.left; if (w < this.minWidth) return; // 触发刷新 this.width = w + 'px'; this.display = 'block'; } } _mouseup() { document.removeEventListener('mousemove', this.resize); document.removeEventListener('mouseup', this.mouseup); this.bar.blur(); window.dispatchEvent(new Event("resize")); // 触发app.resize } get display() { return this.style.display; } // 设置display可以触发刷新 因为app.resize绑定在window.onresize上 set display(state) { if (this.style.display != state) { this.style.display = state; window.dispatchEvent(new Event("resize")); } } get width() { return this.style.width; } set width(w) { if (this.style.width != w) { this.style.width = w; window.dispatchEvent(new Event("resize")); } } } class SiderMenu extends HTMLDivElement { /** * 构造tabMenu和container * @param {HTMLDivElement} menu 存放tab的 样式: .siderTabs 每一个tab: .siderTab * @param {HTMLDivElement} container 展示具体内容的 样式: .siderContent 拖动条: .siderBar 每一个子内容都会加上siderItem类 * @param {number} minWidth 展示具体内容的最小宽度 * @returns {SiderMenu} 构造好的SiderMenu */ static new(menu, container, minWidth) { Object.setPrototypeOf(menu, SiderMenu.prototype); SiderMenu.prototype.init.call(menu, container, minWidth); return menu; } init(box, minWidth) { this.classList.add('siderTabs'); this.container = SiderContent.new(box, minWidth); box.display = 'none'; this.tabClick = this._tabClick.bind(this); this.tabs = []; } /** * 添加一个菜单项及其内容 * @param {string} name tab的名字 * @param {string} tabClass tab的类名 用空格分隔 * @param {HTMLElement} dom tab对应的内容 * @param {boolean} selected 是否默认选中 * @returns {HTMLDivElement} 添加的tab .item是dom .dataset.name是名称 */ add(name, tabClass, dom, selected = false) { const tab = document.createElement('div'); tab.className = 'siderTab'; tab.classList.add(...tabClass.split(' ')); tab.dataset.name = name; this.container.appendChild(dom); dom.classList.add('siderItem'); dom.style.display = 'none'; tab.item = dom; tab.addEventListener('click', this.tabClick); this.appendChild(tab); if (this.tabs.push(tab) == 1) { tab.classList.add('selected'); dom.style.display = 'block'; } else if (selected) this.select(tab); return tab; } /** * 选中一个标签 * @param {HTMLDivElement || Number} tab * @returns {HTMLDivElement} 选择的标签 */ select(tab) { if (typeof tab == 'number') tab = this.tabs[tab]; if (!tab) return; for (const t of this.tabs) { t.classList.remove('selected'); t.item.style.display = 'none'; } tab.classList.add('selected'); tab.item.style.display = 'block'; return tab; } /** * 控制面板的显示 * @param {boolean} ifshow 是否显示面板 */ show(ifshow = true) { this.container.display = ifshow ? 'block' : 'none'; } // 绑定给tab用,不应该用户被调用 _tabClick(e) { const tab = e.target; if (tab.classList.contains('selected')) { // 如果显示的就是tab的,则隐藏 // 用style.dispaly是读取,用.display = 是为了刷新 this.container.display = this.container.style.display == 'none' ? 'block' : 'none'; } else { // 否则只显示tab的 for (const t of this.tabs) { t.classList.remove('selected'); t.item.style.display = 'none'; } tab.classList.add('selected'); this.container.display = 'block'; } tab.item.style.display = 'block'; tab.blur(); } }