# HG changeset patch # User Daniel Wolff # Date 1455048306 -3600 # Node ID 718306e29690a01c0c6029827a29d1698a94f997 commiting public release diff -r 000000000000 -r 718306e29690 .hg_archival.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hg_archival.txt Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,6 @@ +repo: 9b468c630020a7629598df694c61f1b8da44bfd1 +node: 023a89f1b9079073d0726030237c6afdf8392ff0 +branch: partial_results +latesttag: public +latesttagdistance: 1 +changessincelatesttag: 1 diff -r 000000000000 -r 718306e29690 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,4 @@ +\.pyc$ +\.*\.sw.$ +.DS_Store +scripts/compression/dlzma diff -r 000000000000 -r 718306e29690 COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,674 @@ + 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 +. diff -r 000000000000 -r 718306e29690 LICENSES --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSES Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,8 @@ +This distribution includes the following components: + +Bootstrap v3.3.2 Javascript and CSS, Copyright 2011-2015 Twitter, Inc: MIT License + bootstrap.min.1.css is a modified version of the original. + +svg-pan-zoom v3.0.0 https://github.com/ariutta/svg-pan-zoom + +Kube 3.1 CSS framework diff -r 000000000000 -r 718306e29690 cpack/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/README Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,3 @@ +These directories must all by symlinked into the the cpack directory +of the ClioPatria instance directory. The main code is in the +dml directory. diff -r 000000000000 -r 718306e29690 cpack/dbpedia/LICENSES --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dbpedia/LICENSES Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,3 @@ +The DBPedia ontology is made available under the terms of the +Creative Commons Attribution-ShareAlike 3.0 License and the +GNU Free Documentation License. See http://wiki.dbpedia.org/ . diff -r 000000000000 -r 718306e29690 cpack/dbpedia/lib/dbpedia.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dbpedia/lib/dbpedia.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,31 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University College London. + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dbpedia, []). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_library)). + +/** Provide DBPedia schema and namespaces + +*/ + +:- rdf_register_ns(dbpedia, 'http://dbpedia.org/'). +:- rdf_register_ns(dbprop, 'http://dbpedia.org/property/'). +:- rdf_register_ns(dbont, 'http://dbpedia.org/ontology/'). +:- rdf_attach_library(dbpedia(rdf)). +:- rdf_load_library(dbpedia). diff -r 000000000000 -r 718306e29690 cpack/dbpedia/rdf/base/Manifest.ttl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dbpedia/rdf/base/Manifest.ttl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,20 @@ +@prefix lib: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix dcterms: . +@prefix dbpedia: . +@prefix dbprop: . +@prefix dbont: . + + + a lib:Schema ; + a lib:Virtual ; + dcterms:title "DBPedia schema" ; + owl:imports + . + +[ a lib:Namespace ; lib:mnemonic "dbpedia" ; lib:namespace dbpedia: ] . +[ a lib:Namespace ; lib:mnemonic "dbprop" ; lib:namespace dbprop: ] . +[ a lib:Namespace ; lib:mnemonic "dbont" ; lib:namespace dbont: ] . + diff -r 000000000000 -r 718306e29690 cpack/dbpedia/rdf/base/dbpedia/dbpedia_3.9.owl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dbpedia/rdf/base/dbpedia/dbpedia_3.9.owl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,6080 @@ + + + + Version 3.8 + + + Ομοσπονδία Καλαθοσφαίρισηςligue de basketballbasketball leaguelega di pallacanestroバスケットボールリーグa group of sports teams that compete against each other in Basketball + + provinceprovinceprovincieAn administrative body governing a territorial unity on the intermediate level, between local and national level + + lunar cratercratère lunaireΣεληνιακός κρατήραςmaankrater + + motorsport season + + στρατιωτικόςmilitairemilitary personmilitaremilitair군인 + + χρονική περίοδοςpériode temporelletime periodtijdvakperiodo temporal + + κινητήρας αυτοκινήτουmoteur d'automobileautomobile enginemotore d'automobile内燃機関motor de automóvelFahrzeugmotor + + ένζυμοenzymeenzima酵素enzymenzym + + πανεπιστήμιοuniversitéuniversity大学universiteit대학universidadeuniversidadUniversität + + ανατομική δομήstructure anatomiqueanatomical structurestruttura anatomica解剖構造anatomische structuur해부학anatomska struktura + + τηλεοπτική σειράémission de télévisiontelevision showテレビ番組televizijska oddaja + + launch padράμπα φορτώσεωςrampe de lancement + + cycling leagueΟμοσπονδία Ποδηλασίαςligue de cyclismea group of sports teams that compete against each other in Cycling + + territory + + curling leagueπρωτάθλημα curlingligue de curlinga group of sports teams that compete against each other in Curling + + φεστιβάλ μουσικήςfestival de musiquemusic festivalmuziekfestival음악제festival de música + + φόροςtaxetax租税belastingimpuestoSteuer + + racecourseippodromoA racecourse is an alternate term for a horse racing track, found in countries such as the United Kingdom, Australia, Hong Kong, and the United Arab Emirates. + + ice hockey playerπαίκτης χόκεϋjoueur de hockey sur glaceijshockeyspeler + + public transit systemÖffentliches PersonenverkehrssystemEin System des Öffentlichen Personenverkehrs auf Straße, Schiene oder Wasser. + + ομάδα αίματοςacademic journal血液型bloedgroeptipo sanguíneoBlutgruppe + + football matchαγώνας ποδοσφαίρουmecz piłki nożnejpartido de fútbola competition between two football teams + + MouseGeneLocationマウス遺伝子座 + + military conflictστρατιωτική σύγκρουσηconflit militaire + + φεστιβάλ κινηματογράφουfestival du filmfilm festival映画祭filmfestival영화제 + + αναψυκτικόboissonbeveragebevanda飲料drank음료bebidaGetränkA drink, or beverage, is a liquid which is specifically prepared for human consumption.Ein Getränk ist eine zum Trinken zubereitete Flüssigkeit. Getränke werden entweder zum Stillen von Durst und damit zur Wasseraufnahme des Körpers, als Nahrungsmittel oder auch als reine Genussmittel aufgenommen.Ένα πόσιμο υγρό ρόφημα, συνήθως με μηδενική ή ελάχιστη περιεκτικότητα αλκοόλης. + + space shuttlenavette spatialeδιαστημικό λεωφορείο우주 왕복선 + + φυλακήprisonprisonprigionegevangenisgefängnis + + αρχαίαarchéesarchaeaarchei古細菌 + + handball playerπαίκτης του handballjoueur de handballhandballer + + religiousreligieuxθρησκευτικός + + αραχνοειδέςarachnidesarachnidaracnideクモ綱spinachtigenaracnídeos + + InstallmentδόσηVersementDeel (van werk) + + department + + painterpeintreMalerschilder + + line of fashionmodelijntype de coutureA coherent type of clothing or dressing following a particular fashionEen samenhangend geheel van kleding in een bepaalde stijl volgens een bepaalde mode. + + πάρκοparcpark公園park공원parquePark + + cycling teamsquadra di ciclismo + + cricketerπαίκτης του κρίκετjoueur de cricketcricketspeler + + ανθοφόρο φυτόangiospermesflowering plantmagnoliofita被子植物bedecktsamige Pflanze + + television episodeεπεισόδιο τηλεόρασηςépisode télévisécapítulo de serie de televisiónA television episode is a part of serial television program. + + グネツム綱GnetophytesGnetophytesgnétophytes + + jockey (horse racer)αναβάτης αλόγου αγώνων騎手 + + results of a sport competitionαποτελέσματα αθλητικού διαγωνισμούrésultats d'une compétition sportiveresultados de una competición deportiva + + πρωτεΐνηprotéineproteinproteinaタンパク質proteïne단백질proteínaprotein + + HumanGeneLocationτοποθεσία του ανθρώπινου γονιδίουヒト遺伝子座 + + speedway teamklub żużlowy + + χριστιανός πατριάρχηςChristian Patriarchpatriarca cristianochristelijk patriarchpatriarcha chrześcijański + + Government Typerégime politiqueΕίδη Διακυβέρνησηςa form of governmentregeringsvorm + + πόληvilletownstadmiasteczkoa settlement ranging from a few hundred to several thousand (occasionally hundreds of thousands). The precise meaning varies between countries and is not always a matter of legal definition. Usually, a town is thought of as larger than a village but smaller than a city, though there are exceptions to this rule. + + édifice religieuxreligious buildingedificio religioso宗教建築cultusgebouwedificio religiosoAn establishment or her location where a group of people (a congregation) comes to perform acts of religious study, honor, or devotion. + + motorcycle riderμοτοσυκλετιστής + + clerical administrative regionrégion administrative dans une églisekerkelijk bestuurlijk gebiedAn administrative body governing some territorial unity, in this case a clerical administrative body + + power station発電所centrale électriquecentral eléctrica + + μηχανικόςingénieurengineeringeniere技術者ingenieuringenieroIngenieur + + όνομαnomname名前naamnomeName + + sumo wrestlersumoworstelaar + + Formula One racerπιλότος της φόρμουλας έναpilote de formule 1 + + κωνοφόροconifereconifer球果植物門conifeerLe conifere sono piante vascolari, con semi contenuti in un cono. Sono piante legnose, perlopiù sono alberi e solo poche sono arbusti. + + speedway leagueπρωτάθλημα αυτοκινητοδρόμουligue de speedwayA group of sports teams that compete against each other in motorcycle speedway racing. + + videogames leagueligue de jeux vidéoA group of sports teams or person that compete against each other in videogames. + + εταιρίαentreprisecompany会社bedrijf회사empresaUnternehmen + + κινητήριοςlocomotivelocomotivelocomotiefLokomotive + + παλαιστήςlutteurwrestlerレスラーworstelaar + + motorcycle racing leagueligue de courses motocyclistea group of sports teams or bikerider that compete against each other in Motorcycle Racing + + salesεκπτώσειςvente販売 + + ενήλικας (πορνογραφικός) ηθοποιόςacteur adulteadult (pornographic) actorattore pornoポルノ女優pornografisch acteurator adultoactor adultopornographischer Schauspieler + + gridiron football playerjoueur de football américain gridiron + + Christian DoctrineΧριστιανικό ΔόγμαChristelijke leerdottrina cristiana + + soccer leagueΟμοσπονδία Ποδοσφαίρουligue de footballA group of sports teams that compete against each other in soccer. + + Team membercoéquipierTeammitgliedΜέλος ομάδαςA member of an athletic team.Ένα μέλος μιας αθλητικής ομάδας. + + GeneLocationθέση γονιδίων遺伝子座 + + road junctionStraßenkreuzungwegkruising + + ΜύλοςTreadmillRosmolenA mill driven by the tractive power of horses, donkeys or even people + + εγκέφαλοςcerveaubraincervellocerebroGehirnΤο βασικό όργανο του νευρικού συστήματος των ζώων, το οποίο καθορίζει ασυνείδητες και συνειδητές λειτουργίες. Ο όρος χρησιμοποιείται πλέον και για τον χαρακτηρισμό των καθοριστικότερων στοιχείων μίας μηχανής ή ενός συνόλου πραγμάτων. + + protohistorical periodperiode in de protohistorie + + Women's Tennis Association tournamentTournoi de la Women's Tennis Association + + volleyball coachπροπονητής βόλλεϋ + + οικισμόςhiri orokormunicipalitémunicipalitygemeente도시 + + λογισμικόlogicielsoftwareソフトウェアsoftware소프트웨어programska opremaSoftware + + όπεραopéraoperaoperaオペラoperaόperaoper + + lacrosse playerπαίκτης χόκεϋ σε χόρτο + + Controlled designation of origin wineΕλεγμένη ονομασία προέλευσης κρασιούvin A.O.C.vino D.O.C.A quality assurance label for winesΜια ετικέτα διασφάλισης της ποιότητας των οίνων + + πρόεδροςprésidentpresident大統領국가원수prezydentPräsident + + racing driverοδηγός αγώνων + + αρχιτεκτονική κατασκευήstructure architecturalearchitectural structurestruttura architettonica構造物bouwkundige structuurestructura arquitecturalBauwerk + + παίχτης τένιςjoueur de tennistennis playertennisserjogador de tennistenista + + digital cameraappareil photo numériquedigitale camera + + γεγονόςévènementeventイベントgebeurteniseventoEreignis + + μουσικό συγκρότημαgroupe de musiqueBandgruppo musicaleバンド_(音楽)band음악 그룹bandabandaMusikgruppe + + regencykabupatenbagian wilayah administratif dibawah provinsi + + χώραpaysГосударствоcountryland나라državaStaat + + ταυρομάχοςtorerobullfightertorero闘牛士stierenvechtertorero + + french locality + + ψάριpoissonfish魚類vispeixeFisch + + Περιοδικόmagazinemagazine雑誌잡지PublikumszeitschriftMagazines, periodicals, glossies or serials are publications, generally published on a regular schedule, containing a variety of articles. They are generally financed by advertising, by a purchase price, by pre-paid magazine subscriptions, or all three.Περιοδικά ή γυαλιστερές φωτογραφίες περιοδικών εκδόσεων δημοσιεύονται σε τακτά χρονικά διαστήματα, περιέχει μια ποικιλία από αντικείμενα.Γενικά χρηματοδοτείται από διαφημίσεις, με τιμή αγοράς, με προπληρωμένες συνδρομές περιοδικών, ή και των τριών.Als Publikumszeitschrift (auch Magazin) bezeichnet man eine Gattung von Zeitschriften, die sich an eine sehr breite Zielgruppe wendet und keine fachlichen Prägungen oder andere spezifische Merkmale voraussetzt. Publikumszeitschriften dienen der Unterhaltung und Information, sie sollen unangestrengt gelesen werden können. + + γαλαξίαςgalaxiegalaxygalaksi銀河galáxia + + manhwamanhwaKorean term for comics and print cartoonsΚορεάτικος όρος για τα κόμικς και τα κινούμενα σχέδια εκτύπωσης + + Organisation memberΜέλος οργανισμούA member of an organisation.Μέλος ενός οργανισμού. + + television season + + caseSachedossierzaakA case is the total of work done to prepare for an administrative or business decision. As a rule, a case is reflected in a set of documents.Een zaak is het geheel aan werk gedaan om tot een bestuurlijke of zakelijke beslissing te komen. Een zaak slaat doorgaans neer in een verzameling documenten. + + εταιρεία δικηγόρωνlaw firm法律事務所advocatenkantoorfirma de abogadosAnwaltskanzleiA law firm is a business entity formed by one or more lawyers to engage in the practice of law. The primary service provided by a law firm is to advise clients (individuals or corporations) about their legal rights and responsibilities, and to represent their clients in civil or criminal cases, business transactions, and other matters in which legal advice and other assistance are sought.Als Anwaltskanzlei bezeichnet man die Büroräume und das Unternehmen oder den Betrieb eines Rechtsanwalts oder mehrerer Rechtsanwälte. + + waterway tunnelKanaltunnel + + αεροδρόμιοaéroportairportaeroporto空港luchthaven공항aeroportolotniskoaeropuertoFlughafen + + πυγμάχοςboxeurboxerpugileボクサーbokser권투 선수boxeador + + φτέρηfougèresfernfelceシダ植物門samambaiafarn + + παίχτης ποδοσφαίρουjoueur de footballsoccer playervoetballer축구 선수futbolista + + fashionmodemodeA type or code of dressing, according to the standards of the time or individual design.Een stijl of code voor kleding, bepaald door de voorkeursstijl van een tijdperk of door individuele ontwerpers. + + νησίîleislandeilandilhawyspaInsel + + Open SwarmΑνοικτό σμήνος + + natural placenatürlicher Ortlieu naturelnatuurgebiedThe natural place encompasses all places occurring naturally in universe.Der natürlicher Ort beinhaltet alle Orte die natürlicherweise im Universum existieren. + + soap characterχαρακτήρας σαπουνόπερας + + college coachπροπονητής κολεγίουentraîneur universitaire + + HumanGeneανθρώπινο γονίδιοヒト遺伝子 + + μυςmusclemuscle筋肉spierMuskel + + information applianceσυσκευή πληροφορικήςAn information device such as PDAs or Video game consoles, etc. + + ruisseaustreamruscello河川bacha flowing body of water with a current, confined within a bed and stream banks + + sports managerSportmanagerαθλητικός μάνατζερsportbestuurderAccording to the french label sub Soccer, trainership could be meant. However, here a Sportsmanager is interpreted as a member of the board of a sporting club.Σύμφωνα με τη γαλλική ετικέτα Soccer,μπορεί να εννοείται ο προπονητής.Παρ'όλα αυτα,εδώ ένας αθλητικός μάνατζερ μεταφράζεται ως ένα μέλος συμβουλίου ενός αθλητικού κλαμπ. + + νοσοκομείοhôpitalhospital病院ziekenhuis병원hospitalKrankenhaus + + hot spring温泉 + + αρχιμάγειροςchefchefchefkokKocha person who cooks professionally for other people + + φιλόσοφοςphilosophephilosopher哲学者filosoof철학자Philosoph + + System of lawrégime de droitrechtssysteema system of legislation, either national or international + + Βάση Δεδομένων Βιολογικών ΧαρακτηριστικώνBase de données biologiquesBiological databasedatabase biologicoバイオデータベースbiologische databankBanco de dados biológicoΔιάφορες βάσεις δεδομένων οι οποίες περιέχουν πληροφορίες που ταυτοποιούν τα βασικά βιολογικά χαρακτηριστικά των οργανισμών. Οι πληροφορίες αυτές συγκροτούνται σε σύνολα βιβλιοθηκών των βασικών δομών των κυττάρων των οργανισμών, όπως οι βιλβιοθήκες νουκλεϊνικών οξέων (genomics) και πρωτεϊνών (proteomics). + + εκκλησίαéglisechurchchiesa教会kerkigrejaiglesiaKirche + + τούνελtunneltunnelトンネルtunnelTunnelA tunnel may be for foot or vehicular road traffic, for rail traffic, or for a canal. Some tunnels are aqueducts to supply water for consumption or for hydroelectric stations or are sewers (http://en.wikipedia.org/wiki/Tunnel).Un tunnel est une galerie souterraine livrant passage à une voie de communication (chemin de fer, canal, route, chemin piétonnier). (http://fr.wikipedia.org/wiki/Tunnel).Ein Tunnel (auch Tunell) ist eine künstliche Passage, die Berge, Gewässer oder andere Hindernisse (in der Regel als Verkehrsweg) unterquert (http://de.wikipedia.org/wiki/Tunnel).Ένα τούνελ μπορεί να είναι για πεζούς ή για αυτοκινητόδρομους,για σιδηρόδρομους,ή για κανάλια στο νερό.Μερικά τούνελ είναι υδραγωγεία για να παρέχουν νερό προς κατανάλωση ή για υδροηλεκτικούς σταθμούς ή είναι υπόνομοι. + + ginkgoginkgoginkgoginkgo biloba銀杏属ginkgoginkgo + + Κοιλάδαvalléevalleyvallevalleitala depression with predominant extent in one direction + + συγγραφέαςécrivainwriter著作家auteur작가escritorschriftsteller + + αυτοκίνητοautomobileautomobileautomobile自動車avtomobilautomovelautomóvilAutomobil + + ιδεολογίαidéologieideologyideologieideologiaIdeologiefor example: Progressivism_in_the_United_States, Classical_liberalismγια παραδειγμα: Προοδευτισμός στις ΗΠΑ, κλασικός φιλελευθερισμός + + Supreme Court of the United States casecas juridique de la Cour suprême des États-Unis + + SwarmschwarmstormoΣμήνος + + Community + + canadian football teamκαναδέζικη ομάδα ποδοσφαίρουéquipe canadienne de football américainsquadra di football canadese + + ραδιοφωνικός σταθμόςstation de radioradio stationラジオ放送局radiozenderemisora de radioRadiosenderA radio station has one line up. For instance the radio station BBC Radio 1. Not to be confused with the broadcasting network BBC, which has many radio stations.Ein Radiosender hat genau ein Programm, zum Beispiel der Sender NDR Kultur. Nicht zu verwechseln mit der Rundfunkanstalt NDR, welche mehrere Radiosender hat. + + προπονητής ποδοσφαίρουentraîneur de footballsoccer managervoetbalmanagerFußballmanager + + πολιτικόςpoliticienpolitician政治家politicuspolitikpolíticoPolitiker + + κωμικόςcomédiencomedianお笑い芸人comediante + + δημιουργός κόμιξcréateur de bandes dessinéescomics creator漫画家만화가 + + μονάρχηςmonarquemonarchmonarcamonarch군주monarch + + δρόμοςrouteroad道路weg도로carretera + + Playboy Playmateplayboy playmateplaymate pour Playboy + + συσκευηappareildeviceデバイスapparaatGerät + + ηφαίστειοvolcanvolcano火山vulkaanVulkanA volcano is currently subclass of naturalplace, but it might also be considered a mountain.Το ηφαίστειο είναι υποκατηγορία φυσικών καταστάσεων, αλλά μπορεί επίσης να θεωρηθεί και βουνό. + + εφημερίδαjournalnewspaper新聞krant신문ZeitungA newspaper is a regularly scheduled publication containing news of current events, informative articles, diverse features and advertising. It usually is printed on relatively inexpensive, low-grade paper such as newsprint.Eine Zeitung ist ein Druckwerk von mäßigem Seitenumfang, das in kurzen periodischen Zeitspannen, mindestens einmal wöchentlich, öffentlich erscheint. Die Zeitung ist, anders als die Zeitschrift, ein der Aktualität verpflichtetes Presseorgan und gliedert sich meist in mehrere inhaltliche Rubriken wie Politik, Lokales, Wirtschaft, Sport, Feuilleton und Immobilien. + + παίκτης αμερικανικού ποδοσφαίρουjoueur de football américainamerican football playergiocatore di football americanoアメリカンフットボール選手American footballspeler + + ακαδημαϊκό περιοδικόjournal académiqueacademic journalgiornale accademico学術雑誌wetenschappelijk tijdschrift학술지Wissenschaftliche FachzeitschriftAn academic journal is a mostly peer-reviewed periodical in which scholarship relating to a particular academic discipline is published. Academic journals serve as forums for the introduction and presentation for scrutiny of new research, and the critique of existing research. Content typically takes the form of articles presenting original research, review articles, and book reviews.Ένα ακαδημαϊκό περιοδικό είναι ως επί το πλείστον περιοδικό για κριτικές οι οποίες σχετίζονται με έναν συγκεκριμένο ακαδημαϊκό τομέα. Τα ακαδημαϊκά περιοδικά χρησιμεύουν ως φόρουμ για την εισαγωγή και παρουσίαση του ελέγχου των νέων ερευνών και της κριτικής της υπάρχουσας έρευνας. Το περιεχόμενο έχει συνήθως την μορφή άρθρων παρουσίασης νέας έρευνας, ανασκόπησης υπάρχων άρθρων και κριτικές βιβλίων.Wissenschaftliche Fachzeitschriften sind regelmäßig verlegte Fachzeitschriften über Spezialthemen aus den verschiedensten wissenschaftlichen Disziplinen. Sie stellen neue Methoden, Techniken und aktuelle Trends aus den Wissenschaften dar. + + table tennis playerπαίκτης πινγκ-πονγκtafeltennisserAthlete who plays table tennisO αθλητής που παίζει πινγκ-πονγκ + + έργο τέχνηςœuvre d'artartworkopera d'arte作品kunstwerkobra de arteA work of art, artwork, art piece, or art object is an aesthetic item or artistic creation. + + παίχτης βόλεϊvolleyball playervolleyballer배구 선수siatkarz + + non-profit organisationorganisation à but non lucratif + + θάλασσαmerseazeeMeer + + Κλήροςecclésiastiqueclericecclesiastico聖職者geestelijkegeistlicher + + beauty queenβασίλισσα ομορφιάςreginetta di bellezzaミスA beauty pageant titleholderΤίτλος που αποδίδεται σε μία γυναίκα, τις περισσότερες φορές μετά από διαγωνισμό. + + σχολείοécolescuola学校school학교Schule + + region + + light novelライトノベルανάλαφρο μυθιστόρημαA style of Japanese novel + + Site of Special Scientific InterestΤοποθεσία Ειδικού Επιστημονικού Ενδιαφέροντοςsite d'intérêt scientifique particulier自然保護協会特別指定地区A Site of Special Scientific Interest (SSSI) is a conservation designation denoting a protected area in the United Kingdom. SSSIs are the basic building block of site-based nature conservation legislation and most other legal nature/geological conservation designations in Great Britain are based upon them, including National Nature Reserves, Ramsar Sites, Special Protection Areas, and Special Areas of Conservation. + + snooker playerSnookerspielerbiljarterAn athlete that plays snooker, which is a billard derivateEin Sportler der Snooker spielt, eine bekannte Billardvariante + + ice hockey leagueπρωτάθλημα χόκεϋligue d'hockey sur glacea group of sports teams that compete against each other in Ice Hockey. + + person functionfunctie van persoonfonction de personne + + μουσικόςmusicienmusical artistmuziekartiest음악가artista musical + + πολιτικό κόμμαparti politiquepolitical partypartido políticopartia politycznapartit políticpolitische Parteifor example: Democratic_Party_(United_States)για παράδειγμα: Δημοκρατικό Κόμμα _United_States) + + presenterΠαρουσιαστήςpresentatorTV or radio show presenter + + ΝερόμυλοςMoulin à eauWatermillmulino ad acquaWatermolenWassermühleA watermill is a structure that uses a water wheel or turbine to drive a mechanical process such as flour, lumber or textile production, or metal shaping (rolling, grinding or wire drawing) + + βάση δεδομένωνBase de donnéesDatabaseデータベースdatabaseBanco de dadosDatenbank + + εθνική ομάδαgroupe ethniqueethnic groupetnia민족ethnie + + ομάδα μπέιζμπολéquipe de basket-ballbaseball teamsquadra di baseball野球チームΈνας αριθμός από άνδρες ή γυναίκες που αποτελούν ένα διακριτό σύνολο με συγκεκριμένους στόχους σχετικά με το άθλημα του μπέιζμπολ. + + αργίαholidaygiorno festivo祝日feiertag + + έντομοinsecteinsect昆虫insect + + ορυκτόminéralmineralminerale鉱物mineraalmineralA naturally occurring solid chemical substance.Corpi naturali inorganici, in genere solidi. + + μουσικό έργοœuvre musicalemusical workopera musicalemuziekwerkmusikalisches Werk + + soccer club season + + mean of transportationmoyen de transportvervoermiddelμεταφορικό μέσο + + unit of workarbeitseinheitwerkeenheidThis class is meant to convey the notion of an amount work to be done. It is different from Activity in that it has a definite end and is being measured." + + moskmosquéemezquitaA mosque, sometimes spelt mosk, is a place of worship for followers of Islam.Une mosquée est un lieu de culte où se rassemblent les musulmans pour les prières communes. + + national collegiate athletic association athleteathlète de la national collegiate athletic association + + γονίδιοgènegene遺伝子gengeneGen + + διαιτητήςarbitrerefereearbitroscheidsrechterárbitroschiedsrichterAn official who watches a game or match closely to ensure that the rules are adhered to. + + ερπετόreptilereptile爬虫類reptielreptil + + καναδός παίκτης ποδοσφαίρουjoueur de football canadiencanadian football playergiocatore di football canadesejogador de futebol canadense + + government agencyBehördeκυβερνητική υπηρεσίαorgaan openbaar bestuurA government agency is a permanent or semi-permanent organization in the machinery of government that is responsible for the oversight and administration of specific functions, such as an intelligence agency.Eine Behörde ist eine staatliche Einrichtung, die im weitesten Sinne für die Erfüllung von Aufgaben der Verwaltung des Staates und dabei insbesondere für Dienstleistungen des Staates gegenüber seinen Bürgern zuständig ist. Eine Behörde erhält ihren Auftrag aus den Gesetzen des Staates, in dem und für den sie tätig ist.Μια κυβερνητική υπηρεσία είναι μόνιμη ή ημι-μόνιμη οργάνωση στο μηχανισμό της κυβέρνησης, η οποία είναι υπεύθυνη για την εποπτεία και διαχείριση συγκεκριμένων λειτουργιών, όπως η υπηρεσία πληροφοριών. + + σημαίαdrapeauflagbayrakvlagFlagge + + βακτήριαbactériebacteriabatterio真正細菌bacteriebacteriabakterium + + καρδινάλιοςcardinalcardinalcardinalekardinaalcardeal + + molluscamollusque軟体動物weekdier + + στάδιοstadestadiumスタジアムstadion경기장Stadion + + κρασίvinwinevinoワインwijnvinoWein + + national soccer clubmilli takım + + μουσείοmuséemuseum博物館museum박물관 + + αθλητής του καλλιτεχνικού πατινάζpatineur artistiquefigure skaterフィギュアスケート選手kunstschaatserpatinador artístico + + pornstarattore pornoacteur pornoA pornographic actor or actress or a porn star is a person who performs sex acts in film, normally characterised as a pornographic film.. + + κινούμενα σχέδιαmangamangamanga日本の漫画Manga are comics created in Japan + + κολέγιοuniversitécollege単科大学faculdade + + nascar driverpilote de la nascar + + periodical literaturePeriodikumpublication périodiquePeriodical literature (also called a periodical publication or simply a periodical) is a published work that appears in a new edition on a regular schedule. The most familiar examples are the newspaper, often published daily, or weekly; or the magazine, typically published weekly, monthly or as a quarterly. Other examples would be a newsletter, a literary journal or learned journal, or a yearbook.Unter Periodikum wird im Bibliothekswesen im Gegensatz zu Monografien ein (in der Regel) regelmäßig erscheinendes Druckwerk bezeichnet. Es handelt sich um den Fachbegriff für Heftreihen, Gazetten, Journale, Magazine, Zeitschriften und Zeitungen.Une publication périodique est un titre de presse qui paraît régulièrement. + + φλέβαveinevein静脈aderveiaVene + + φυτόplanteplantpianta植物plantpflanze + + ταινίαfilmفيلمmovie映画film영화Film + + Περιοχή Χιονοδρομίαςdomaine skiableski areaスキー場skigebied + + GuitarGuitareGuitarraDescribes the guitarDécrit la guitareDescribe la guitarra + + Kολυμβητήςnageurswimmernuotatore競泳選手zwemmernadadorSchwimmera trained athlete who participates in swimming meetsένας εκπαιδευμένος αθλητής που συμμετέχει σε συναντήσεις κολύμβησης + + πρωθυπουργόςpremier ministreprime ministereerste ministerPremierminister + + αθλητήςathlèteathleteatletaアスリートatleetAthlet + + χρώμαcouleurcolourkleurFarbeColor or colour is the visual perceptual property corresponding in humans to the categories called red, yellow, blue and others. Color derives from the spectrum of light (distribution of light energy versus wavelength) interacting in the eye with the spectral sensitivities of the light receptors. + + factoryfabbricausineA factory (previously manufactory) or manufacturing plant is an industrial site, usually consisting of buildings and machinery, or more commonly a complex having several buildings, where workers manufacture goods or operate machines processing one product into another.Une usine est un bâtiment ou un ensemble de bâtiments destinés à la production industrielle. + + œuvre écritewritten workgeschreven werkobra escritageschriebenes ErzeugnisWritten work is any text written to read it (e.g.: books, newspaper, articles)Ein geschriebenes Erzeugnis ist jede Art von Text der geschrieben wurde um ihn zu lesen (z.B. Bücher, Zeitungen, Artikel). + + snooker world championSnookerweltmeisterAn athlete that plays snooker and won the world championship at least onceEin Sportler der Snooker spielt und mindestens einmal die Weltmeisterschaft gewonnen hat + + πρεσβευτήςambassadeurambassadorambasciatore大使ambassadeurBotschafterAn ambassador is the highest ranking diplomat that represents a nation and is usually accredited to a foreign sovereign or government, or to an international organization. + + snooker world rankingSnookerweltranglisteThe official world ranking in snooker for a certain year/seasonDie offizielle Weltrangliste im Snooker eines Jahres / einer Saison + + venue + + ραδιοφωνικό πρόγραμμαradio programprogramma radiofonicoラジオ番組radioprogrammaradio programm + + royaltyroyautékraljevska oseba王室 + + Κουτί πληροφοριών συλλόγου καλαθοσφαίρισηςéquipe de basket-ballbasketball teamsquadra di pallacanestroバスケットボールチームtime de basqueteBasketballmannschaft + + Πλανήτηςplanètepláinéadplanet惑星planeetplanetPlanetaplanetaplanetaplanetaPlanet + + deputyαναπληρωτήςdéputé + + familyfamilieA group of people related by common descent, a lineage. + + year in spaceflightannée de vols spatiaux + + sanctuaireshrinesantuario神社schrein + + χωριόdesavillagevillagedorpwieśdorfa clustered human settlement or community, usually smaller a town + + public service output + + θέατροthéâtretheatre劇場schouwburgTheaterA theater or theatre (also a playhouse) is a structure where theatrical works or plays are performed or other performances such as musical concerts may be produced. + + drama + + προστατευμένη περιοχήaire protégéeprotected area保護地区beschermd gebiedThis class is not just used for protected nature, but also for protected city views and enclosed neighbourhoodsDeze klasse wordt niet alleen gebruikt voor beschermde natuur, maar ook voor beschermde stadsgezichten en hofjes + + penalty shoot-out + + κανάλιcanalcanalcanale運河kanaalkanala man-made channel for waterένα κανάλι για νερό φτιαγμένο από άνθρωπο + + E4 PeriodE4 Periode + + μουσικό είδοςgenre musicalmusic genregenere musicalegenre (muziek)género musicalmusik genre + + έτοςannéeyearjaaranoañoJahr + + παπάςprêtrepriestprete司祭priesterpriester + + congressmanAbgeordneterβουλευτήςmembre du Congrès + + Αθλήματαsportsportスポーツsport스포츠esporteDeporteSportA sport is commonly defined as an organized, competitive, and skillful physical activity. + + νεύροnerfnervezenuwNerv + + samba schoolσχολή σάμπαescola de samba + + ξενοδοχείοhôtelhotelalbergoホテルhotel호텔Hotel + + fashion designerσχεδιαστής μόδας + + βιβλιοθήκηbibliothèquelibrary図書館bibliotheek도서관BibliotecaBibliothek + + μοντέλοmannequinmodelモデル_(職業)(foto)model모델model + + σύνδεσμοςligamentbindweefselligamentoband + + Δραστηριότηταactivitéactivityattività活動activiteitatividadeactividadAktivität + + Stadtviertelcity districtquartierstadswijkDistrict, borough, area or neighbourhood in a city or town + + δισκογραφικήlabel discographiquerecord labelplatenlabelPlattenlabel + + acteur de doublagevoice actor声優stemacteur성우 + + ολυμπιακοί αγώνεςJeux Olympiquesolympics近代オリンピック올림픽Juegos Olímpicos + + καναδική ένωση ποδοσφαίρουcanadian football leaguecanadian football leaguelega di football canadeseカナディアン・フットボール・リーグA group of sports teams that compete against each other in canadian football league.ένα σύνολο αθλητικών ομάδων που ανταγωνίζονται μεταξύ τους στην Καναδική ένωση ποδοσφαίρου + + prehistorical periodperiode in de prehistorie + + φαγητόnourritureFood食品voedsel음식alimentoLebensmittelFood is any eatable or drinkable substance that is normally consumed by humans.Φαγητό είναι οποιαδήποτε φαγώσιμη ή πόσιμη ουσία που καταναλώνεται κανονικά από ανθρώπους.Lebensmittel umfasst als Oberbegriff sowohl Getränke als auch die Nahrungsmittel und Genussmittel. + + τραγούδιchansonsongcanzonelied노래lied + + παιχνίδιpièce de théâtreplay戯曲toneelstukobra de teatroTheaterstückA play is a form of literature written by a playwright, usually consisting of scripted dialogue between characters, intended for theatrical performance rather than just reading.Ένα παιχνίδι είναι μια μορφή της λογοτεχνίας, γραμμένο από έναν συγγραφέα, που συνήθως αποτελείται από σενάριο του διαλόγου μεταξύ των χαρακτήρων, που προορίζεται για την θεατρική παράσταση και όχι μόνο ανάγνωση. + + albumalbumalbumalbumアルバムalbum앨범Album + + Comedy Group + + ΓλυπτικήsculptureSculpturesculturabeeldhouwwerkSkulpturSculpture is three-dimensional artwork created by shaping or combining hard materials, typically stone such as marble, metal, glass, or wood, or plastic materials such as clay, textiles, polymers and softer metals.Γλυπτική είναι τρισδιάστατο έργο τέχνης το οποίο δημιουργήθηκε από τη διαμόρφωση ή συνδυάζοντας σκληρά υλικά, τυπικώς πέτρα όπως μάρμαρο, μέταλλο, γυαλί, ή ξύλο, ή πλαστικά υλικά όπως άργιλος, υφάσματα, πολυμερή και μαλακότερα μέταλλα.Een beeldhouwwerk is een drie-dimensionaal kunstvoorwerp of plastiek, gemaakt van harde materialen zoals steen of metaal. Ook kunnen textiel of kunststoffen erin verwerkt zijn of het hoofdbestanddeel ervan uitmaken. + + boroughTeilgemeindedeelgemeenteAn administrative body governing a territorial unity on the lowest level, administering part of a municipality + + deaneryproosdijThe intermediate level of a clerical administrative body between parish and diocese + + αεροπορική εταιρείαcompagnie aérienneairlinecompagnia aerea航空会社luchtvaartmaatschappij항공사Fluggesellschaft + + volleyball leagueΟμοσπονδία Πετοσφαίρισηςligue de volleyballA group of sports teams that compete against each other in volleyball. + + γκραν πριgrand prixGrand Prixgran premioグランプリgrosser Preis + + Πέρασμα βουνούcol de montagnemountain passbergpasa path that allows the crossing of a mountain chain. It is usually a saddle point in between two areas of higher elevation + + δημιουργίαœuvrework仕事werkobraWerk + + πύραυλοςfuséerocketロケットraket로켓Rakete + + Blazon + + architect + + πτηνόoiseaubirduccello鳥類vogelVogel + + golf playerπαίκτης γκολφgolfeurgolfspeler + + πρωτάθλημα μπόουλινγκligue de bowlingbowling leaguelega di bowlingボーリングリーグa group of sports teams or players that compete against each other in BowlingΜία διοργάνωση ομάδες ανθρώπων ή μεμονομένα άτομα συναγωνίζονται στο άθλημα του μπόουλινγκ, συνήθως με ένα έπαθλο στους πρωταθλητές. + + public service input + + Πληροφορίες Αγίουsaintsaint聖人heilige성인 + + historical periodιστορική περίοδοςhistorische periodeA historical Period should be linked to a Place by way of the property dct:spatial (already defined) + + κινούμενα σχέδιαbande dessinéecomicsfumetto漫画stripverhaalhistorieta + + squash playergiocatore di squashsquasher + + παίχτης του πόκερjoueur de pokerpoker playerpokerspelerPokerspieler + + animeάνιμεanimeアニメA style of animation originating in JapanΣτυλ κινουμένων σχεδίων με καταγωγή την Ιαπωνία + + βιβλίοlivrebooklibroboekksiążkallibreবইBuch + + γλώσσαlangagelanguage言語taal언어idiomaSprache + + εστιατόριοrestaurantrestaurantレストランrestaurant + + geological periodgeologische periode + + old territory + + collection of valuablesKunst- und Wertsachenversammlungverzameling van kostbaarhedencollection d'objetsCollection of valuables is a collection considered to be a work in itself)Een verzameling van kostbaarheden, die als een werk beschouwd wordt ). + + επισκοπήdioceseDistrict or see under the supervision of a bishop. + + Πληροφορίες παιχνιδιούjeugameゲームspeljogoSpiela structured activity, usually undertaken for enjoyment and sometimes used as an educational tool + + legislatureνομοθετικό σώμαpouvoir législatifwetgevend orgaan + + movie genreFilmgenreείδος ταινίαςfilmgenre + + ηθοποιόςacteuractorattore俳優acteur영화인atoraktoractorSchauspielerAn actor or actress is a person who acts in a dramatic production and who works in film, television, theatre, or radio in that capacity.Μια ηθοποιός ή ένας ηθοποιός είναι ένα άτομο που παίζει σε μια δραματική παραγωγή και που εργάζεται στο χώρο του κινηματογράφου, της τηλεόρασης, του θεάτρου, ή το ραδιόφωνο.Un attore o un attrice è una persona che recita in una produzione teatrale, televisiva, cinematografica o radiofonica. + + αμφίβιοamphibienamphibiananfibio両生類amfibieanfíbio + + golf leagueένωση γκολφligue de golfliga de golfeGolfplayer that compete against each other in Golf + + career stationKarrierestationthis class marks a career step in the life of a person, e.g. a soccer player, holding information on the time span, matches and goals he or she achieved at a certain club + + ουρανοξύστηςgratte-cielskyscraper超高層建築物wolkenkrabber초고층 건물Hochhaus + + ομάδαgroupegroupgruppo集団groepGruppeAn (informal) group of people.un groupe (informel) de personnes.Μια συνήθως άτυπη ομάδα ανθρώπων. + + κληρική τάξηordre religieuxclerical orderordine clericalekloosterordeEen kloosterorde is een orde van religieuzen, mannen of vrouwen, die zich verenigd hebben omtrent een gemeenschappelijke geloofsopvatting en kloosterregel waaraan zij gebonden zijn, en op een permanente wijze samenleven binnen één en dezelfde plaatselijke gemeenschap, een klooster of een tempel. Meerdere kloosters van gelijkgezinde religieuzen vormen samen een kloosterorde. + + Wind motorRoosmolenA wind-driven turbine that adapts itself to wind direction and to wind-force. Is considered to be a class in its own, despite the wind as common factor with Windmill. + + φάρμακοmédicamentdrug薬物geneesmiddelDroge + + Noteworthy part of a building (facade, chimney, etc.)Opmerkelijk onderdeel van een bouwselA smaller detail about a building with a particular interest + + τρένοtraintraintreno列車treintrenzug + + Ανεμόμυλοςmoulin à ventWindmillmulino a ventoWindmolenMolinos de vientoWindmühleA windmill is a machine that converts the energy of wind into rotational energy by means of vanes called sailsLe moulin à vent est un dispositif qui transforme l’énergie éolienne (énergie cinétique du vent) en mouvement rotatif au moyen d’ailes ajustables. + + sports leagueΑθλητική Ομοσπονδίαligue sportive스포츠 리그A group of sports teams or individual athletes that compete against each other in a specific sport. + + jeu de sociétéboard gamegioco da tavoloボードゲームbordspelcome from http://en.wikipedia.org/wiki/Category:Board_gamesUn gioco da tavolo è un gioco che richiede una ben definita superficie di gioco, che viene detta di solito tabellone o plancia. + + παίχτης του μπάντμιντονjoueur de badmintonbadminton playergiocatore di badmintonバドミントン選手badmintonspeler배드민턴 선수jogador de badminton + + νόμισμαdevisecurrencymuntsoort통화Währung + + langage de programmationprogramming languageprogrammeertaallinguagem de programaçãoProgrammiersprache + + παίκτης σκάκιchess playergiocatore di scacchischakerszachistaSchachspieler + + rugby playerπαίκτης rugbyjoueur de rugbyrugbyspeler + + παίκτης βελάκιωνdarterdarts player + + Πληροφορίες προσώπουpersonneشخصpersonpersona人_(法律)persoonOsebapessoapersonaPerson + + αρχιτέκτοναςarchitectearchitectarchitetto建築士architect건축가arquitectoArchitekt + + Globular SwarmΣφαιρωτό σμήνος + + handball leagueΟμοσπονδία Χειροσφαίρισηςligue de handballa group of sports teams that compete against each other in Handball + + dogchienHundhond + + infrastructureΥποδομήinfrastructure + + ατόληatollatollatollo環礁Atoll + + netball playergiocatore di netball + + prefecture + + διαστημική αποστολήmission spatialespace mission우주 임무misión espacial + + railway lineEisenbahnliniespoorlijnA railway line is a transport service by trains that pull passengers or freight provided by an organization. Not to be mistaken for railway track, which is the structure consisting of the rails. Wikipedia do not clearly differentiate between both, so there is one infobox describing tracks and lines.Eine Eisenbahnlinie im Verkehrswesen ist die regelmäßige Bedienung einer bestimmten Eisenbahnstrecke durch öffentliche Verkehrsmittel. + + cycling competitionδιαγωνισμός ποδηλασίαςgara ciclisticawielercompetitie + + μοναστήριmonastèremonasterykloosterKlosterMonastery denotes the building, or complex of buildings, comprising the domestic quarters and workplace(s) of monastics, whether monks or nuns, and whether living in community or alone (hermits). The monastery generally includes a place reserved for prayer which may be a chapel, church or temple, and may also serve as an oratory. (http://en.wikipedia.org/wiki/Monastry).Μονή υποδηλώνει το κτίριο ή συγκρότημα κτιρίων, που αποτελείται από τις εγχώρια τρίμηνα και στο χώρο εργασίας (ες) των μοναχών, αν οι μοναχοί ή μοναχές, και αν ζουν στην κοινότητα ή μεμονωμένα (ερημίτες). Η μονή περιλαμβάνει γενικά ένα χώρο που προορίζεται για την προσευχή που μπορεί να είναι ένα παρεκκλήσι, εκκλησία ή ναό, και μπορεί επίσης να χρησιμεύσει ως μια ρητορική. +(http://en.wikipedia.org/wiki/Monastry).Een klooster (van het Latijnse claustrum, afgesloten ruimte) is een gebouw of een samenstel van gebouwen dat dient tot huisvesting van een groep of gemeenschap van mannen of vrouwen, vaak monniken of monialen genoemd, die zich uit de wereld heeft teruggetrokken om een godsdienstig leven te leiden. (http://nl.wikipedia.org/wiki/Klooster_%28gebouw%29).Le monastère est un ensemble de bâtiments où habite une communauté religieuse de moines ou de moniales. (http://http://fr.wikipedia.org/wiki/Monast%C3%A8re). + + σιδηροδρομική σήραγγαEisenbahntunnelspoorwegtunnel + + γερουσιαστήςsénateursenatorsenatorsenadorSenator + + χημικό στοιχείοélément chimiquechemical elementelemento chimico元素chemisch element + + όνομαprénomgiven namevoornaamimięVorname + + αρτηρίαartèrearteryarteria動脈Arterie + + field hockey leagueπρωτάθλημα χόκεϊ επί χόρτουligue d'hockey sur gazona group of sports teams that compete against each other in Field Hockeyένα γκρουπ αθλητικών ομάδων που διαγωνίζονται η μια εναντίον της άλλης στο χόκεϊ επί χόρτου + + tennis tournamenttennis toernooiΤουρνουά Τένιςtorneo di tennis + + synagogsynagoguesinagogasynagogeA synagogue, sometimes spelt synagog, is a Jewish or Samaritan house of prayer.Une synagogue est un lieu de culte juif. + + σχέδιοprojetprojectプロジェクトproyectoProjektA project is a temporary endeavor undertaken to achieve defined objectives.Ein Projekt ist ein zeitlich begrenztes Unternehmen, das unternommen wird, um definierte Ziele zu erreichen. + + football league seasonαγωνιστική περίοδος πρωταθλήματος ποδοσφαίρου + + appareil photographiquecamerafotocameraカメラcameraUna fotocamera (in lingua italiana nota tradizionalmente come macchina fotografica) è uno strumento utilizzato per la ripresa fotografica e per ottenere immagini di oggetti reali stampabili su supporti materiali cartacei o archiviabili su supporti elettronici. + + δικαστήςjugejudgegiudice裁判官rechterrichter + + πλοίοnavireshipschipstatekbarcoSchiff + + βραβείοrécompenseawardpremionagradanagrodaAuszeichnung + + ουράνιο σώμαcorps celestecelestial bodycorpo celeste天体hemellichaamcuerpo celeste + + martial artistΠολεμικός Καλλιτέχνης + + hollywood cartoonκινούμενα σχέδια του Hollywood + + μουσικόςmusiquemusicalミュージカルmusical뮤지컬Musical + + beach volleyball playerπαίκτης του beach volleygiocatore di beach volleyビーチバレー選手Ένα άτομο (άνδρας ή γυναίκα) που ασχολείται με το άθλημα του μπίτς βόλλεϋ. + + national collegiate athletic association team season + + αστέριétoilestarstellaster + + inline hockey leagueπρωτάθλημα χόκεϋ inlinegroup of sports teams that compete against each other in Inline Hockey. + + Eurovision song contest entryΔιαγωνισμός τραγουδιού της Eurovisionconcours Eurovision de la chanson + + parishparoisseparochieThe smallest unit of a clerical administrative body + + ερασιτέχνης μποξέρboxeur amateuramateur boxerpugile amatorialeアマチュアボクサー + + οστόosboneossobotossoKnochenΗ βασική μονάδα του συστήματος στήριξης των σπονδυλωτών οργανισμών. + + πόληcitécitycittàstad도시cidadeStadta relatively large and permanent settlement, particularly a large urban settlement + + οικονομολόγοςéconomisteeconomisteconoomeconomistaAn economist is a professional in the social science discipline of economics.Le terme d’économiste désigne une personne experte en science économique.Un economista es un profesional de las ciencias sociales experto en economía teórica o aplicada. + + conventionσυνέδριοcongrès컨벤션 + + speedway rider + + gymnastγυμναστήςA gymnast is one who performs gymnasticsΈνας γυμναστής είναι ένας που εκτελεί γυμναστικές ασκήσεις + + εμπορικό κέντροcentre commercialshopping mallショッピングモールwinkelcentrumshopping + + δημοσιογράφοςjournalistejournalistgiornalistaジャーナリストjournalistjournalist + + sport facilityαθλητικές εγκαταστάσειςinstallation sportive + + πράκτοραςagentagentagenteエージェントagentagenteAnalogous to a foaf:Agent, an agent is an entity that acts. This is intended to be the super class of Person and Organisation.Ανάλογα με την κλάση foaf:Agent, ένας πράκτορας είναι μια οντότητα που ενεργεί. Αυτό προορίζεται να είναι μια υπερκλάση της κλάσης Άτόμο και Οργανισμός. + + ΜύλοςMoulinMillmulinoMolenMühlea unit operation designed to break a solid material into smaller pieces + + Έργο ΖωγραφικήςpeinturePainting絵画schilderijobrazGemäldeDescribes a painting to assign picture entries in wikipedia to artists. + + olympic resultαποτελέσματα Ολυμπιακών αγώνωνrésultat de Jeux Olympiquesresultados de Juegos Olímpicos + + Sports team memberμέλος αθλητικής ομάδαςA member of an athletic team.Μέλος αθλητικής ομάδας. + + Στρατιωτική Μονάδαunité militairemilitary unit군대unidade militarunidad militar + + public service + + animanga characterχαρακτήρας ανιμάνγκαpersonaggio animangaキャラクターAnime/Manga characterΧαρακτήρας από Άνιμε/Μάνγκα + + soccer tournomentτουρνουά ποδοσφαίρουcampeonato de futebolfutbol turnuvası + + ασθένειαmaladiedisease病気ziekte질병Krankheit + + σταφύλιraisingrapeuvaブドウdruifWeintraube + + ύδαταétendue d'eaubody of waterdistesa d'acqua水域Cuerpo de aguaΣυγκεντρωμένες, συνήθως μεγάλες ποσότητες νερού (π.χ. ωκεανοί) που βρίσκονται στη Γη ή σε οποιονδήποτε άλλο πλανήτη. Ο όρος χρησιμοποιείται και για υδάτινους σχηματισμούς όπου υπάρχει κίνηση του νερού, όπως ποταμοί, ρεύματα ή κανάλια. + + race trackπίστα αγώνωνcircuit de course + + ιστορικό κτίριοbâtiment historiquehistoric building歴史的建造物historisch gebouw + + μνημείοmonumentmonumentmonumentDenkmalA type of structure (a statue or an art object) created to commemorate a person or important event, not necessarily of a catastrophic nature. + + καλλιτέχνηςartisteartistartista芸術家kunstenaar예술가Künstler + + horse trainerεκπαιδευτής αλόγων調教師 + + ImdbImdbImdbImdb + + geopolitical organisationγεωπολιτική οργάνωσηorganisation géopolitique + + MouseGeneγονίδιο ποντικιούマウス遺伝子 + + ομάδα αμερικανικού ποδοσφαίρουéquipe américaine de football américainamerican football teamsquadra di football americanoアメリカン・フットボール・チーム + + Gaelic games playerΓαελικός παίκτης παιχνιδιώνjoueur de sports gaéliques + + νουβέλαromannovelnovella小説romanA book of long narrative in literary proseΈνα βιβλίο με μεγάλη αφήγηση σε λογοτεχνική πρόζαLe roman est un genre littéraire, caractérisé pour l'essentiel par une narration fictionnelle plus ou moins longue. + + skaterpattinatore + + μπικουτίcurlingspelercurler + + governmental administrative regionrégion administrative d'étatgebied onder overheidsbestuurAn administrative body governing some territorial unity, in this case a governmental administrative body + + eukaryoteευκαρυωτικόeucaryote真核生物 + + professorprofesseurProfessorprofessor + + vice presidentαντιπρόεδροςVizepräsidentvice président + + πρωτάθλημα μπέιζμπολligue de baseballbaseball leaguelega di baseball野球リーグa group of sports teams that compete against each other in Baseball.ένα σύνολο από ομάδες μπέιζμπολ οι οποίες συναγωνίζονται μεταξύ τους. + + εκπαιδευτικό ίδρυμαétablissement d'enseignementeducational institutiononderwijsinstellingBildungseinrichtung + + διαστημικός σταθμόςstation spatialespace stationruimtestation우주 정거장estación espacialRaumstation + + αστερισμόςconstellationcostellazionetakımyıldızısamenstelUna costellazione è ognuna delle 88 parti in cui la sfera celeste è convenzionalmente suddivisa allo scopo di mappare le stelle. + + σκιέρskieurskiersciatoreスキーヤーskiërskifahrer + + paintball leagueκύπελλο paintballligue de paintballa group of sports teams that compete against each other in Paintballένα γκρουπ αθλητικών ομάδων που ανταγωνίζονται στο paintball + + club mossΜούσκλιαlycopodiopsidaヒカゲノカズラ綱 + + lacrosse leagueπρωτάθλημα χόκεϋ σε χόρτοligue de crossea group of sports teams that compete against each other in Lacrosse. + + olympic eventολυμπικακό γεγονός + + δισκογραφία καλλιτέχνηdiscographie de l'artisteartist discographydiscografia dell'artistaディスコグラフィ + + abbayeabbeyabbaziaabdijabadíaAn abbey is a Catholic monastery or convent, under the authority of an Abbot or an Abbess, who serves as the spiritual father or mother of the community.Une abbaye est un monastère ou un couvent catholique placé sous la direction d'un abbé, lequel sert de père spirituel à la communauté religieuseUn'abbazia (detta anche abazia o badia a seconda se diretta da un abate o una badessa), è un particolare tipo di monastero, che per il diritto canonico è un ente autonomo. + + formula one racingφόρμουλα ένας αγώναςFormule 1-coureur‎ + + Sportereignissports eventevento esportivoévènement sportifa event of competitive physical activity + + sculptorsculpteurbeeldhouwer + + πάπαςpapepope教皇paus교황papieżPapst + + χημική ένωσηproduit chimiquechemical compoundcomposto chimico化合物composto químico + + bièrebeerbirraビールbiercervezaBier + + period of artistic stylestijlperiode + + overseas department + + Intercommunality + + Μνημείο Παγκόσμιας Πολιτιστικής Κληρονομιάς (Πληροφορίες ΠΠΚ)site du patrimoine mondialWorld Heritage Site世界遺産세계유산A UNESCO World Heritage Site is a site (such as a forest, mountain, lake, desert, monument, building, complex, or city) that is on the list that is maintained by the international World Heritage Programme administered by the UNESCO World Heritage Committee, composed of 21 state parties which are elected by their General Assembly for a four-year term. A World Heritage Site is a place of either cultural or physical significance. + + comic + + aμερικανικό πρωτάθλημα ποδοσφαίρουamerican football leagueamerican football leaguelega di football americanoアメリカン・フットボール・リーグAmerikaanse voetbal competitieliga de futebol americanoA group of sports teams that compete against each other in american football.Ένα σύνολο αθλητικών ομάδων που ανταγωνίζονται μεταξύ τους στο αμερικάνικο ποδόσφαιρο. + + sports teamsportteamομαδικά αθλήματαéquipe sportive + + αυστραλιανό πρωτάθλημα ποδοσφαίρουaustralian football leagueaustralian football leaguelega di football australianoオーストラリアン・フットボール・リーグliga de futebol australianoA group of sports teams that compete against each other in australian football.Μια ομάδα αθλητικών ομάδων που ανταγωνίζονται μεταξύ τους σε αυστραλιανό ποδόσφαιρο. + + δίκτυο ραδιοφωνικής μετάδοσηςchaîne de télévision généralistebroadcast networkemittenteネットワーク_(放送)omroeporganisatieSendergruppeΈνα δίκτυο μετάδοσης είναι μια οργάνωση, όπως μια εταιρεία ή άλλη ένωση, που παρέχει ζωντανό ή μαγνητοσκοπημένο περιεχόμενο, όπως ταινίες, δελτία ειδήσεων, αθλητικά, και τα προγράμματα δημοσίων υποθέσεων για την εκπομπή πάνω από μια ομάδα ραδιοφωνικών ή τηλεοπτικών σταθμών + + Hokejska ekipahockey teamομάδα χόκεϊéquipe de hockey + + δολοφόνοςassassinmurdererassasinomoordenaarMörder + + διακόσμησηdécorationdecorationonorificenzaonderscheidingcondecoraciónAn object, such as a medal or an order, that is awarded to honor the recipient ostentatiously.Per onorificenza si intende un segno di onore che viene concesso da un'autorità in riconoscimento di particolari atti benemeriti.Une distinction honorifique en reconnaissance d'un service civil ou militaire . + + wrestling eventmatch de catchworstelevenement + + municipalitycommuneGemeindegemeenteAn administrative body governing a territorial unity on the lower level, administering one or a few more settlements + + γέφυραpontbridgepontebrug다리mostponteসেতুBrücke + + districtkecamatanbagian wilayah administratif dibawah kabupaten + + ΒουνόmontagnemountainbergmontanhaBerg + + track listlijst van nummersA list of music tracks, like on a CDEen lijst van nummers als op een CD album + + σπηλιάgrottecavegrotta洞窟grotHöhle + + επιστήμοναςscientifiquescientist科学者wetenschapper과학자বিজ্ঞানীWissenschaftler + + Ιστότοποςsite webwebsiteウェブサイト웹사이트Webseite + + lymphlympheリンパλέμφος + + ερευνητικό έργοprojet de rechercheresearch projectonderzoeksprojectproyecto de investigaciónForschungsprojektA research project is a scientific investigation, usually using scientific methods, to achieve defined objectives.Ένα ερευνητικό έργο είναι μια επιστημονική έρευνα, συνήθως με τη χρήση επιστημονικών μεθόδων, για την επίτευξη των καθορισμένων στόχων. + + Locality + + ζώοanimalanimalanimale動物dier동물živalTier + + ήπειροςcontinentcontinentcontinente大陸대륙KontinentUn continente è una grande area di terra emersa della crosta terrestre, è anzi la più vasta delle ripartizioni con le quali si suddividono le terre emerse. + + παλαίστραarenastadioアリーナstadionarenastadion + + soccer league seasonπερίοδος κυπέλλου ποδοσφαίρουfutbol ligi sezonu + + εγκληματίαςcriminelcriminaldelinquentecrimineel범죄인criminosoVerbrecher + + επώνυμοnom de famillesurnameachternaamnazwiskoNachname + + θηλαστικό ζώοmammifèremammalmammifero哺乳類zoogdiermamíferosäugetier + + εκλογήélectionElectionverkiezingWahl + + πρωτάθλημα πυγμαχίαςligue de boxeboxing leaguelega di pugilatoボクシングリーグA group of sports teams or fighters that compete against each other in BoxingΜία διοργάνωση στην οποία μεμονωμένοι πυγμάχοι είτε ομάδες πυγμάχων συναγωνίζονται μεταξύ τους με σκοπό την νίκη. + + district water boardwaterschapConservancy, governmental agency dedicated to surface water management + + radio-controlled racing leagueligue de courses radio-télécommandéA group of sports teams or person that compete against each other in radio-controlled racing. + + μύκηταςfungifungus菌類schimmel + + αεροσκάφοςavionaircraftaereo航空機vliegtuig비행기Flugzeug + + λίσταlistelist一覧lijstA general list of items.une liste d'éléments.Een geordende verzameling objecten.Μια γενική λίστα από αντικείμενα. + + statestaat + + πλασματικός χαρακτήραςpersonnage de fictionfictional characterキャラクターpersonage (fictie) + + βρύοmoussesmossmuschio蘚類Laubmoss + + tennis leagueΟμοσπονδία Αντισφαίρισηςligue de tennisA group of sports teams or person that compete against each other in tennis. + + Biomoleculeβιομόριοbiomolecola生体物質equivalent to http://ccdb.ucsd.edu/NIF/BIRNLex-OBO-UBO.owl#birnlex_22.Κάθε μόριο που παράγεται σε έναν ζωντανό οργανισμό. Συνήθως μεγαλομοριακές ενώσεις που χρησιμεύουν στην δομή και στο μεταβολισμό του κυττάρου. Πρωτεΐνες, νουκλεϊνικά οξέα, υδατάνθρακες και λιπίδια. + + ΣταθμόςstationстанцияstationstationestaçãoPublic transport station (eg. railway station, metro station, bus station).Остановка общественного транспорта (например: железнодорожная станция, станция метро, автостанция). + + ποτάμιrivièreriverrivierFlussa large natural stream + + οργάνωσηorganisationorganisation組織organisatie조직organizacijaorganizaçãoOrganisation + + χαρακτήρας κινούμενων σχεδίωνpersonnage de bandes dessinéescomics characterコミックスのキャラクター만화애니 등장인물personagem de quadrinhos + + Listenακούω + + templetempletempiotempeltempel + + fromagecheeseformaggiokaasKäseA milk product prepared for human consumption + + περιοχήlekualieuمكانplace立地plaatslugarlugarOrtImmobile things or locations.uma localização + + embryologyεμβρυολογίαembryologie + + άγνωστοςInconnuUnknownBilinmeyen無知Onbekend + + εκδότηςéditeurpublisher出版社uitgeverPublishing company + + multi volume publicationmeerdelige publicatie + + route of transportationTransportweg + + sports team seasonπερίοδος αθλητικής ομάδαςA season for a particular sports team (as opposed to the season for the entire league that the team is in)μία περίοδος για μία αθλητική ομάδα + + ResumeCVA Resume describes a persons work experience and skill set.Een CV (curriculum vitae) beschrijft iemands werkervaring en vaardigheden. + + green algaalgue verte緑藻 + + ski resort + + genregenreGenreύφος + + χημική ουσίαsubstance chimiquechemical substancesostanza chimica化学物質substância química + + iran municipality + + memorialμνημείοgedenktekenDenkmalA monument erected to commemorate an event and/or group + + παίκτης μπέιζμπολjoueur de baseballbaseball playergiocatore di baseball野球選手honkballer야구 선수jogador de basebolΟ αθλητής (άνδρας ή γυναίκα) που συμμετέχει σε μία ομάδα μπέιζμπολ. + + medicianmedico + + road tunnelΟδική σήραγγαStraßentunnel + + natural region + + national football league season + + καλλιεργούμενη ποικιλίαcultivar (cultivated variety)A cultivar is a plant or grouping of plants selected for desirable characteristics that can be maintained by propagation. A plant whose origin or selection is primarily due to intentional human activity. + + κάστροchâteaucastlecastellokasteelburgCastles often are, but need not be a military structure. They can serve for status, pleasure and hunt as well. + + vice prime ministerαντιπρωθυπουργόςvice premier ministre + + Μουσικό Όργανοinstrument de musiqueInstrumentstrumento musicalemuziekinstrument악기GlasbiloInstrumentomusikinstrumentDescribes all musical instrument + + δήμαρχοςmairemayor首長burgemeesterBürgermeister + + είδοςespècespecies種_(分類学)soortespeciesSpezie + + τηλεοπτικός σταθμόςchaînes de télévisiontelevision stationcanale televisivoテレビジョン放送局canal de televisiónFernsehsenderA television station has usually one line up. For instance the television station WABC-TV (or ABC 7, Channel 7). Not to be confused with the broadcasting network ABC, which has many television stations.Ένας τηλεοπτικός σταθμός έχει μια παράταξη.Για παράδειγμα ο τηλεοπτικός σταθμός WABC-TV (or ABC 7, Channel 7).Δεν πρέπει να συγχέεται με το τηλεοπτικό δίκτυο ABC,που έχει πολλούς τηλεοπτικούς σταθμούς.Ein Fernsehsender hat normalerweise ein Programm, zum Beispiel der Sender Erstes Deutsches Fernsehen (Das Erste). Nicht zu verwechseln mit der Rundfunkanstalt ARD, welche mehrere Fernsehsender hat. + + αγώναςcourseraceレースRennen + + populated placebewohnter Ortlieu habitébebouwde omgeving + + ποδηλάτηςcyclistecyclistwielrennerciclistaciclista + + rugby leagueπρωτάθλημα rugbyligue de rugbyA group of sports teams that compete against each other in rugby. + + soccer clubομάδα ποδοσφαίρουclub de football + + αστεροειδήςastéroïdeasteroidasteroide小惑星asteróideasteroide + + όπλοarmeweapon武器wapen무기Waffe + + PolyhedronPolyederpoliedroπολύεδρο + + λίμνηlaclake호수meer호수See + + υπολοχαγόςlieutenantlieutenantluitenanttenente + + host + + διασημότηταcélébritécelebritycelebritàberoemdheid + + γράμμαlettreletter文字letterA letter from the alphabet.une lettre de l'alphabet. + + topical conceptthematisches Konzept + + nobleευγενής + + Φάροςpharelighthouse灯台vuurtorenLeuchtturm + + Μέλος κοινοβουλίουmembre du Parlementmember of parliamentparlementslidmembro do parlamentoParlamentsmitglied + + wine regionrégion viticoleワイン産地wijnstreek + + deitygottheitgodheid + + σιδηροδρομικός σταθμόςgaretrain stationstazione ferroviaria鉄道駅treinstation + + Πληροφορίες Επισκόπουévêque chrétienChristian Bishopvescovo cristianoChristelijk bisschopbiskup chrześcijański + + polo leagueΟμοσπονδία Υδατοσφαίρισηςligue de poloA group of sports teams that compete against each other in Polo. + + πρωτάθλημα αγώνων αυτοκινήτωνla ligue de course automobileauto racing leaguelega automobilistica自動車競技リーグa group of sports teams or individual athletes that compete against each other in auto racingμια ομάδα αθλητικών ομάδων ή μεμονωμένων αθλητών που ανταγωνίζονται μεταξύ τους σε αγώνες αυτοκινήτων + + historic placeιστορικός χώροςsite historique + + Βρετανική μοναρχίαroyauté BritanniqueBritish royaltyreali britanniciイギリス王室Britanska kraljevska oseba + + television host + + manhuamanhuaComics originally produced in ChinaΚόμικς που παράγονται αρχικά στην Κίνα + + Château d'eauWater towerSerbatoio idrico a torreWatertorenWasserturma construction designed to store larger quantities of water at a place of some elevation in order to keep pressure on the water provision systemune construction destinée à entreposer l'eau, et placée en général sur un sommet géographique pour permettre de la distribuer sous pression + + king of Polandkról Polskikoning van Polen + + κτίριοbâtimentbuildingedificio建築部gebouwstavbaedificioGebäude + + αστροναύτηςastronauteastronautastronauta宇宙飛行士ruimtevaarder우주인astronautaastronautaAstronaut + + mixed martial arts leagueligue d'arts martiaux mixtesa group of sports teams that compete against each other in Mixed Martial Arts + + διοικητική περιφέρειαrégion administrativeadministrative regionregione amministrativa行政区画bestuurlijk gebiedA PopulatedPlace under the jurisdiction of an administrative body. This body may administer either a whole region or one or more adjacent Settlements (town administration) + + bodybuilderculturistabodybuilder + + singlesinglesingleシングル싱글In music, a single or record single is a type of release, typically a recording of fewer tracks than an LP or a CD. + + softball leagueligue de softballA group of sports teams that compete against each other in softball. + + casinocasinòcasinoIn modern English, a casino is a facility which houses and accommodates certain types of gambling activities.Un casino est un lieu proposant des jeux d'argent et de hasard ou jeux de casino. + + race horseιπποδρομία + + σατυρικό σκίτσοdessin animécartooncartone animatoカートゥーン + + διαστημόπλοιοvaisseau spatialspacecraftruimtevaartuig우주선 + + radio hostοικοδεσπότης ραδιοφώνου + + mixed martial arts eventévènement d'arts martiaux mixtes + + βιντεοπαιχνίδιjeux vidéovideo gameテレビゲーム비디오 게임video game / jogovideojuegoVideospielA video game is an electronic game that involves interaction with a user interface to generate visual feedback on a video device. + + governorκυβερνήτηςgouverneur知事 + + Κουτί πληροφοριών ένωσηςtrade unionvakbondsyndicat professionnelA trade union or labor union is an organization of workers who have banded together to achieve common goals such as better working conditions. + + κάτοχος δημόσιου αξιώματοςtitulaireoffice holderambtsdrager공직자Amtsinhaber + + military structureΣτρατιωτική ΔομήA military structure such as a Castle, Fortress, Wall, Naval base etc. + + cricket leagueκύπελλο κρικετligue de cricketa group of sports teams that compete against each other in Cricket + + rugby clubclub de rugby + + mountain rangechaîne de montagneΟροσειράbergketena chain of mountains bordered by highlands or separated from other mountains by passes or valleys. + + Australian rules football playerαυστραλιανοί κανόνες ποδοσφαιριστήオージーフットボール選手giocatore di football australiano + + παίκτης καλαθοσφαίρισηςjoueur de basketballbasketball playergiocatore di pallacanestroバスケットボール選手농구 선수BasquetbolistaΈνας αθλητής (άνδρας ή γυναίκα) που ασχολείται με το άθλημα της καλαθοσφαίρισης. + + καγκελάριοςchancelierchancellorcancellierekanselierchancelerKanzler + + Legal Caseνομική υπόθεσηcas juridiquecaso jurídico + + αστρακόδερμοcrustacéscrustacean甲殻類schaaldier + + εκφωνητήςbroadcasteremittente放送事業者RundfunkveranstalterΟ ραδιοτηλεοπτικός φορέας είναι ένας οργανισμός που είναι υπεύθυνος για την παραγωγή ραδιοφωνικών ή τηλεοπτικών προγραμμάτων και / ή τη διαβίβασή τους + + cycadφοινικόθαμνοςcycadophytesソテツ門 + + political party of leaderpolitische Partei des VorsitzendenThe Political party of leader. + + distance laps + + speakernumber of office holder + + ons + + city typetype stadτύπος + + shuttle + + ranking + + long distance piste number + + year of electrificationJahr der ElektrifizierungYear station was electrified, if not previously at date of opening. + + last seasonΠροηγούμενη Περίοδος + + minimum temperature (K)ελάχιστη θερμοκρασία (K) + + illustratorillustratorillustrateurIllustrator (where used throughout and a major feature) + + Parents Wedding DateHochzeitstag der Elterndata do casamento dos pais + + fastest driver + + date actαπόφαση_διάνοιξης + + external ornament + + minority of a settlement + + reference + + massif + + British Comedy AwardsΒρετανικά Βραβεία Κωμωδίας + + first launch rocket + + source confluence country + + launch + + other serving linesandere verbindingenandere VerbindungenConnecting services that serve the station such as bus, etc. + + largest metro + + first ownerpremier propriétaireprimer dueño + + speciessoort種_(分類学) + + management region + + bicycle informationFahrradinformationenInformation on station's bicycle facilities. + + grid referencecoördinaten + + wins at Senior Euro + + historical region + + number of staffαριθμός προσωπικούaantal medewerkers + + original nameoorspronkelijke naamThe original name of the entity, e.g. film, settlement, etc. + + senatorsenador + + former call sign + + missionαποστολή + + cca state + + surface gravity (g) + + attorney generalprocureur-generaalPublic attorneyde procureur-generaal + + gnis code + + maiden flight rocket + + geographic coordinates + + scottish name + + race trackcircuit + + load limit (g)Belastungsgrenze (g)Load limit of the bridge. + + school code + + number of bombsαριθμός των βομβών + + TheologyΘεολογία + + jurisdictionZuständigkeitJurisdiction is the practical authority granted to a formally constituted legal body or to a political leader to deal with and make pronouncements on legal matters and, by implication, to administer justice within a defined area of responsibility.Die Zuständigkeit oder Kompetenz legt im öffentlichen Recht fest, welche Behörde bzw. welches Gericht im Einzelfall rechtlich zu hoheitlichem Handeln ermächtigt und verpflichtet ist. + + number of locationsnombre de sites + + service end date + + digital sub channel + + first air dateSendebeginnThe date on which regular broadcasts began. + + maximum boat length (μ)μέγιστο_μήκος_πλοίου (μ) + + guestεπισκέπτης + + numbernummerαριθμός + + mass (g)μάζα (g) + + broadcast repeaterεπαναληπτική αναμετάδοση + + participantdeelnemerTeilnehmer + + torch bearer + + formatformaatformatformat + + mother + + second commander + + number of districtsjumlah kecamatan + + localization of the island + + spokespersonporta-voz + + royal anthem + + subject of playThe overall subject matter dealt with by the play. + + observatory + + historical name + + target airport + + duration (s)duur (s)The duration of the item (movie, audio recording, event, etc.) in ISO 8601 date format + + sport countrySportnationThe country, for which the athlete is participating in championshipsDas Land, für das der Sportler an Wettkämpfen teilnimmt + + aircraft patrolπεριπολία αεροσκάφους + + music fusion genre + + networkδίκτυο + + ICD9ICD9 + + bronze medalistmedalha de bronzeχάλκινο μετάλλιο + + waist size (μ)Taillenumfang (μ)ウエスト (μ) + + code bookwetboekcode book or statute book referred to in this legal case + + υπότιτλοςsubtitleonderschriftlegendaUntertitel + + Dorlands suffix + + σχολείοécoleschoolscuolaschoolschuleschool a person goes or went toσχολείο στο οποίο πηγαίνει ή πήγε κάποιος + + child organisationdochterorganisatie + + βάρος (g)poids (g)weight (g)体重 (g)gewicht (g)peso (g)Gewicht (g) + + membershiplidmaatschap + + last launch date + + flag Link + + monarchmonarch + + FAA Location Identifier + + area quote + + parentouderparent + + less populous countrypaís menos populoso + + active years end yearενεργά χρόνια τέλος του χρόνουactieve jaren eind jaar + + bioclimate + + is handicapped accessibleist rollstuhlgerechtTrue if the station is handicapped accessible. + + Alps subgroupυποομάδα των άλπεωνsottogruppo alpinothe Alps subgroup to which the mountain belongs, according to the SOIUSA classification + + constructionKonstruktion + + notable workoeuvre majeure代表作bekende werken + + supplemental draft year + + spur of + + volcanic activity + + administrative collectivityadministratieve gemeenschapδιοικητική συλλογικότητα + + chief editorhoofdredacteur + + collectivity minority of a settlement + + vein + + relativeσυγγενήςVerwandter親戚 + + failed launches + + power type + + release daterelease datumημερομηνία κυκλοφορίαςdata wydania + + military unit sizethe size of the military unit + + συγγραφέαςauteurauthorauteurautor + + fate + + organisation + + IOBDB IDLortel Archives Internet Off-Broadway database "show id" from lortel.org. + + memorial ID numbercode gedenktekenIdentifier for monuments of the Memorial typeCode oorlogsmonument of ander gedenkteken + + museumTypesoort museumThis property has been added because 'buildingType' is much more about the place, whereas 'museumType' is about the way the place is being (or:was) usedNieuw type is nodig omdat Museum eigenlijk geen subklasse van Building is, maar meer te maken heeft met de functie van het gebouw. 'Museumtype' is dan ook meer thema- en collectiegerelateerd + + US sales + + subdivisions + + has junction withσύνδεση + + order in office + + word before the country + + opponents"opponent in a military conflict, an organisation, country, or group of countries. " + + seriesreeksσειρά + + arabic name of a lebanon settlement + + list itemlijst itemsαντικείμενο λίστας + + spacewalk end + + mentormentorA wise and trusted counselor or teacherCelui qui sert de guide, de conseiller à quelqu’un. + + approximate calories (J)κατά προσέγγιση θερμίδες (J)Approximate calories per serving.Kατά προσέγγιση θερμίδες ανά μερίδα. + + number built + + opening dateημερομηνία ανοίγματοςdate d'ouvertureEröffnungsdatum + + date useέναρξη_χρήσης + + πόληvillecitystadStadt + + rural municipality + + review + + circulationoplageκυκλοφορία + + total population referencereferencia do total da populacao + + venerated invereerd in + + production + + Human Development Index (HDI)Índice de Desenvolvimento Humano (IDH)a composite statistic used to rank countries by level of "human development" + + Beschleunigung (s)acceleration (s)επιτάχυνση (s) + + συνολικός_πληθυσμόςpopulation totalepopulation totalinwonersaantalpopulação totalEinwohnerzahl + + number of platform levelsNumber of levels of platforms at the station. + + media typemediatypePrint / On-line (then binding types etc. if relevant) + + Gemini Award + + former broadcast networkehemalige Sendergruppeancienne chaîne de télévision généralisteA former parent broadcast network to which the broadcaster once belonged.Eine ehemalige Sendergruppe zu dem der Rundfunkveranstalter gehört hat. + + Gray subjectRefers to the famous 1918 edition of Gray's Anatomy. + + plantφυτό植物 + + sister station + + yearsseizoen + + number of stationsAnzahl der StationenNumber of stations or stops. + + MeSH IDMeSH ID + + Link from a Wikipage to a Wikipage in a different language about the same or a related subject.Reserved for DBpedia. + + mandate of a prefect of a romanian settlement + + έκταση (m2)superficie (m2)area (m2)oppervlakte (m2)área (m2)Fläche (m2)The area of a owl:Thing in square metre. + + type of tennis surfacetype de surface (tennis)tipo de surperficie(tennistype speelgrondThere are five types of court surface used in professional play. Each surface is different in the speed and height of the bounce of the ball. + + international phone prefix + + name + + human development index rank + + share of audienceAnteil der Zuschauer/Zuhörer + + wine region + + broadcast station classαναμετάδοση ραδιοφωνικού σταθμού + + honoursδιακρίσειςeerbewijzen + + founded bygegründet vongesticht doorIdentifys the founder of the described entity. This can be a person or a organisation for instance. + + kindOfLanguage + + first mention + + census yearέτος απογραφήςZensusjahr + + identification symbol + + opening yearopeningsjaarEröffnungsjahr + + main island + + millsCodeNLWindmotorenmillsCodeNLWindmotoren + + depiction description (caption)This property can be used to map image captions from Infoboxes + + number of seats in the land parlement + + iso code of a community + + election date leaderWahldatum des VorsitzendenThe date that leader was elected. + + population metro + + causalties + + designerσχεδιαστής + + minority floor leadernumber of office holder + + conservation status保全状況 + + current record + + project keywordA key word of the project. + + lowest place + + analog channelαναλογικό κανάλι + + κόμμα_αρχηγούleader partyregeringspartijpartido do liderRegierungspartei + + number of houses present)aantal huizen aanwezigCount of the houses in the Protected AreaAantal huizen in afgegrensd gebied + + apparent magnitudescheinbare Helligkeitφαινόμενο μέγεθος + + single rankings + + city luxembourgish name + + trainer club + + literary genreliterair genreliterarische GattungA literary genre is a category of literary composition. Genres may be determined by literary technique, tone, content, or even (as in the case of fiction) length. + + lymph + + complexioncor da pele + + information name + + mouth region + + start career + + size_vμέγεθος + + population density (/sqkm)bevolkingsdichtheid (/sqkm)Bevölkerungsdichte (/sqkm)πυκνότητα_πληθυσμού (/sqkm) + + channelκανάλιkanaal + + OCLCOnline Computer Library Center number + + first driver country + + infant mortalitymortalidade infantil + + parking informationParkplatzinformationenInformation on station's parking facilities. + + siler medalistmedalha de prata + + block alloyκράμα μετάλλου + + general council + + home stadium + + GeneReviewsName + + lower age + + caused bycasus + + sixth form students + + sourceQuelleπηγή + + assets ($)περιουσιακά στοιχεία ($)Assets and liabilities are part of a companis balance sheet. In financial accounting, assets are economic resources. Anything tangible or intangible that is capable of being owned or controlled to produce value and that is held to have positive economic value is considered an asset.Περιουσιακά στοιχεία και υποχρεώσεις αποτελούν μέρος του ισολογισμού μιας εταιρείας.Σε χρηματοοικονομική λογιστική,τα περιουσιακά στοιχεία είναι οι οικονομικοί πόροι. Οτιδήποτε ενσώματο ή άυλο, που είναι ικανό να ανήκει ή να ελέγχεται για να παράγει αξία και που κατέχεται για να έχει θετική οικονομική αξία θεωρείται ένα περιουσιακό στοιχείο. + + type of electrificationArt der ElektrifizierungElectrification system (e.g. Third rail, Overhead catenary). + + service numberThe service number held by the individual during military service. + + fourth commander + + project objectiveProjektzielA defined objective of the project. + + architectural styleαρχιτεκτονικό στυλbouwstijlstyle architectural + + protestant percentage + + dissolution dateontbindingsdatum + + original start pointπρωταρχική_αρχή + + target space station station + + polespôle + + FounderΙδρυτής + + hair colorHaarfarbecor do cabelo + + region link + + ending theme + + number of restaurantsαριθμός εστιατορίων + + emblem + + available smart cardbenutzbare Chipkarteδιαθέσιμη έξυπνη κάρταSmartcard for fare payment system for public transit systems that are or will be available at the station.Chipkarte für automatische Bezahlsysteme im Personenverkehr die an diesem Bahnhof benutzt werden kann.Έξυπνη κάρτα για το σύστημα πληρωμής των ναύλων για τα δημόσια συστήματα μεταφορών που είναι ή θα είναι διαθέσιμα στο σταθμό. + + vice principal + + feature + + colour hex codeFarben Hex CodeA colour represented by its hex code (e.g.: #FF0000 or #40E0D0). + + prefecture + + είδοςgenregenreジャンルgenre + + source confluencelugar de nacimientoπηγές + + wheelbase (μ) + + formation dateformatie datumΙδρύθηκε + + course (μ) + + year of creationjaar van creatie + + norwegian landskap + + notable studentσημαντικοί_φοιτητές + + mouth elevation (μ)ύψος_εκβολών (μ) + + πρόεδροςpresidentpresidentpresidentePräsident + + story editor + + code land registrykadastercodeLand Registry code designating a parcel of landKadastercode voor een perceel + + former choreographer + + related functionssoortgelijke functiesThis property is to accommodate the list field that contains a list of related personFunctions a person holds or has heldDeze property is voor de lijst van persoonfuncties die een persoon (bv. een politicus) bekleedt of heeft bekleed + + pcc secretary + + model start date + + MeSH name + + coaching record + + daylight saving time zone + + dam + + subsequent infrastructurevolgende infrastructuur + + photographer + + commissioner date + + programme formatThe programming format describes the overall content broadcast on a radio or television station. + + UN/LOCODEUN/LOCODE, the United Nations Code for Trade and Transport Locations, is a geographic coding scheme developed and maintained by United Nations Economic Commission for Europe (UNECE), a unit of the United Nations. UN/LOCODE assigns codes to locations used in trade and transport with functions such as seaports, rail and road terminals, airports, post offices and border crossing points. + + volume quote + + Different usage of an airportοι χρήσεις ενός αεροδρομίου + + starringmet in de hoofdrolηθοποιοί + + NRHP Reference Number + + century breaksCentury Breaksnumber of breaks with 100 points and moreAnzahl Breaks mit 100 Punkten oder mehr, wird nicht übersetzt + + subsidiarytreinador + + influenceda influencéεπηρέασε + + picture formatBildformat + + showspectacle + + playsslaghand + + area land (m2)oppervlakte land (m2)έκταση_στεριάς_περιοχής (m2) + + most wins + + city sicilian name + + main interest + + portfolio + + musiciansμουσικοί + + diploma + + number of speakersaantal sprekersAnzahl Sprecher + + τοποθεσίαemplacementlocationlocatielocalizaçãoStandort + + explorerkaşif + + blazon + + snow park number + + dist_ly + + number of stars + + setup time (s) + + vice leader partypartido do vicelider + + parliament + + league championşampiyon + + throwing side + + last launch + + hip size (μ)Hüftumfang (μ)ヒップ (μ) + + authority title of a romanian settlement + + collectionσυλλογή + + water percentage of a place + + last raceτελευταίος αγώνας + + serving temperatureServing temperature for the food (e.g.: hot, cold, warm or room temperature). + + original languageoorspronkelijke taalOriginalspracheThe original language of the work. + + port1 docked time (s) + + recommissioning date + + unicode + + makeup artisttruccatorethe person who is responsible for the actors makeup + + pole driver team + + visitors per yearbezoekers per jaarBesucher pro Jahr + + branch toυποκατάστημα + + ofs code of a settlement + + brain info numberαριθμός νοητικής πληροφόρησης + + Alps sectionτμήμα των άλπεωνsezione alpinathe Alps section to which the mountain belongs, according to the SOIUSA classification + + relationσχέσηrelatie + + city since + + Laurence Olivier Award + + cargo gas (g) + + CMP EVA duration (s) + + cargo water (g) + + function end date + + foundation place + + end dateeinddatumdate de finfecha de finThe end date of the event. + + marchmarcha + + used in warwars that were typical for the usage of a weapon + + wins at JLPGA + + ICAO Location IdentifierΙΚΑΟ + + last publication dateDate of the last publication. + + automobile modelμοντέλο αυτοκινήτου + + distributing label + + number of participating nations + + car number + + champion in singlekampioen enkelspelchampion en simpleCampeón en simplewinner of a competition in the single session, to distinguish from the double session (as in tennis) + + lowestχαμηλότερο + + aircraft userχρήστης αεροσκάφουςusuario del avión + + number of lanesAnzahl der Fahrstreifennombre de voies + + animator + + ιδεολογίαideologyideologieideologiaIdeologie + + epochmoment in time used as a referrence point for some time-vaying astronomical quantity + + most populous countrypaís mais populoso + + virtual channelεικονικό κανάλι + + aircraft bomberβομβαρδιστικό αεροσκάφος + + election majoritynumber of votes the office holder attained + + national ranking + + NNDB id + + chair label + + order date + + tu + + voice typestemtypevoice type of a singer or an actor + + varietals + + former partner + + locus supplementary data + + end pointσημείο_τέλους + + field + + region + + fastest lap + + enshrined deity祭神 + + related mean of transportation + + pole driver + + land percentage of a place + + lowest region + + sheading + + modelmodèle + + originally used foroorspronkelijk gebruikOriginal use of the architectural structure, if it is currently being used as anything other than its original purpose. + + Wikipage redirectReserved for DBpedia. + + last flight start date + + aircraft interceptorαναχαίτιση αεροσκάφους + + borderσύνορα + + bed countaantal beddenAnzahl Bettenαριθμός κρεβατιών + + service module + + speed limit (kmh)Tempolimit (kmh) + + restore dateημερομηνία ανακαίνισης + + unesco + + batting side + + vastest lake + + team nameόνομα ομάδας + + red ski piste number + + classesτάξεις + + σεναριογράφοςwriterscrittoreschrijverschriftsteller + + mean radius (μ)μέση ακτίνα (μ) + + country top level (tld)domínio de topo (tld)domaine de premier niveau (tld) + + size logo + + number of doctoral students + + best ranking finishbeste Platzierung im Ranglistenturnier + + statestaatνομός + + anthemvolksliedύμνοςhino + + nation + + ICAO codeICAO designation for airline companies + + doctoral advisorδιδακτορικός_σύμβουλος + + third driver country + + building end dateΗμερομηνία λήξης κατασκευής + + number of postgraduate students + + impact factorImpact FactorThe impact factor, often abbreviated IF, is a measure reflecting the average number of citations to articles published in science and social science journals.Der Impact Factor oder genauer Journal Impact Factor (JIF) einer Fachzeitschrift soll messen, wie oft andere Zeitschriften einen Artikel aus ihr in Relation zur Gesamtzahl der dort veröffentlichten Artikel zitieren. Je höher der Impact Factor, desto angesehener ist eine Fachzeitschrift. + + licenseeIdentify which company or entity holds the licence (mostly string are used in Wikipedia, therefore range is xsd:sting). + + discontinued + + χάρτηςcartemapkaartmapaLandkarteA map of the place.Χάρτης μιας περιοχής.Eine Landkarte des Ortes. + + belgium political majority + + major islandmaior ilha + + green long distance piste number + + champion in double femalechampion en double femmesCampeón en doble mujereswinner of a competition in the female double session (as in tennis) + + undrafted year + + region servedwerkgebied + + monument code (municipal)monumentcode gemeentelijke monumentenWe should be able to distinguish status types since different codes refer to different protection regimes.We moeten soorten codes kunnen onderscheiden al naar gelang het een rijks-, provinciaal of gemeentelijk monument, of een MIP-code, betreft + + previous eventvorige evenementevento anterior + + capital country + + athleticsαθλητισμός + + racesαγώνας + + administrative status + + affiliationιστολόγιοEuropees lidmaatschap + + national years + + picture description + + ascentανάβαση + + securitySIcherheitSafety precautions that are used in the buildingSicherheitsmaßnahmen, die für das Gebäude getroffen wurden + + winter temperature (K) + + opening theme + + diocesebisdomA religious administrative body above the parish level + + vice chancellorVizekanzler + + wins at NWIDE + + principal engineerπρώτος_μηχανικός + + roleρόλοςrôle + + damsire + + docked time (s) + + element aboveэлемент снизуhoger elementelement placed above to current element in table of D.I.MendeleevЭлемент снизу под текущим элементом в таблице Д.И.Менделеева + + building start yearbouw start jaarέτος έναρξης κατασκευής + + similarπαρόμοιοςpodobny + + size of a thumbnail + + population year + + owning organisationοργανισμός + + capital region + + agency station codestationscodeStationsabkürzungκωδικός πρακτορείουAgency station code (used on tickets/reservations, etc.).Κωδικός πρακτορείου (χρησιμοποιείται σε εισιτήρια/κρατήσεις,κτλ.). + + different + + port2second docking port of a spacecraft + + Dewey Decimal ClassificationThe Dewey Decimal Classification is a proprietary system of library classification developed by Melvil Dewey in 1876. + + can baggage checkedGepäckkontrolle möglichWhether bags can be checked. + + discipleélèveA person who learns from another, especially one who then teaches others..Celui qui apprend d’un maître quelque science ou quelque art libéral. + + beatified datezalig verklaard datum + + area rank + + third teamτρίτη ομάδα + + internationally + + Olivier Award + + Alps groupομάδα των άλπεωνgruppo alpinothe Alps group to which the mountain belongs, according to the SOIUSA classification + + eventevento + + vehicles per dayFahrzeuge pro Tag + + tenanthuurderενοικιαστήςlocataire + + regime + + Tony Award + + historical map + + sea + + current member + + lunar orbit time (s) + + language regulator or academytaal instituut + + gross domestic product (GDP) ($) + + blazon link + + project coordinatorThe coordinating organisation of the project. + + first publication dateeerste publicatiedatumDatum der Erstausgabedata pierwszego wydaniaDate of the first publication.Datum der ersten Veröffentlichung des Periodikums. + + length of a coast + + kabyle settlement name + + population urban + + production end date + + original end pointπρωταρχικό_σημείο_τέλους + + first flight start date + + kind of coordinate + + military branchThe service branch (Army, Navy, etc.) a person is part of. + + significant building + + using country + + LCCNThe Library of Congress Control Number or LCCN is a serially based system of numbering cataloging records in the Library of Congress in the United States. It has nothing to do with the contents of any book, and should not be confused with Library of Congress Classification. + + stylestilstileestilo + + number of gold medals wonnomber de médailles d'or gagnéescantidad de medallas de oro ganadas + + running mate + + CO2 emission (g/km) + + port1 undocking date + + closedgesloten + + ist + + colonial name + + wha draft year + + BlazonCaption + + route junctionWegabzweigungA junction or cross to another route.Eine Abzweigung oder Kreuzung zu einem anderen Verkehrsweg. + + provost + + Number Of MunicipalitiesAantal gemeentennumero de municipios + + project + + total tracksthe total number of tracks contained in the album + + conservation status system + + number of participating male athletesnombre d'athlètes masculins participant + + vehicleόχημαVehikelvehicle that uses a specific automobile platformόχημα που χρησιμοποιεί μια συγκεκριμένη πλατφόρμα αυτοκινήτων + + philosophicalSchool + + backgroundφόντο + + norwegian center + + formation yearformatie jaar + + demolition yearsloop jaarThe year the building was demolished. + + SeitenverhältnisAspect Ratioλόγος + + zdbIdentifier for serial titles. More precise than issn + + percentage of alcoholalcoholpercentagepercentage of alcohol present in a beverage + + purchasing power parity rank + + red long distance piste number + + government mountain + + subregion + + unitary authority + + birth namegeboortenaamGeburtsnameόνομα_γέννησης + + Cesar Award + + follows + + term periodχρονική περίοδος + + descriptionπεριγραφήBeschreibungomschrijvingShort description of a person + + mouth place + + reporting markA reporting mark is a two-, three-, or four-letter alphabetic code used to identify owners or lessees of rolling stock and other equipment used on the North American railroad network. + + leader namenaam leiderprésidentόνομα_αρχηγού + + share date + + title + + mill dissapeared code NLverdwenen molen code NL + + tag + + subdivision link + + music composerkomponistcomponistμουσική + + number of lawyersAnzahl RechtsanwälteNumber of lawyers or attorneys in the company. + + prospect team + + criteriacritério + + home townHeimatort + + season numberThe season number to which the TelevisionEpisode belongs. + + scale + + capture date + + width quote + + administrative districtprovincieδήμος + + national affiliationafiliacao nacional + + geologyγεωλογίαgéologie + + maximum temperature (K)μέγιστη θερμοκρασία (K) + + promotedyükselenler + + names + + final flightdate of final flight + + active year + + other winsSonstige Siege + + subprefecture + + uses + + scots name + + tattooτατουάζTätowierungtatuagem + + Gründerfounding personstichterΙδρυτής + + launches + + fansgroup + + warsπολέμους + + successoropvolgerNachfolger後任者 + + number of seasons + + neighbour constellations + + right tributaryδεξιοί_παραπόταμοι + + prefix + + country with first spaceflight + + region typeregio-type + + specialist + + date foundation of a populated place + + delivery dateleverdatum + + purchasing power parity year + + championships + + distance to Cardiff (μ)απόσταση από το Cardiff (μ) + + number of playersαριθμός παιχτώνnombre de joueursnumero de jugadores + + leagueLigaπρωτάθλημα + + okato code + + touristic site + + frazioni + + monument code (national)monumentcode rijksmonumentenCode is too general. We should be able to distinguish status types since different codes refer to different protection regimesCode is te algemeen. We moeten soorten codes kunnen onderscheiden al naar gelang het een rijks-, provinciaal of gemeentelijk monument betreft + + crew + + bandμπάντα + + blue long distance piste number + + total discsthe total number of discs contained in the album + + head + + sharing out area + + mission duration (s) + + model end year + + command structure + + wing area (m2) + + linked space + + citizenshipburgerschapStaatsangehörigkeitυπηκοότητα + + route start locationOrt des WeganfangsThe start location of the route.Der Startort des Verkehrswegs. + + olympic oath sworn by athlete + + depth quote + + wins at japan + + EC numberEC番号 + + μέγεθος εικόνας (px1)taille de l'image (px)image size (px)イメージサイズ (px2)tamaño de la imagen (px)the image size expressed in pixels + + jockey + + Link from a Wikipage to an external pageReserved for DBpedia. + + next mission + + compilerFor compilation albums: the person or entity responsible for selecting the album's track listing. + + domaindomeinドメイン_(分類学) + + kind of rock + + IATA codeIATA designation for airline companies + + number of classroomsαριθμός αιθουσών + + a sideεξώφυλλο + + major lakemaior lago + + spouseechtgenoot配偶者the person they are married to + + track numberνούμερο τραγουδιού + + sharing out name of a settlement + + disbanded + + crew size + + LCCThe Library of Congress Classification (LCC) is a system of library classification developed by the Library of Congress. + + battleveldslagSchlacht + + number of linesAnzahl der LinienNumber of lines in the transit system. + + right ascension + + body discoveredανακάλυψη σώματος遺体発見 + + elevator countAufzüge + + agency + + fuel system + + launch vehicle + + aircraft attackεπίθεση αεροσκάφους + + institutioninstitutie + + clubclubομάδα + + service end year + + prime ministerminister-presidentPremierminister + + albedoalbedoreflection coefficientσυντελεστής ανάκλασης + + retirement datepensioendatum + + ISO 3166-1 codedefines codes for the names of countries, dependent territories, and special areas of geographical interest + + previous entity + + featuresχαρακτηριστικόkenmerk + + fuel type + + old name + + painterζωγράφος + + number of graduate students + + military unitFor persons who are not notable as commanding officers, the unit (company, battalion, regiment, etc.) in which they served. + + commander + + city dutch name + + youth clubjeugdclub + + flooding date + + musical artist + + per capita income ($)renda per capita ($) + + annual temperature (K)ετήσια θερμοκρασία (K)jaartemperatuur (K) + + residenceverblijfplaatsκατοικία + + principal area + + elevation quote + + maximum ELO rating + + measurementsmedidas + + sister college + + first game + + building start dateΗμερομηνία έναρξης κατασκευής + + assemblyσυνέλευση + + resultαποτέλεσμα + + length of a frontier + + deanπρύτανηςdecaan + + original maximum boat beam (μ) + + phone prefix label of a settlement + + old province + + DrugBankDrugBank + + other language of a settlement + + Radius_ly + + number of visitorsαριθμός επισκεπτώνbezoekersaantal + + displacement (g)A ship's displacement is its mass at any given time. + + designation of runway + + mouth countryχώρες_λεκάνης + + orbital period (s)Περίοδος περιφοράς (s) + + FCFC + + wingspan (μ) + + English name + + Alps major sectorσημαντικότερος τομέας των άλπεωνgrande settore alpinothe Alps major sector to which the mountain belongs, according to the SOIUSA classification + + law country + + number of officials + + call signindicativo de chamadaA call sign is not the name of a broadcaster! In broadcasting and radio communications, a call sign (also known as a call name or call letters, or abbreviated as a call) is a unique designation for a transmitting station.Indicativo de chamada (também chamado de call-sign, call letters ou simplesmente call) é uma designação única de uma estação de transmissão de rádio. Também é conhecido, de forma errônea, como prefixo. + + service start year + + international phone prefix label + + approved rating of the Entertainment Software Self-Regulation Body in Germany + + last flight end date + + left child + + manager club + + aircraft electronicηλεκτρονικό αεροσκάφος + + number of neighbourhood + + overall record + + bird + + rebuilder + + resting place + + geologic period + + largest city + + secondLeadervice-voorzitter + + hairs + + flower + + production start date + + rankPlatzierung + + number of countiesnúmero de condados + + band memberbandlidμέλος μπάνταςA member of the band.Ένα μέλος της μπάντας. + + port2 undocking date + + common nameThe common name of an entity. Frequently, foaf:name is used for all of the different names of a person; this property just defines the most commonly used name. + + merger date + + influenced byinfluencé parεπιρροέςbeïnvloed door + + wins in EuropeSiege in Europa + + fare zoneTarifzoneThe fare zone in which station is located.Die Tarifzone zu der die Station gehört. + + municipality codegemeente-code + + arteryαρτηρίαader + + suppredded dateoppressie datum + + railway rolling stockOperierende Schienenfahrzeuge + + code istat + + extinction year + + Staatsformgovernment typestaatsvormtipo de governobroadly, the type of structure of its government + + date of abandonment + + most steadyen istikrarlı + + launch date + + country with first astronaut + + feast dayfeestdag + + function start date + + previous editorπρώην συντάκτης + + hra state + + government elevation (μ) + + visitors totalεπιβατική κίνηση + + country origin + + current seasonΤρέχον Περίοδος + + other channel + + is part of routeName of another route from which the route is part of. Infobox property values are mostly given as plain text, therefore range is xsd:string. + + beltway city + + management mountain + + vice principal label + + number of islandsαριθμός νησιώνaantal eilanden + + reference for geographic data + + has abstractέχει περίληψηReserved for DBpedia.Προορίζεται για την DBpedia. + + floor area (m2)vloeroppervlak (m2)περιοχή ορόφων (m2) + + service start date + + apskritis + + nobel laureates + + demonymτοπονύμιο_πληθυσμούdémonymenaam bevolkingsgroep + + commandant + + map caption + + first launch + + merged into partyAufgegangen in Partei + + maximum inclination + + lyricsστίχοιparolier歌詞 + + maximum discharge (m³/s) + + allegianceυποταγήThe country or other power the person served. Multiple countries may be indicated together with the corresponding dates. This field should not be used to indicate a particular service branch, which is better indicated by the branch field. + + term of office + + ISO region codeISO regiocode + + county seatprovincie zetel + + number of vineyards + + rotation period (s) + + active years end dateενεργή ημερομηνία λήξης χρόνουactieve jaren einddatum + + career prize money ($)prijzengeld loopbaan ($) + + number of items in collectionaantal titels/itemsIndication as to the size of the collection of this libraryAanduiding van omvang van de collectie van deze bibliotheek + + poorest countrypaís mais pobre + + sign name of a hungarian settlement + + referent bourgmestre + + unlc code + + musical keyμουσικό κλειδίtoonsoort + + διακρίσειςrécompenseaward受賞onderscheidingAuszeichnung + + ethnic groupethnieetnia + + production companyproductiebedrijfthe company that produced the work e.g. Film, MusicalWork, Software + + movie + + airdateημερομηνία αέρα + + current team memberA current member of an athletic team. + + wins at LET + + Crewπλήρωμαcrew + + rector + + active years start yearενεργός χρόνος έτος λειτουργίαςactieve jaren start jaar + + officeυπηρεσίαBüro + + thumbnail localization + + number of suites + + drains from + + temperature (K)θερμοκρασία (K)température (K) + + information + + number of newly introduced sportsnumbre de sports nouvellement ajoutésnumero de deportes nuevamente añadidos + + government country + + original titleoorspronkelijke titelThe original title of the work, most of the time in the original language as well + + mute character in playName of a mute character in play. + + FilmPolski.pl id + + campus type + + developerontwikkelaarEntwicklerdéveloppeur + + blue ski piste number + + gene location start遺伝子座のスタート座標the start of the gene coordinates + + capital coordinates + + CAS supplemental + + canonized dateheiligverklaring datum + + licence letter of a german settlement + + wins at pro tournaments + + city allemmanic name + + canonized byheilig verklaard door + + provides + + highest state + + latest release version + + MedlinePlusMedlinePlus + + lowest position + + aircraft trainer + + riverποτάμιrivière + + gagaouze + + ESPN id + + notable wine + + retiredσυνταξιούχος + + administratorδιαχειριστής + + location citylocatie stadvilleCity the thing is located. + + Number Of Capital Deputiesnumero de deputados distritais + + area of catchment quote + + premiere yearYear the play was first performed. + + employer雇用者θέσεις_εργασίας + + main building本殿 + + bowl recordρεκόρ μπόουλινγκ + + ύψος (μ)hauteur (μ)height (μ)身長 (μ)hoogte (μ)višina (μ)altura (μ)Höhe (μ) + + flag border + + president of the general council + + ingredientZutatAn ingredient is a substance that forms part of a mixture (in a general sense). Here it is used in the context of recipes that specify which ingredients are used to prepare a specific dish or drink. + + aircraft helicopter cargoφορτίο ελικοφόρου αεροσκάφους + + spacecraftδιαστημόπλοιοvéhicule spatial + + refseq mRNArefseq mRNA + + απόσταση από την πρωτεύουσα (μ)distance to capital (μ)distanza alla capitale (μ)distância até a capital (μ)entfernung zur hauptstadt (μ) + + original maximum boat length (μ) + + previous mission + + management position + + governing bodybestuursorgaanVerwaltungsgremiumBody that owns/operates the Place. + + Polish Film AwardPolska Nagroda Filmowa (Orzeł) + + MeSH number + + entourage + + key person + + declination + + Lieutenancy area + + forcesforces + + voice + + government region + + authority mandate + + connotationA meaning of a word or phrase that is suggested or implied, as opposed to a denotation, or literal meaning. + + rulingrelevante regelgevingRuling referred to in this legal case + + contract award + + budget year + + red coordinate in the RGB space + + legal arrondissement + + hall of fame + + language codekod językowy + + eurobabe index ideurobabeindex idcódigo no eurobabeindex + + mill code BEmolen code BEmills code from the Belgian database on millsunieke code voor molens in database www.molenechos.org + + endowment ($) + + total cargo (g) + + tv.com id + + green ski piste number + + youth wingala jovem + + statistic value + + current world championchampion du monde actuelactual Campeón del mundohuidig wereldkampioen + + watershed (m2)waterscheiding (m2)cuenca hidrográfica (m2)λεκάνη_απορροής (m2) + + career stationKarrierestationcarrièrestapthis property links to a step in the career of a person, e.g. a soccer player, holding information on the time span, matches and goals he or she achieved at a club. + + government position + + credit + + συνθέτηςcompositeurcomposercomponistKomponist + + opening film + + trainingπροπόνηση + + date of christeningdoopdatum + + innervates + + number of silver medals wonnomber de médailles d'argent gagnéescantidad de medallas de plata ganadas + + draftEntwurf + + closing seasonkapanış sezonu + + builderbouwerοικοδόμος + + top speed (kmh)Höchstgeschwindigkeit (kmh) + + assistant principalκύριος βοηθός + + number of territoriesnúmero de territórios + + previous workvorig werkπροηγούμενη δημιουργία + + έτοςannéeyearannojaarañoJahr + + start year of insertion + + procedureprocedureThe name designating a formal collection of steps to be taken to complete the caseDe naam die verwijst naar de formele definitie van een verzameling stappen die in de juiste volgorde leiden tot de afronding van de zaak + + portrayer + + human development index (HDI) categorycategoria do indice de desenvolvimento humano (IDH) + + regencykabupaten + + main islands + + periapsis (μ) + + european union entrance datedata de entrada na uniao europeia + + price money ($)Preisgeld ($) + + moldavian name + + industryindustrie + + distance to Douglas (μ)απόσταση από το Douglas (μ) + + Penalties Team A + + diploma + + flora + + signature + + judgerechterleading judge + + pole driver country + + coronation datekroningsdatum + + COSPAR id + + visitors per dayBesucher pro Tag + + alternative titlealternatieve titelThe alternative title attributed to a work + + legend thumbnail localization + + mandate of the president of the general council + + gross ($)ακαθάριστα ($) + + broadcast translatorαναμετάδοση μεταφραστή + + Date Last Updated + + associateσυνεργάτης + + DfEDfE number of a school in England or Wales + + bigest city + + surface of runway + + έτος γέννησηςbirth year生年geboortejaarGeburtsjahr + + council of a liechtenstein settlement + + debut team + + head label + + continent rankRang KontinentPlace of the building in the list of the highest buildings in the continentDer Platz des Gebäudes in der Liste der höchsten Gebäude des Kontinents + + musical band + + politic government departmentministerio do politico + + HGNCidHGNCid + + mouth mountain + + linked to + + highest regionhoogste regio + + length quote + + tuition ($) + + number of pagesaantal pagina'sAnzahl der SeitenThe books number of pages. + + zip codepostcode + + individualised PND numberPersonennamendateiPND (Personennamendatei) data about a person. PND is published by the German National Library. For each person there is a record with her/his name, birth and occupation connected with a unique identifier, the PND number. + + opening seasonaçılış sezonu + + notable featuresnotlar + + military government + + iso code of a province + + discharge (m³/s)εκροή (m³/s)uitstoot (m³/s) + + iso code of a region + + spoken ingesproken in + + suborbital flights + + variant or variationvariantvariant or variation of something, for example the variant of a car + + networth ($) + + state of origin + + number of orbits + + ημερομηνία_θανάτουdate de décèsdeath date没年月日sterfdatumSterbedatum + + aircraft recon + + province link + + bar pass rateποσοστό επιτυχίας + + associate editorσυνεργαζόμενος συντάκτης + + managing editor + + number of undergraduate students + + strengthδύναμη + + circuit name + + rank of an agreement + + official school colouroffizielle SchulfarbeThe official colour of the EducationalInstitution represented by the colour name (e.g.: red or green). + + current partner + + official name of a switzerland settlement + + χώραpayscountrylandpaíspaísLand + + subprefecture + + fastest driver country + + executive headteacher + + KFZ-Kennzeichenvehicle codevoertuig codeRegion related vehicle code on the vehicle plates. + + twin citytweeling stad + + age rangeεύρος ηλικίας + + relation time + + dubberthe person who dubs another person e.g. an actor or a fictional character in movies + + faunafauna + + FC runs + + person functionpersoon functie + + fuel capacity (μ³) + + τόπος_θανάτουlieu de décèsdeath place死没地plaats van overlijdenSterbeortthe place where they died + + laying down + + Number Of State Deputiesnumero de deputados estaduais + + Location Identifier + + nearest citydichtstbijzijnde stadπόλη + + summer temperature (K) + + mouth positionlugar de desembocadura + + automobile platformπλατφόρμα αυτοκινήτων + + καύσιμαcarburantfuelbrandstofTreibstoff + + leaderleiderηγέτηςlider + + number of rocket stagesnumber of stages, not including boosters + + testaverage + + aircraft helicopter transportμεταφορές που πραγματοποιούνται με ελικοφόρο αεροσκάφος + + sovereignn country + + discovererΑνακαλύφθηκε από + + magazineπεριοδικό + + first flight + + teaching staff + + supplemental draft round + + beatified byzalig verklaard door + + date of acquirementημερομηνία απόκτησης + + monument code for the Monuments Inventory Projectmonumentcode voor het Monumenten Inventarisatie ProjectThe Dutch MIP project was meant to take stock of all kinds of monumentsCode voor alle soorten monumenten gebezigd door het MI-project + + gini coefficientcoeficiente de Giniis a measure of the inequality of a distribution. It is commonly used as a measure of inequality of income or wealth. + + spacewalk begin + + first driver + + command + + cinematographycinematografie + + local authority + + geolocDepartment + + oil system + + partnerpartnerσυνέταιροςPartner + + National Topographic System map number + + freeLabel + + percentage of area waterποσοστό_υδάτωνpercentage wateroppervlak + + Golden Raspberry Award + + source confluence state + + total population + + latest preview version + + National Olympic Committee + + number of licensednombre de licenciésnombre de personnes ayant une license pour pratiquer cette activité + + SAT scoremost recent average SAT scores + + fips code + + port2 docked time (s) + + seasonσαιζόν + + magenta coordinate in the CMYK space + + head alloy + + tamazight settlement name + + Computing Media + + capital district + + + + congressional district + + distance traveled (μ)afgelegde afstand (μ) + + wins at challenges + + total travellers + + podiums + + seating capacityzitplaatsen + + distance to London (μ)απόσταση από το Λονδίνο (μ) + + creatormaker + + ageηλικία + + amgId + + number of vehiclesAnzahl der FahrzeugeNumber of vehicles used in the transit system. + + ημερομηνία ίδρυσηςfounding date創立日data założeniaGründungsdatum + + effectiveRadiatedPower (W) + + owning company + + achievementκατόρθωμαhaut fait, accomplissementlogro + + group commemoratedgroep mensen herdachtDesignates the category of people commemorated by a monumentAanduiding van de categorie mensen die door dit monument worden herdacht + + buildinggebouwκτίριο + + ATC supplementalATC συμπληρωματικό + + service + + 門_(分類学) + + brandμάρκα + + comic + + political mandate + + latest release datedate de dernière version + + crews + + total mass (g) + + government place + + notify date + + cuisinekeukenκουζίναcuisine + + demographics as ofindicadores demograficos em + + coached team + + editor titleτίτλος συντάκτη + + βασίλειοkingdomregno界_(分類学)rijkreich + + committee + + unit cost ($) + + ATC suffixATC κατάληξηsuffix ATC + + leaderFunction + + management elevation (μ) + + bust size (μ)Μέγεθος προτομής (μ)バスト (μ) + + city italian name + + sharing out + + work + + musicTypesoort muziekwerkType is too general. We should be able to distinguish types of music from types of architectureType is te algemeen. We moeten soorten muziek van soorten gebouwen kunnen onderscheiden + + phone prefix name + + Link from a Wikipage to another WikipageReserved for DBpedia. + + average class sizeμέσο μέγεθος τάξης + + affair + + passengers per yearpassagiers per jaarPassagiere pro JahrNumber of passengers per year. + + set designerscenografothe person who is responsible for the film set design + + road end directionHimmelsrichtung des WegendesEnd of the route. The opposite of OntologyProperty:routeStartDirection.Himmelsrichtung des Endes des Verkehrsweges. Der Gegensatz zur OntologyProperty:routeStartDirection. + + average depth + + lounge + + Alps SOIUSA codeκώδικας SOIUSA των άλπεωνcodice SOIUSAthe Alps SOIUSA code corresponding to the mountain, according to the SOIUSA classification + + yellow coordinate in the CMYK space + + volumesdelen + + monument code (provinciall)monumentcode provinciale monumentenCode is too general. We should be able to distinguish status types since different codes refer to different protection regimesCode is te algemeen. We moeten soorten codes kunnen onderscheiden al naar gelang het een rijks-, provinciaal of gemeentelijk monument betreft + + branch ofδιακλάδωση_του + + synonymσυνώνυμοシノニム + + piercingpiercing + + handednesshabilidade com a maoan attribute of humans defined by their unequal distribution of fine motor skill between the left and right hands. + + dry cargo (g)droge last (g) + + divisionverdeling + + visitor percentage changeprozentuale Veränderung der BesucherzahlPercentage increase or decrease. + + past member + + IFTA Award + + associated musical artistσυνεργάτης-μουσικός καλλιτέχνης + + army + + relegated teamsdüşenler + + port2 docking date + + smallest countrymenor país + + Gaudí AwardPremis GaudíAwards of the Catalan Academy of Cinema + + meeting building + + last appearance + + number of laps + + patronpatrono + + race length (μ) + + continentcontinentelinks a country to the continent it belongs + + geolocdual + + ζώοanimalanimal動物beestTier + + date budget + + area of a land (m2) + + start year + + race horse + + highest position + + flagSize + + current rankaktueller Ranglistenplatz + + armώμος + + type of municipalitytype gemeente + + this seasonbu sezon + + austrian land tag + + neighbour region + + individualised GND numberGemeinsame NormdateiGND (Gemeinsame Normdatei) is an international authority file for the organisation of personal names, subject headings and corporate bodies from catalogues. It is used mainly for documentation in libraries and archives. The GND is managed by the German National Library in cooperation with various library networks. The GND falls under the Creative Commons Zero(CC0) license. + + sexφύλοGeschlecht + + legal formrechtsvormRechtsformThere are many types of business entity defined in the legal systems of various countries. These include corporations, cooperatives, partnerships, sole traders, limited liability company and other specialized types of organization.Die Rechtsform definiert die juristischen Rahmenbedingungen einer Organisation bzw. Unternehmens. + + ISO 639-1 codeISO 639-1 codekod ISO 639-1 + + per capital income rank + + secretarysecretarissecretario + + satellite + + quote + + purposedoelobjectif + + lieutenantlieutenant + + mayor article + + lowest state + + access dateημερομηνία πρόσβασης + + head teacher + + pluviometry + + end year of sales + + frequency of publicationfrequentie van publicatieErscheinungsweiseThe frequency of periodical publication (eg. Weekly, Bimonthly).Die Häufigkeit der Erscheinungen des Periodikums (z.B. wöchentlich, monatlich). + + toll ($)Maut ($) + + source position + + thumbnailReserved for DBpedia. + + meeting city + + production start yearproductie beginjaar + + pronunciation + + GeneReviewsID + + unknown outcomesnumber of launches with unknown outcomes (or in progress) + + number of islands + + aircraft helicopter utility + + number of tracksAnzahl der GleiseNumber of tracks of a railway or railway station. + + ταχυδρομικός κώδικαςcode postalpostal codepostcodecódigo postalPostleitzahlA postal code (known in various countries as a post code, postcode, or ZIP code) is a series of letters and/or digits appended to a postal address for the purpose of sorting mail. + + reservationsAre reservations required for the establishment or event? + + codecode + + slogansloganSlogan + + museumμουσείοmuseum博物館 + + Emmy Award + + inflowεισροή + + second teamδεύτερη ομάδα + + buried placebegraafplaatsτόπος θαψίματοςThe place where the person has been buried.Ο τόπος όπου το πρόσωπο έχει θαφτεί.De plaats waar een persoon is begraven. + + maiden flightdate of maiden flight + + CODENCODEN is a six character, alphanumeric bibliographic code, that provides concise, unique and unambiguous identification of the titles of serials and non-serial publications from all subject areas. + + ΕπαρχίαcontaecountyprovinciehrabstwoBezirk + + start pointσημείο_αρχής + + end year + + first olympic eventpremière épreuve olympique + + INSEE codeINSEE-codenumerical indexing code used by the French National Institute for Statistics and Economic Studies (INSEE) to identify various entities + + champion in single femalechampion en simple femmesCampeón en simple mujereswinner of a competition in the single female session, to distinguish from the double session (as in tennis) + + last air dateSendeschlussThe date on which the broadcaster made its last broadcast. + + location countryΧώραpaís de localizaçãoCountry the thing is located. + + creator of dishThe person that creates (invents) the food (eg. Caesar Cardini is the creator of the Caesar salad). + + significant project + + licenselicentieάδειαlicence + + aircraft helicopter observationπαρατήρηση ελικοφόρου αεροσκάφους + + requirement + + delegation + + type of municipalitytype gemeente + + παιδίطفلchild子供kindKind + + is peer reviewedIn academia peer review is often used to determine an academic papers suitability for publication. + + city arberisht name + + net income ($) + + companyorganisatieεταιρεία会社 + + volcanic type + + intercommunality + + route directionHimmelsrichtung des VerkehrswegesThe general direction of the route (eg. North-South).Himmelsrichtung des Verkehrsweges (z.B. North-South). + + third commander + + architectual bureauαρχιτεκτονική κατασκευή + + wine year + + alma materσπουδέςschools that they attended + + vice leadervicelider + + delegate mayor + + shoe numberschoenmaatnúmero do sapato + + water + + life expectancyexpectativa de vida + + draft team + + film colour typespecifies the colour type of the film i.e. 'colour' or 'b/w' + + pseudonympseudoniemPseudonym + + departmentafdelingdépartementeskualdea + + is part ofist ein Teil von + + operated bybetrieben vonOrganisation or city who is the operator of the ArchitecturalStructure. Not to confuse with maintainer or the owner. + + old district + + clusterbirlik + + salary ($)μισθός ($)Gehalt ($)給料 ($) + + address in roadAdresse in Straßeδιεύθυνση στον δρόμοA building, organisation or other thing that is located in the road.Ένα κτήριο, οργανισμός ή κάτι άλλο που βρίσκεται στον δρόμο. + + access dateημερομηνία ανάβασης + + rebuild dateherbouw datum + + rocketfuséeρουκέτα + + reference for general data + + lunar rover + + Bioavailability"The rate and extent to which the active ingredient or active moiety is absorbed from a drug product and becomes available at the site of action. For drug products that are not intended to be absorbed into the bloodstream, bioavailability may be assessed by measurements intended to reflect the rate and extent to which the active ingredient or active moiety becomes available at the site of action (21CFR320.1)." + + home arena + + death yearjaar van overlijdenSterbejahr没年 + + date unveileddatum onthullingDesignates the unveiling dateDuidt de datum van onthulling aan + + ψευδώνυμοaliasalias別名alias + + former coach + + gross domestic product rank + + αριθμός μελώνnombre de membresnumber of membersnúmero de membrosnumero de miembros + + Alps supergroupAlps υπερομάδαsupergruppo alpinothe Alps supergroup to which the mountain belongs, according to the SOIUSA classification + + number of turnsnombre de virages + + european affiliationafiliacao europeia + + last flight + + rocket functionpurpose of the rocket + + dissolved + + latest preview date + + boilerδοχείο βράσης + + saintάγιοςheiligesanto + + operating systembesturingssysteem + + narrator + + lower earth orbit payload (g)Payload mass in a typical Low Earth orbit + + programming language + + number of matches or caps + + maximum area + + faculty sizenumber of faculty members + + second driverδεύτερος οδηγός + + place of burial + + current productionThe current production running in the theatre. + + flying hours (s) + + chromosomeχρωμόσωμα染色体 + + map descriptionkaart omschrijving + + Primite + + editorσυντάκτηςHerausgeberredacteur + + symbolHUGO Gene Symbol + + headquarterαρχηγείοHauptsitz + + richest countryπλουσιότερη χώραpaís mais rico + + non-fiction subjectnon-fictie onderwerpThe subject of a non-fiction book (e.g.: History, Biography, Cookbook, Climate change, ...). + + number of spansAnzahl der BögenNumber of spans or arches. + + iso code of a place + + ship draft (μ)The draft (or draught) of a ship's hull is the vertical distance between the waterline and the bottom of the hull (keel), with the thickness of the hull included; in the case of not being included the draft outline would be obtained. + + cornish namecornish naam + + foundation + + piston stroke (μ) + + end year of insertion + + PDBPDB + + gross domestic product per people + + surface area (m2)έκταση (m2) + + city sardinian name + + significant design + + governorate + + religious orderreligieuze orde + + Genome DBGenome DBthe edition of the database used (i.e. hg19) + + cultivarName of the cultivar (cultivated variety) + + pertescasualties + + branch fromπαράρτημα από + + commissioner + + σημείο βρασμού (K)point d'ébullition (K)boiling point (K)沸点 (K)kookpunt (K)Siedepunkt (K) + + drama + + blockblok + + ceeb + + number of rockets + + settlement attached + + military rankThe highest rank achieved by a person. + + purchasing power parity + + width of runway (μ)滑走路の全幅 (μ) + + player in teamπαίχτης σε ομάδαA person playing for the sports team.Άτομο που παίζει για αθλητική ομάδα. + + number of filmsαριθμός ταινιών + + youth years + + voltage of electrification (V)Voltzahl der Elektrifizierung (V)Voltage of the electrification system. + + logoλογότυποlogo + + garrison + + population as ofbevolking vanafpopulation en date deχρονιά_απογραφής + + winning team + + NUTS codeNUTS-code:Nomenclature of Territorial Units for Statistics (NUTS) is a geocode standard for referencing the subdivisions of countries for statistical purposes. The standard is developed and regulated by the European Union, and thus only covers the member states of the EU in detail. + + trainerεκπαιδευτήςentraîneurtrainer + + landing date + + coachπροπονητής + + derivative + + reopening dateDate of reopening the architectural structure. + + discovereddescobridorΗμερομηνία ανακάλυψης + + metropolitan boroughstadswijk + + date membership establisheddatum vaststellen ledental + + number of goals scored + + coast line (μ) + + track length (μ)Streckenlänge (μ)Length of the track. Wikipedians usually do not differentiate between track length and line lenght. + + number of visitors as ofThe year in which number of visitors occurred. + + premiere placeThe theatre and/or city the play was first performed in. + + completion datedatum van oplevering + + cable car + + arrondissementarrondissementarrondissementδιαμέρισμα + + academic advisorpromotorακαδημαϊκοί_σύμβουλοι + + addedπροστιθέμενη + + Dorlands prefix + + route type abbreviationThe route type abbreviation (eg.: I for Interstate, M for Motorway or NJ for New Jersey Route). + + ward of a liechtenstein settlement + + summer appearances + + minority leadernumber of office holder + + free flight time (s) + + ημερομηνία_γέννησηςdate de naissancebirth date生年月日geboortedatumজন্মদিনGeburtsdatum + + eruption + + per capita income as ofrenda per capita em + + has natural busttem busto natural + + circuit length (μ) + + number of bronze medals wonnomber de médailles de bronze gagnéescantidad de medallas de bronce ganadas + + United States National Bridge ID + + draft year + + end career + + sportάθλημαsport + + id + + average depth quote + + eMedicine subjecteMedicine onderwerp + + landing site + + capital elevation (μ) + + crown dependency + + prominence (μ) + + genusgeslacht属_(分類学) + + state delegate + + chairman title + + split from partyAbspaltung von Partei + + engineeringenieurIngenieurμηχανικός + + officer in charge + + cylinder count + + debut + + call sign meaningThe out written call sign. + + EntrezGeneEntrezGene + + peopleName + + aircraft gunΠολυβόλο + + date extendedεπέκταση + + ratio + + wins at ALPG + + play role + + city german name + + enemy + + ra + + minimum elevation (μ)βάση (μ)minimum elevation above the sea level + + inclination + + sharing out population + + other function + + black ski piste number + + translated motto + + subsequent workvervolg werkεπόμενη δημιουργία + + associated rocketσυνδεόμενος πύραυλος + + shore length (μ)μήκος_όχθης (μ) + + elevation (μ)hoogte (μ)υψόμετρο (μ)altitude (μ)average elevation above the sea levelaltitude média acima do nível do mar + + source country + + work area (m2)Arbeitsplätze (m2) + + gnl + + source region + + number of academic staffαριθμός ακαδημαϊκού προσωπικού + + gaelic name + + colorChart + + climateclimaklimaklimaat + + wins at majors + + city frioulan name + + number of sports eventsαριθμός αθλητικών γεγονότωνnumbre d'épreuves sportivesnumero de dpruebas deportivas + + relatedgerelateerd + + chief executive officerGeschäftsführer + + other appearances + + president of the regional council + + port1first docking port of a spacecraft + + distance to Dublin (μ)απόσταση από το Δουβλίνο (μ) + + city calabrian name + + population urban density (/sqkm) + + title datetitel datumdata do titulo + + largest countrymaior país + + closing yearSluitingsjaarSchließungsjahr + + educationopleidingéducation教育 + + publication datepublicatiedatum + + closing film + + champion in mixed doublekampioen gemengd dubbelspelchampion en double mixteCampeón en doble mixtowinner of a competition in the mixed double session (as in tennis) + + length of runway (μ)Start- und Landebahnlänge (μ) + + phone prefix + + governmentgouvernement + + updatedThe last update date of a resource + + largest settlementgrootste plaats + + spaceRaum + + associated actσυνδεδεμένη πράξη + + Alps main partκύριο μέρος των άλπεωνgrande parte alpinathe Alps main part to which the mountain belongs, according to the SOIUSA classification + + γλώσσαlanguelanguagetaallínguaSprache + + boardεπιβιβάζομαιbestuur取締役会 + + source confluence elevation (μ) + + interestενδιαφέρον + + chorus character in playThe name of the (Greek) chorus character in play. + + ship launched + + ground + + source confluence position + + production years + + last launch rocket + + city rankRang StadtPlace of the building in the list of the highest buildings in the cityDer Platz des Gebäudes in der Liste der höchsten Gebäude der Stadt + + lunar module + + cost ($)kosten ($)κόστος ($) + + fastest driver team + + episode numberThe episode number of the TelevisionEpisode. + + custodian + + foresterDistrict + + πάρτυparty政党partijPartei + + party numbernúmero do partido + + datedatumημερομηνία + + other party + + afdb idafdb idcódigo no afdb + + escape velocity (kmh) + + other information of a settlement + + memberlid van + + choreographerchoreograaf + + maximum depth quote + + appearances in leagueεμφανίσεις στο πρωτάθλημα + + licence number + + crew member + + joint community + + πρωτεύουσαcapitalcapitalhoofdstadcapitalHauptstadt + + eyesogen + + is part of anatomical structureist ein Teil von anatomischer Struktur + + deaneryproosdijDioceses and parishes should know which deaneries there are + + e-teatr.pl id + + source district + + presenterπαρουσιαστής + + area date + + number of representatives + + note on resting place + + frozenπαγωμένη + + successful launches + + gradesβαθμοί + + record labelplatenlabelδισκογραφική + + belgium political seats + + project end dateThe end date of the project. + + JSTORJSTOR number (short for Journal Storage) is a United States-based online system number for archiving academic journals. + + homeport + + number of wineries + + austrian land tag mandate + + land registry code + + passengers used systembenutztes System der PassagiereSystem the passengers are using (from which the passenger statistics are). + + is a city state + + satellites deployed + + date of an agreement + + income + + ratingcijfer + + territoryterritorio + + TERYT codekod TERYTindexing code used by the Polish National Official Register of the Territorial Division of the Country (TERYT) to identify various entities + + ensembleensemble + + The IUPAC International Chemical IdentifierInternationale chemische Bezeichnung der IUPAC + + dissolution year + + education system + + distance to Belfast (μ) + + star rating + + year of world champion titlejaar van wereldkampioen titelannée d'obtention du titre de champion du mondecan be one or several yearsil peut s'agir d'une ou de plusieurs années + + model start year + + recent winner + + number of live albumsthe number of live albums released by the musical artist + + major shrineschrijn + + DiseasesDBDiseasesDBDiseasesDB + + main organ + + timeshift channel + + salesπώλησηventeThis property holds an intermediate node of the type Sales. + + Establishmentίδρυση + + meaning + + note + + b side + + subdivision name of the island + + project start dateThe start date of the project. + + recorded inopgenomen inηχογράφησηenregistré à + + αριθμός εργαζομένωνnombre d'employésnumber of employeesaantal medewerkersnúmero de empleados + + area of searchΠεριοχή Αναζήτησης + + majority leadernumber of office holder + + record dateopname datumηχογράφηση + + special effectsthe person who is responsible for the film special effects + + πυκνότητα (μ3)densité (μ3)density (μ3)密度 (μ3)densidade (μ3)Dichte (μ3) + + IATA Location IdentifierΙΑΤΑ + + grinding capabilitymaal capaciteitgrinding capability for Mills + + wins at LAGT + + compression ratio + + egafd idegafd idcódigo no egafd + + minimum inclination + + river mouthriviermondingεκβολές + + parent organisationmoederorganisatie + + patron saint + + major volcanomaior vulcão + + size (B)Dateigröße (B)size of a file or software + + maximum elevation (μ)κορυφή (μ)maximum elevation above the sea level + + tournament record + + resolutionανάλυσηrésolutionNative Resolution + + official language + + saturation coordinate in the HSV colour space + + supply + + orderδιαταγήorde目_(分類学) + + mill span (μ)vlucht (μ)Εκπέτασμα (μ) + + third driver + + orogenyorogenèse + + houseσπίτι + + event date + + last winτελευταία νίκη + + rival + + artistartiestInterpretκαλλιτέχνης + + denomination + + grandsire + + gini coefficient rankingposição no ranking do coeficiente de Gini + + rangebereik + + promotion + + last championson şampiyon + + cylinder bore (μ) + + wilaya + + right child + + illiteracyanalfabetismo + + managerπροπονητής + + adjacent settlement of a switzerland settlement + + asset under management ($)κεφάλαιο υπό διαχείριση ($) + + selectionwhen (or in which project) the person was selected to train as an astronaut + + operatorexploitant + + father + + clubs record goalscorer + + προέλευσηorigineoriginoorsprongorigemHerkunft + + active years start dateενεργά χρόνια ημερομηνία έναρξηςactieve jaren startdatumdate de début d'activité + + percentage of fatvetgehaltehow much fat (in relative terms) does this unity of food contain + + number of parking spaces + + branchriviertakδιακλαδώσεις + + last election dateThe last election date for the house. + + draft round + + associateStarσυγγενικός αστέραςçevreleyen + + previous population total + + dist_pc + + filenamebestandsnaamdateinameόνομα αρχείου + + former teamvoormalig team + + manx name + + wins at other tournaments + + number of volumes + + race + + date constructionέναρξη_κατασκευής + + draft pick + + statusstatusstatutestatus + + dress codeThe recommended dress code for an establishment or event. + + appmag_v + + precursor + + regional language + + SIL codeSIL-codekod SIL + + Council area + + absolute magnitudeαπόλυτο μέγεθοςabsolute Helligkeit + + publisheruitgeverHerausgeberεκδότης + + population metro density (/sqkm)bevolkingsdichtheid (/sqkm) + + number of sportsnumbre de sportsnumero de deportes + + area metro (m2)περιοχή μετρό (m2) + + wins at LPGA + + χρώμαcouleurcolourkleurFarbeA colour represented by its entity. + + daira + + alongsideδίπλα + + country with first satellite launched + + comment + + agglomerationPopulationYear + + type coordinate + + project reference IDThe reference identification of the project. + + highway systemthe highway system that a route is part of + + ISBNISBNThe International Standard Book Number (ISBN) is a unique numeric commercial book identifier based upon the 9-digit Standard Book Numbering (SBN) code. + + management place + + visitor statistics as ofYear visitor information was gathered. + + school number + + mean temperature (K)μέση θερμοκρασία (K) + + anniversaryεπέτειος + + σκηνοθέτηςdirecteurdirectorregisseurRegisseur + + revenue ($)έσοδα ($) + + television seriesτηλεοπτικές σειρές + + creative director + + sublimation point (K) + + wins at pga + + passengers per dayPassagiere pro TagNumber of passengers per day. + + UniProtUniProt + + superintendentopzichter + + wine produced + + de facto language + + computing platformsome sort of hardware architecture or software framework, that allows this software to run + + ATC prefixATC πρόθεμαpréfix ATC + + last positionτελευταία θέση + + number of contries inside en continent + + area of catchment (m2)λίμνη (m2) + + chancellorKanzler + + έτος ίδρυσηςfounding yearoprichtingsjaaraño de fundaciónGründungsjahr + + number of people attendingnúmero de participantesnombre de participants + + european parliament groupgrupo parlamentar europeu + + eruption dateJahr des letzten Ausbruchsjaar uitbarsting + + NRHP typeType of historic place as defined by the US National Park Service. For instance National Historic Landmark, National Monument or National Battlefield. + + goals in leaguedoelpunten in de competitie + + subdivision + + managementmanagement + + mayor function of a switzerland settlement + + produces + + cyrillique name + + hybridPlants from which another plant (or cultivar) has been developed from + + CPU + + bourgmestre + + NIS codeIndexing code used by the Belgium National Statistical Institute to identify populated places. + + music subgenre + + university大学university a person goes or went to + + worst defeat + + next eventvolgende evenementεπόμενο γεγονός + + distributing company + + chaplain + + number of studio albumsthe number of studio albums released by the musical artist + + combattantfighter + + Alps subsectionAlps υποδιαίρεση των άλπεωνsottosezione alpinathe Alps subsection to which the mountain belongs, according to the SOIUSA classification + + feat + + end reign + + police name + + country蔵書数 + + career points + + boiler pressureπίεση δοχείου βράσης + + number of professionalsnombre de professionnelsnumero de profesionalesnumber of people who earns his living from a specified activity. + + alumniαπόφοιτοι πανεπιστημίου + + volcano id + + allcinema idallcinema idallcinema id + + religious head + + employer's celebration + + εθνικότηταnationaliténationality国籍nationaliteitnacionalidadeNationalität + + fees ($)δίδακτρα ($) + + number of albumsthe total number of albums released by the musical artist + + certificationcertification + + waterway through tunnelWasserweg durch TunnelWaterway that goes through the tunnel. + + RefSeq + + statistic year + + project budget funding ($)The part of the project budget that is funded by the Organistaions given in the "FundedBy" property. + + teamteamομάδαéquipe + + highest point of the island + + aircraft transportαερομεταφορές + + number of roomsαριθμός δωματίωνaantal kamers + + mayorMandate + + system of lawrechtssysteemA referral to the relevant system of law + + station visit duration (s) + + ISO 639-3 codeISO 639-3 codekod ISO 639-3 + + parent mountain peak + + Film Fare Award + + first launch date + + green coordinate in the RGB space + + election dateWahltermin + + Ceremonial County + + Golden Globe Award + + belgium merged settlement + + binomialδιωνυμικός学名 + + principal + + rail gauge (μ)Spurweite Eisenbahn (μ) + + personάτομο + + foal date + + argue dateδημοφιλής ημερομηνία + + wins at championships + + vice presidentVizepräsident + + licence number label + + project participantA participating organisation of the project. + + source confluence region + + date completedολοκλήρωση + + configurationconfiguration + + sport governing body + + provinceεπαρχίαprovincie + + ICD10ICD10 + + έκταση περιοχής (m2)superficie (m2)area total (m2)oppervlakte (m2)Fläche (m2) + + route endWegendeEnd of the route. This is where the route ends and, for U.S. roads, is either at the northern terminus or eastern terminus.Ende des Verkehrswegs. + + highest mountain + + notable commander + + iss dockings + + International Standard Identifier for Libraries and Related Organizations (ISIL) + + official opened by + + professionεπάγγελμαberoep + + redline (kmh) + + OMIM idOMIM idOMIM id + + cargo fuel (g) + + regional council + + number of countriesαριθμός χωρώνnúmero de países + + program cost ($) + + currency codeISO 4217 currency designators. + + allianceσυμμαχία + + general manager + + length reference + + mandate of the president council of the regional council + + population date + + episode + + mgiidmgiidMouse Genomic Informatics ID + + cover artistcover artistCover artist + + broadcast areaπεριοχή αναμετάδοσης + + label of a website + + heritage registerinventaire du patrimoineregistered in a heritage register : inventory of cultural properties, natural and man-made, tangible and intangible, movable and immovable, that are deemed to be of sufficient heritage value to be separately identified and recorded.inscrit à un inventaires dédiés à la conservation du patrimoine, naturel ou culturel, existants dans le monde. + + final publication datelaatste publicatiedatumDatum der finalen AusgabeDate of the final publication.Datum der allerletzten Veröffentlichung des Periodikums. + + budget ($)budget ($)προϋπολογισμός ($) + + regionregioπεριοχή + + former band membervoormalig bandlidA former member of the band. + + Goya Award + + number of officesAnzahl Bürosαριθμός γραφείωνNumber of the company's offices.Αριθμός γραφείων εταιρείας. + + hue coordinate in the HSV colour space + + INNDCIInternational Nonproprietary Name given to a pharmaceutical substance + + route startWeganfangStart of the route. This is where the route begins and, for U.S. roads, is either at the southern terminus or western terminus.Anfang des Verkehrswegs. + + musicFormatmusikFormateThe format of the album: EP, Single etc. + + flagσημαίαvlaggöndere çekmek + + long distance piste kilometre (μ) + + mukthar of a lebanon settlement + + ethnicityethnische zugehörigkeitetnia + + définitiondefinitiontanımlar + + wins at AUS + + bluecoordinate in the RGB space + + devisecurrencyvalutamoedaWährung + + doctoral studentδιδακτορικοί_φοιτητέςdoctoraalstudent + + population placea place were members of an ethnic group are living + + squad numberThe number that an athlete wears in a team sport. + + command module + + number of ministriesnumero de ministerios + + ELO rating + + association of local governmentvereniging van lokale overhedenσυνεργασία της τοπικής αυτοδιοίκησης + + management country + + addressadresseadresδιεύθυνση + + seniunija + + medalistmedalhista + + distributorallumeur + + offered classes + + highest building in year + + discipline + + εικόναpictureafbeeldingfiguraBildA picture of a thing. + + lunar EVA time (s) + + combatant + + number of studentsαριθμός φοιτητών + + contractoraannemer + + former channel + + capital position + + constellationgwiazdozbiórTakımyıldızstelsel + + κατηγορίαcatégoriecategoryKategorieKategorie + + apc president + + total population rankingposição no ranking do total da populacao + + breederκτηνοτρόφος + + legislative period nameName in der LegislaturperiodeThe term of the on-going session (e.g.: "40th Canadian Parliament"). + + billed + + finnish name of a sweden settlement + + patron (art)mécèneAn influential, wealthy person who supported an artist, craftsman, a scholar or a noble.. See alsoCelui qui encourage par ses libéralités les sciences, les lettres et les arts. + + model end date + + gross domestic product as ofproduto interno bruto em + + number of villagesjumlah desa/kelurahan + + artificial snow area + + port1 docking date + + structural systembouwmethodeκατασκευαστικό σύστημα + + reopened + + based onβασισμένο σεop basis van + + staffπροσωπικό + + sister newspaper + + PubChemPubChemPubChem + + highest rankhöchster Ranglistenplatz + + source state + + Number of votes given to candidate + + wins at ASIA + + equity ($) + + skillscompétencesbekwaamheden + + comparablesimilar, unrelated rockets + + diameter (μ)diameter (μ)diamètre (μ)διάμετρος (μ) + + BAFTA Awardβραβείο BAFTA + + statistic label + + route end locationOrt des WegendesThe end location of the route.End-Ort des Verkehrswegs. + + positionΘέσηpositie + + maximum boat beam (μ)μέγιστο_πλάτος_πλοίου (μ) + + orbital flights + + team size + + scotish name + + familytaalfamilierodzina + + opponent敵対者Gegner + + vice prime ministervice premier + + settlement code + + funded byA organisation financing the research project. + + classτάξηklasse + + avifauna population + + landing vehicle + + γνωστός_γιαconnu pourknown forbekend omconocido porbekannt für + + hub airport + + most populated countrypaís mais povoado + + distance to Charing Cross (μ) + + albumalbumαπό το άλμπουμ + + mozabite settlement name + + reference for cultural data + + extinction dateontbindingsdatum + + aircraft helicopter attackεπίθεση ελικοφόρων αεροσκαφών + + tree + + seniority + + second driver country + + materialmatériel + + umbrella titleoverkoepelende titel + + ISO 639-2 codeISO 639-2 codekod ISO 639-2 + + twin country + + depth (μ)diepte (μ)βάθος (μ)profondeur (μ) + + gini coefficient as ofcoeficiente de Gini em + + Established + + μήκος (μ)longueur (μ)length (μ)lengte (μ)Länge (μ) + + has channel + + place of military conflictOrt eines militärischen Konflikts + + maximum area quote + + number of teamsnumero di squadre + + largest win + + solicitor generaladvocaat-generaalhigh-ranking solicitorde advocaat-generaal + + rank of an area + + sport specialtysport specialiteitthe sport specialty the athlete practices, e.g. 'Ring' for a men's artistic gymnastics athlete + + status year + + number of participating athletesnombre d'athlètes participant + + number of volunteersαριθμός εθελοντών + + eraεποχή + + game artistゲームデザイナーA game artist is an artist who creates art for one or more types of games. Game artists are responsible for all of the aspects of game development that call for visual art. + + deme + + setting of playThe places and time where the play takes place. + + railway platformsperronsαποβάθραInformation on the type of platform(s) at the station. + + legal articlewetsartikelarticle in code book or statute book referred to in this legal case + + french name of a settlement + + equipmentεξοπλισμός + + position in which a surface occurs in a text + + notesnotesadditional notes that better describe the entity + + spur type + + catholic percentage + + size map + + Grammy Award + + academic disciplinewissenschaftliche DisziplinAn academic discipline, or field of study, is a branch of knowledge that is taught and researched at the college or university level. Disciplines are defined (in part), and recognized by the academic journals in which research is published, and the learned societies and academic departments or faculties to which their practitioners belong. + + death age + + iucn categoryIUCN categorie + + boosterπροωθητής + + FDA UNII codecódigo FDA UNIIFDA Unique Ingredient Identifier (UNII) code for a DBpedia Drug + + IUPAC nameIUPAC名 + + Wikipage revision IDReserved for DBpedia. + + next entity + + nerve + + first winnerπρώτος νικητής + + techniqueτεχνικήtécnica + + communecommune + + intercommunality shape + + outflowεκροή + + weaponwapen + + classificationcategorie + + movementbewegingmouvement artistiqueartistic movement or school with which artist is associated + + ship beam (μ)The beam of a ship is its width at the widest point. + + currently used forhuidig gebruikusage actueluso actualCurrent use of the architectural structure, if it is currently being used as anything other than its original purpose. + + frequency (Hz)συχνότητα (Hz)fréquence (Hz) + + suppliesπαροχές + + topic + + start reign + + named after + + Method of discovery + + heirErbe + + highest point of a norwegian settlement + + ski piste kilometre (μ) + + championchampionCampeónwinner of a competition + + launch pad + + Game Engineゲームエンジン + + body styleτύπος σώματος + + total launches + + first flight end date + + highest breakHöchstes Break + + Orthologous Geneオーソロガス遺伝子 + + organisation memberIdentify the members of an organisation. + + siblingbroer of zusfrère ou soeurGeschwister + + brain info typeτύπος νοητικής πληροφόρησης + + route + + UTC offset + + ιδιοκτήτηςpropriétaireownereigenaardueñoEigentümer + + wavelength (μ)longueur d'onde (μ) + + Stadiumστάδιο + + on chromosomethe number corresponding to the chromosome on which the gene is located + + Bundeslandfederal stateprovincie + + certification datedatum certificatie + + variant or variationvariant of variatievariant or variation, for example all variations of a color + + function end yearlaatste jaar functie + + minimum system requirements + + source elevation (μ) + + firstPopularVote + + station structurestation structuurType of station structure (underground, at-grade, or elevated). + + regional prefecture + + competitioncompetitioncompetición + + number of piers in waterAnzahl der Pfeiler in WasserNumber of piers standing in a river or other water in normal conditions. + + astrological signαστρολογικό ζώδιοSternzeichensigno astrológico + + resting place position + + geolocDepartment + + TradeMarkMarca + + first race + + binomial authority(学名命名者) + + same name of a sweden settlement + + EKATTE codeIndexing code used by the Bulgarian National Statistical Institute to identify populated placesЕдинен класификатор на административно-териториалните и териториалните единици + + editing + + committee in legislatureAusschuss in der LegislativeCommittee in the legislature (eg.: Committee on Economic and Monetary Affairs of the European Parliament). + + reference for politic data + + siren number + + rebuilding yearherbouw jaar + + melting point (K)Schmelzpunkt (K)point de fusion (K)融点 (K) + + minimum area quote + + champion in single malechampion en simple hommeCampeón en simple hombreswinner of a competition in the single male session, to distinguish from the double session (as in tennis) + + roof heightHöhe Dach + + country rankRang LandPlace of the building in the list of the highest buildings in the countryDer Platz des Gebäudes in der Liste der höchsten Gebäude des Landes + + registration + + number of competitors + + part + + layout + + eMedicine subjecteMedicine onderwerp + + neighboring municipalityaangrenzende gemeentemunicipío adjacente + + ΤίτλοςtitleタイトルtiteltítuloTitel + + orbits + + taoiseachhead of government of Ireland + + first win + + open access contentfrei zugänglicher InhaltenAvailability of open access content.Verfügbarkeit von frei zugänglichem Inhalten. + + parent company + + chief place + + power + + distance to Edinburgh (μ)απόσταση από το Εδιμβούργο (μ) + + upper age + + former nameπροηγούμενο όνομα + + National Film Award + + subsystem + + output + + ACT scoreACT σκορmost recent average ACT scoresποιό πρόσφατες μέσες βαθμολογίες ACT + + spikeκαρφίsmaç + + area water (m2)oppervlakte water (m2)έκταση_υδάτων_περιοχής (m2) + + subsystem link + + ski tow + + mayorδήμαρχοςburgemeestermaire + + manufacturerκατασκευαστής + + Academy AwardΒραβείο ακαδημίας + + launch site + + Computing input + + monument protection statusmonumentStatusJust 'Status' is too general. We should be able to distinguish status types since different statuses may require different treatmentAlleen 'Status' is te algemeen. We moeten soorten statussen kunnen onderscheiden omdat een andere status andere consequenties kan hebben + + associated bandσυνεργαζόμενο συγκρότημα + + floor countverdiepingenαριθμός ορόφων + + colour hex code of away jersey or its partsFarben Hex Code des Auswärtstrikots oder Teile diesesA colour represented by its hex code (e.g.: #FF0000 or #40E0D0). + + UCI codecodice UCIOfficial UCI code for cycling teams + + dynastydynastie + + austrian land + + lieutenancy + + time in space (s) + + valvetrain + + θρησκείαreligionreligion宗教religiereligião + + agglomerationPopulation + + biome生物群系 + + NAACP Image Award + + aircraft fighterμαχητικό αεροσκάφος + + IBDB IDThe Internet Broadway Database ID (IBDB ID) from ibdb.com. + + Screen Actors Guild Award + + typeτύποςtype + + line length (μ)Linienlänge (μ)Length of the line. Wikipedians usually do not differentiate between track length and line lenght. + + city ladin name + + goals in national teaminterland doelpunten + + number of pads + + share source + + wha draft + + session numbernúmero da sessão + + islandνησιά + + has input + + oversight + + country with first satellite + + number of continent dependencies + + music by + + Gray pageRefers to the famous 1918 edition of Gray's Anatomy. + + governorκυβερνήτηςgouverneur + + champion in double malechampion en double hommesCampeón en doble hombreswinner of a competition in the male double session (as in tennis) + + gold medalistmedalha de ouro + + ski lift + + doubles rankings + + incumbentplaatsbekleder + + Ordination + + kanji name + + mayor title of a hungarian settlement + + περιοχήdistrictstreekdistritoBezirk + + olympic oath sworn bylecteur du serment olympique + + publicly accessibledescribes in what way this site is accessible for public + + manager title + + CAS numbernuméro CASCAS番号 + + crossesδιασχίζει + + orbital inclination + + translatorvertalerμεταφραστήςtraducteurTranslator(s), if original not in English + + activitéoccupation職業beroepBeschäftigung + + τόπος_γέννησηςlieu de naissancebirth placegeboorteplaatsGeburtsortwhere the person was born + + flagCaption + + municipalityplaatsmunicipalité + + locality of a switzerland settlement + + appearances in national teamεμφανίσεις στην εθνική ομάδα + + webcastwebcastThe URL to the webcast of the Thing. + + Wikipage disambiguatesReserved for DBpedia. + + rank in final medal count + + thumbnailCaption + + operating income ($) + + IMDB idIMDB idimdb idIMDb id + + missionsαποστολές + + sharing out year + + source confluence mountain + + επιφάνεια απόReserved for DBpedia. + + aircraft helicopter multiroleελικοφόρο αεροσκάφος πολλαπλών ρόλων + + facility id + + outskirts + + organ systemthe organ system that a anatomical structure belongs to + + dec + + lunar surface time (s) + + number of clubsnombre de clubsnumero de clubs + + majority floor leadernumber of office holder + + lowest mountainχαμηλώτερο βουνό + + activity + + Number Of Federal Deputiesnumero de deputados federais + + mouth state + + novel + + Wikipage page IDReserved for DBpedia. + + Gene Location遺伝子座 + + retired rocket + + aircraft helicopterελικοφόρο αεροσκάφος + + first appearance + + blazon ratio + + colour hex code of home jersey or its partsFarben Hex Code des Heimtrikots oder Teile diesesA colour represented by its hex code (e.g.: #FF0000 or #40E0D0). + + chefsous-chefchefchef cuisinier + + sequence number + + seasonsezon + + top scoreren golcü + + chaoui settlement name + + neighbourhood of a hungarian settlement + + sharing out population name + + gini coefficient categorycategoria do coeficiente de Gini + + less populated countrypaís menos povoado + + maintained bygewartet von + + station EVA duration (s) + + source mountain + + parliament type + + mir dockings + + Believers + + Member of Parliament + + human development index as ofÍndice de desenvolvimento humano em + + winter appearances + + premiere dateDate the play was first performed. + + city link + + administrative center + + year of constructionbouwjaarBaujahrέτος κατασκευήςThe year in which construction of the Place was finished.Το έτος στο οποίο ολοκληρώθηκε η κατασκευή ενός μέρους. + + landeshauptmann + + area urban (m2)αστική περιοχή (m2) + + curatorconservator + + οικογένειαfamillefamily科_(分類学)familierodzinafamilie + + executive producer + + transmissionμετάδοση + + personName + + number of participating female athletesnombre d'athlètes participant féminins + + road start directionHimmelsrichtung des WegstartsEnd of the route. For U.S. roads, this should be either "South" or "West" per the standards set by the U.S. Roads project.Himmelsrichtung des Anfangs des Verkehrsweges. + + meeting roadzusammentreffende StraßeA road that crosses another road at the junction.Eine Straße die an der Kreuzung eine andere Straße kreuzt. + + sport disciplinediscipline sportivetak van sportthe sport discipline the athlete practices, e.g. Diving, or that a board member of a sporting club is focussing at + + wins at KLPGA + + highest place + + canonized placeheiligverklaring plaats + + settlement + + number of entrancesαριθμός εισόδωνaantal ingangen + + most successfullen başarılı + + sexual orientationorientação sexual + + senior + + value coordinate in the HSV colour space + + international affiliationafiliacao internacional + + welsh name + + Penalties Team B + + character in playName of a character in play. + + size blazon + + area of water (m2) + + torque output (Nm) + + city greek name + + number of episodesαριθμός επειδοδίων + + cannon number + + campus + + engine type + + mouth district + + prefect of a romanian settlement + + source place + + bgafd idbgafd idcódigo no bgafd + + limit + + governor general + + population rural + + start datestartdatumdate de débutfecha de inicioThe start date of the event. + + former highschool + + cantonkantoncanton + + political party in legislaturepolitische Partei in der LegislativePolitical party in the legislature (eg.: European People's Party in the European Parliament). + + Ariel AwardAriel Award + + refseq proteinrefseq protein + + wha draft team + + person that first ascented a mountain + + total area rankingσυνολική περιοχή + + συντομογραφίαabréviationabbreviationafkortingskrótAbkürzung + + year of first ascentjaar van de eerste beklimming + + route numberThe number of the route. + + secondPopularVote + + frequently updated + + national teamnationaal team + + co executive producer + + chainketteαλυσίδαThe chain of Hotels this instance is associated with. + + V_hb + + serving railway linespoorlijnenangebundene EisenbahnlinieRailway services that serve the station. + + αρχιτέκτοναςarchitectearchitectarchitectArchitekt + + flag bearer + + apoapsis (μ)απόαψης (μ) + + width (μ)breedte (μ)Breite (μ)πλάτος (μ) + + minimum discharge (m³/s) + + capital place + + deputy + + date when the island has been discovereddatum waarop het eiland is ontdekt + + lunar landing site + + is part of military conflict + + school board + + component + + rebuilding date + + broadcast networkSendergruppeτηλεοπτικό κανάλιchaîne de télévision généralisteThe parent broadcast network to which the broadcaster belongs.Die Sendergruppe zu dem der Rundfunkveranstalter gehört. + + decommissioning date + + military commandFor persons who are notable as commanding officers, the units they commanded. Dates should be given if multiple notable commands were held. + + number of settlement inside a department + + introduction date + + population density rural (/sqkm) + + longNamevolledige naam + + destinationπροορισμός + + market capitalisation ($) + + appointer + + tor floor heightHöhe der höchsten Etage + + ethnic groups in year + + firstLeaderπρώτος ηγέτης + + battle honours + + clip up number + + chairpersonvoorzitter + + first publication yearJahr der Erstausgabeπρώτο έτος δημοσίευσηςYear of the first publication.Jahr der ersten Veröffentlichung des Periodikums.Έτος της πρώτης δημοσίευσης. + + eye colorAugenfarbecor dos olhos + + partial failed launchestotal number of launches resulting in partial failure + + name dayονομαστική εορτήimieniny + + mill code NLmolen code NL + + japan name + + gene location end遺伝子座のエンド座標the end of the gene + + champion in doublekampioen dubbelchampion en doubleCampeón en doblewinner of a competition in the double session (as in tennis) + + gamesαγώνες + + sire + + winsνίκεςzeges + + fuel consumptionbrandstofverbruik + + long distance piste number + + mascotmascotemascottesomething, especially a person or animal, used to symbolize a sports team, company, organization or other group.Animal, poupée, objets divers servant de porte-bonheur ou d’emblème. + + project budget total ($)The total budget of the research project. + + left tributaryαριστεροί_παραπόταμοι + + shoots + + 色名Farbennamenom de couleurA colour represented by a string holding its name (e.g.: red or green). + + start year of sales + + introduced + + autonomyαυτονομία + + Modus the game can be played in + + population quote + + initally used forusage initialuso inicialInitial use of the architectural structure. + + most down point of a norwegian settlement + + dayημέραjour + + ταινίαfilmfilmfilmfilm + + Golden Calf Award + + trustee + + other name + + commissioning date + + minimum area + + playing time (s)speeltijd (s) + + function start year + + capital mountain + + decoration + + volume (μ³)volume (μ³)όγκος (μ³)volume (μ³) + + growing grape + + instrumentόργανοinstrument + + place of worshipgebedsplaatsA religious administrative body needs to know which places of worship itEen kerkelijke organisatie houdt bij welke gebedshuizen ze heeft + + trainer yearstrainersjaren + + production end yearproductie eindjaar + + acting headteacherδιευθυντής σχολείου + + τύπος μύλουmill typemolen-type + + Peabody Award + + collegeκολλέγιοhaute école + + bridge carriesγέφυρα μεταφοράςType of vehicles the bridge carries. + + archipelagoαρχιπέλαγοςarchipel + + algerian settlement name + + other + + councillor of an austrian mayor + + located in arealandstreek + + ski piste number + + date of burialdatum begrafenis + + ICDOICDO + + number of launches + + construction materialbouwmateriaalBaumaterialConstruction material (eg. concrete, steel, iron, stone, brick, wood). + + displacement (μ³) + + project typeThe type of the research project. Mostly used for the funding schemes of the European Union, for instance: Specific Targeted Research Projects (STREP), Network of Excellence (NoE) or Integrated Project. + + buildingTypeΤύπος κτιρίουsoort gebouwType is too general. We should be able to distinguish types of music from types of architectureType is te algemeen. We moeten soorten muziek van soorten gebouwen kunnen onderscheidenΟ τύπος είναι πολύ γενικό.Θα πρέπει να είναι σε θέση να διακρίνουν τα είδη της μουσικής από τους τύπους της αρχιτεκτονικής + + date disappearance of a populated place + + mountain rangebergketen + + irish name + + final publication yearJahr der finalen AusgabeYear of the final publication.Jahr der allerletzten Veröffentlichung des Periodikums. + + costume designercostumistathe person who is responsible for the film costume design + + religious head label + + distance (μ)Entfernung (μ) + + black coordinate in the CMYK space + + σύνθημαdevisemottomottolema + + Footednesshabilidade com o péa preference to put one's left or right foot forward in surfing, wakeboarding, skateboarding, wakeskating, snowboarding and mountainboarding. The term is sometimes applied to the foot a footballer uses to kick. + + death causedoodsoorzaakTodesursacheαιτία_θανάτου + + patentpatente + + oldcode + + decayαποσύνθεση + + predecessorvoorgangerVorgänger前任者 + + NSSDC ID + + iafd idiafd idcódigo no iafd + + maori name + + showJudge + + runtime (s)duur (s)διάρκεια (s)durée (s) + + ζώνη_ώρας1fuseau horairetime zonetijdzonefuso horariostrefa czasowahuso horariozona horària + + ranking winsSiege in Ranglistenturnieren + + performer + + closing dateημερομηνία κλεισίματοςdate de fermeture + + boroughδήμοςstadsdeel + + area of a agglomeration + + highschool + + cyanic coordinate in the CMYK space + + french nickname for something + + wins at sun + + power output (W) + + building end yearbouw eindjaarέτος λήξης κατασκευής + + maximum depth (μ)μέγιστο_βάθος (μ) + + rank of a population + + event periodperiode + + notableIdea + + unique reference number (URN)DfE unique reference number of a school in England or Wales + + comitat of a settlement + + stylistic originorigens estilísticas + + leadership + + penalty score + + Vorwahlarea codenetnummerκωδικός_περιοχήςArea code for telephone numbers. + + cooling system + + free + + pastor + + SIMC codeindexing code used by the Polish National Official Register of the Territorial Division of the Country (TERYT) to identify various entities + + designer company + + engineμηχανήmotor + + AFI Awardβραβείο AFI + + endangered sinceem perigo desde + + watercourse + + issnISSNissnISSNInternational Standard Serial Number (ISSN) + + height above average terrain (μ) + + producerproducentProduzentπαραγωγός + + railway line using tunnelTunnel benutzende EisenbahnlinieRailway line that is using the tunnel. + + piscicultural population + + ChEBIA unique identifier for the drug in the Chemical Entities of Biological Interest (ChEBI) ontology + + relief + + digital channel + + aircraft typeτύπος αεροσκάφουςtipo de avión + + leader titleτίτλος_αρχηγού + + jure language + + urban area + + prospect league + + beatified placezalig verklaard plaats + + maiden voyage + + nominee + + monthμήναςMonat + + architectural movement + + destruction datesloopdatumημερομηνία καταστροφής + + touareg settlement name + + olympic oath sworn by judge + + reopening yearheropening jaarYear of reopening the architectural structure. + + impact factor as ofImpact Factor ist vonCensus year of the imapct factor.Erhebungsjahr des Impact Factors. + + number of members as ofnumero de membros em + + chairman + + note on place of burial + + productProduktπροϊόν + + accessπρόσβαση + + American Comedy Awardαμερικάνικο βραβείο κωμωδίας + + demolition dateημερομηνία κατεδάφισηςThe date the building was demolished. + + lunar sample mass (g) + + affiliate + + authorityautoriteitαρχή + + drains to + + city occitan name + + film audio typespecifies the audio type of the film i.e. 'sound' or 'silent' + + longtypecan be used to include more informations e.g. the name of the artist that a tribute album is in honor of + + source confluence place + + parish + + campus size (m2) + + genderφύλοGeschlechtgeslacht + + head chefchef-kok + + area rural (m2)αγροτική περιοχή (m2) + + related placessoortgelijke plaatsenThis property is to accommodate the list field that contains a list of, e.g., monuments in the same townDeze property is voor de lijst van monumenten die horen bij het monument van de infobox + + classisklasse綱_(分類学)the living thing class (from the Latin "classis"), according to the biological taxonomy + + decide date + + quotationcitationcitaA quotation is the repetition of one expression as part of another one, particularly when the quoted expression is well-known or explicitly attributed by citation to its original source.Une citation est la reproduction d'un court extrait d'un propos ou d'un écrit antérieur dans la rédaction d'un texte ou dans une forme d'expression orale.En su acepción más amplia, una cita es un recurso retórico que consiste en reproducir un fragmento de una expresión humana respetando su formulación original. + + previous infrastructurevorige infrastructuur + + school patron + + co producer + + tvShow + + barangays + + manager years + + mainspan (μ)portée principale (μ)κύρια καμάρα (μ) + + number of crewαριθμός πληρώματοςaantal bemanningsleden + + average speed (kmh)Durchschnittsgeschwindigkeit (kmh)μέση ταχύτητα (kmh)The average speed of a thing.Η μέση ταχύτητα ενός πράγματος. + + current statushuidige status + + is part of wine region + + discharge average (m³/s) + + capacitycapacité + + aita code + + date closedτερματισμός_λειτουργίας + + nickname for something + + mill code NLmolen code NLmills code from the central Dutch database on millsunieke code voor molens in www.molendatabase.nl + + μήκος (mm)longueur (mm)length (mm)lengte (mm)Länge (mm) + + + + + wheelbase (mm) + + + + + total mass (kg) + + + + + area urban (km2)αστική περιοχή (km2) + + + + + lunar sample mass (kg) + + + + + volume (km3)volume (km3)όγκος (km3)volume (km3) + + + + + volume (μ³)volume (μ³)όγκος (μ³)volume (μ³) + + + + + piston stroke (mm) + + + + + cargo water (kg) + + + + + μήκος (mm)longueur (mm)length (mm)lengte (mm)Länge (mm) + + + + + mass (kg)μάζα (kg) + + + + + periapsis (km) + + + + + docked time (μ) + + + + + apoapsis (km)απόαψης (km) + + + + + diameter (mm)diameter (mm)diamètre (mm)διάμετρος (mm) + + + + + original maximum boat length (μ) + + + + + station visit duration (ω) + + + + + cargo fuel (kg) + + + + + minimum discharge (m³/s) + + + + + periapsis (km) + + + + + σημείο βρασμού (K)point d'ébullition (K)boiling point (K)沸点 (K)kookpunt (K)Siedepunkt (K) + + + + + βάρος (kg)poids (kg)weight (kg)体重 (kg)gewicht (kg)peso (kg)Gewicht (kg) + + + + + width (mm)breedte (mm)Breite (mm)πλάτος (mm) + + + + + apoapsis (km)απόαψης (km) + + + + + watershed (km2)waterscheiding (km2)cuenca hidrográfica (km2)λεκάνη_απορροής (km2) + + + + + mass (kg)μάζα (kg) + + + + + maximum boat length (μ)μέγιστο_μήκος_πλοίου (μ) + + + + + mean temperature (K)μέση θερμοκρασία (K) + + + + + area metro (km2)περιοχή μετρό (km2) + + + + + time in space (m) + + + + + discharge average (m³/s) + + + + + width (mm)breedte (mm)Breite (mm)πλάτος (mm) + + + + + port2 docked time (μ) + + + + + βάρος (kg)poids (kg)weight (kg)体重 (kg)gewicht (kg)peso (kg)Gewicht (kg) + + + + + population metro density (/sqkm)bevolkingsdichtheid (/sqkm) + + + + + μήκος (mm)longueur (mm)length (mm)lengte (mm)Länge (mm) + + + + + mass (kg)μάζα (kg) + + + + + distance traveled (km)afgelegde afstand (km) + + + + + population density (/sqkm)bevolkingsdichtheid (/sqkm)Bevölkerungsdichte (/sqkm)πυκνότητα_πληθυσμού (/sqkm) + + + + + ύψος (mm)hauteur (mm)height (mm)身長 (mm)hoogte (mm)višina (mm)altura (mm)Höhe (mm) + + + + + maximum discharge (m³/s) + + + + + maximum temperature (K)μέγιστη θερμοκρασία (K) + + + + + periapsis (km) + + + + + width (mm)breedte (mm)Breite (mm)πλάτος (mm) + + + + + power output (kW) + + + + + total cargo (kg) + + + + + free flight time (μ) + + + + + time in space (μ) + + + + + έκταση περιοχής (km2)superficie (km2)area total (km2)oppervlakte (km2)Fläche (km2) + + + + + discharge (m³/s)εκροή (m³/s)uitstoot (m³/s) + + + + + lunar surface time (ω) + + + + + σημείο βρασμού (K)point d'ébullition (K)boiling point (K)沸点 (K)kookpunt (K)Siedepunkt (K) + + + + + maximum boat beam (μ)μέγιστο_πλάτος_πλοίου (μ) + + + + + πυκνότητα (μ3)densité (μ3)density (μ3)密度 (μ3)densidade (μ3)Dichte (μ3) + + + + + fuel capacity (l) + + + + + maximum temperature (K)μέγιστη θερμοκρασία (K) + + + + + population density (/sqkm)bevolkingsdichtheid (/sqkm)Bevölkerungsdichte (/sqkm)πυκνότητα_πληθυσμού (/sqkm) + + + + + cylinder bore (mm) + + + + + lunar orbit time (ω) + + + + + πυκνότητα (μ3)densité (μ3)density (μ3)密度 (μ3)densidade (μ3)Dichte (μ3) + + + + + runtime (m)duur (m)διάρκεια (m)durée (m) + + + + + mass (kg)μάζα (kg) + + + + + ύψος (mm)hauteur (mm)height (mm)身長 (mm)hoogte (mm)višina (mm)altura (mm)Höhe (mm) + + + + + mean radius (km)μέση ακτίνα (km) + + + + + minimum temperature (K)ελάχιστη θερμοκρασία (K) + + + + + cargo gas (kg) + + + + + mean radius (km)μέση ακτίνα (km) + + + + + volume (μ³)volume (μ³)όγκος (μ³)volume (μ³) + + + + + CMP EVA duration (ω) + + + + + population urban density (/sqkm) + + + + + orbital period (μ)Περίοδος περιφοράς (μ) + + + + + top speed (kmh)Höchstgeschwindigkeit (kmh) + + + + + melting point (K)Schmelzpunkt (K)point de fusion (K)融点 (K) + + + + + diameter (μ)diameter (μ)diamètre (μ)διάμετρος (μ) + + + + + campus size (km2) + + + + + minimum temperature (K)ελάχιστη θερμοκρασία (K) + + + + + original maximum boat beam (μ) + + + + + CO2 emission (g/km) + + + + + torque output (Nm) + + + + + mean temperature (K)μέση θερμοκρασία (K) + + + + + lower earth orbit payload (kg) + Payload mass in a typical Low Earth orbit + + + + lunar EVA time (ω) + + + + + displacement (cc) + + + + + orbital period (μ)Περίοδος περιφοράς (μ) + + + + + temperature (K)θερμοκρασία (K)température (K) + + + + + melting point (K)Schmelzpunkt (K)point de fusion (K)融点 (K) + + + + + size (MB)Dateigröße (MB) + size of a file or software + + + + area metro (km2)περιοχή μετρό (km2) + + + + + temperature (K)θερμοκρασία (K)température (K) + + + + + course (km) + + + + + μήκος (km)longueur (km)length (km)lengte (km)Länge (km) + + + + + surface area (km2)έκταση (km2) + + + + + diameter (mm)diameter (mm)diamètre (mm)διάμετρος (mm) + + + + + average speed (km/s)Durchschnittsgeschwindigkeit (km/s)μέση ταχύτητα (km/s) + The average speed of a thing.Η μέση ταχύτητα ενός πράγματος. + + + + ύψος (mm)hauteur (mm)height (mm)身長 (mm)hoogte (mm)višina (mm)altura (mm)Höhe (mm) + + + + + apoapsis (km)απόαψης (km) + + + + + average speed (km/s)Durchschnittsgeschwindigkeit (km/s)μέση ταχύτητα (km/s) + The average speed of a thing.Η μέση ταχύτητα ενός πράγματος. + + + + mission duration (μ) + + + + + βάρος (kg)poids (kg)weight (kg)体重 (kg)gewicht (kg)peso (kg)Gewicht (kg) + + + + + diameter (km)diameter (km)diamètre (km)διάμετρος (km) + + + + + βάρος (kg)poids (kg)weight (kg)体重 (kg)gewicht (kg)peso (kg)Gewicht (kg) + + + + + Beschleunigung (s)acceleration (s)επιτάχυνση (s) + + + + + surface area (km2)έκταση (km2) + + + + + πυκνότητα (μ3)densité (μ3)density (μ3)密度 (μ3)densidade (μ3)Dichte (μ3) + + + + + mass (kg)μάζα (kg) + + + + + distance (km)Entfernung (km) + + + + + ύψος (cm)hauteur (cm)height (cm)身長 (cm)hoogte (cm)višina (cm)altura (cm)Höhe (cm) + + + + + shore length (km)μήκος_όχθης (km) + + + + + έκταση (km2)superficie (km2)area (km2)oppervlakte (km2)área (km2)Fläche (km2) + The area of a owl:Thing in square metre. + + + + floor area (m2)vloeroppervlak (m2)περιοχή ορόφων (m2) + + + + + distance (km)Entfernung (km) + + + + + area of catchment (km2)λίμνη (km2) + + + + + dry cargo (kg)droge last (kg) + + + + + station EVA duration (ω) + + + + + volume (km3)volume (km3)όγκος (km3)volume (km3) + + + + + port1 docked time (μ) + + + + + \ No newline at end of file diff -r 000000000000 -r 718306e29690 cpack/dbpedia/rdf/cpack/dbpedia.ttl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dbpedia/rdf/cpack/dbpedia.ttl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,23 @@ +@prefix rdf: . +@prefix rdfs: . +@prefix dcterms: . +@prefix cpack: . + +<> a cpack:Ontology ; + cpack:packageName "dbpedia" ; + dcterms:title "DBPedia OWL schema" ; + cpack:author [ foaf:name "Samer Abdallah" ; + foaf:mbox ; + ] ; + cpack:primaryRepository + [ a cpack:GitRepository ; + cpack:gitURL + ] ; + cpack:description + +"""This package provides the DBPedia Ontology schema. The default configuration installs + the =dbp= prefix for use in Prolog and ensures that the schema is loaded + in the RDF store. +""" . + + diff -r 000000000000 -r 718306e29690 cpack/dml/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/README Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,29 @@ +# Digital Music Lab Cliopatria plugin + +This CPACK relies on a number of external files and packages. + + +## Score to sound rendering via fluidsynth + +This requires fluidsynth to be installed, along with some usable sound fonts. +The applications/score_ui GUI presents various options for what instrument(s) +to use to sonify a given score. This determines which fluidsynth initialisation +file is used -- these are kept in ./fluid. If you look at one of these files, +you will see that they refer to specific soundfonts. As the licensing status +of these files is somewhat unclear, I'm leaving it up to you to download them. +Whatever you do, collect all these soundfonts (or file system links) in one +directory and edit the setting score_ui:soundfont_dir to point to this +directroy. The default directory is /usr/share/sounds/sf2, which is where +Debian based distros install their soundfonts. At the very least, you can do + + apt-get install fluid-soundfont-gm + +and get a working general midi soundfont, by selecting fluid_gm as your +fluidsynth initialisation file. + + +## MATLAB + +### General figure plotting service + +### Signal processing and other specific computations diff -r 000000000000 -r 718306e29690 cpack/dml/api/archive.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/archive.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,93 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(api_archive, [ locator_uri/2, with_input_from_uri/2, uri_absolute_path/2, archive_file/3, archive_file/2 ]). + +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(xmlarchive)). +:- use_module(library(httpfiles)). +:- use_module(library(fileutils)). +:- use_module(library(insist)). + +:- set_prolog_flag(double_quotes,string). +:- rdf_register_prefix(file,'file://'). +:- http_handler(api(archive/get), archive_get, []). +:- setting(archive:root,string,"~/lib/dml-archive","Directory containing accessible files"). + +user:file_search_path(archive,Path) :- setting(archive:root,DD), expand_file_name(DD,[Path]). + +archive_get(Request) :- + http_parameters(Request, [uri(URI, [optional(false), description("URI of archive entry")])]), + file_name_extension(_,Ext,URI), + with_input_from_uri(URI,reply_from_stream(Ext)). + +uri_absolute_path(URI,Path) :- var(Path), !, + insist(string_concat("file://",LocString,URI)), + absolute_file_name(archive(LocString),Path,[access(read)]). +uri_absolute_path(URI,Path) :- + file_search_path(archive,Root), + atom_concat(Root,Rel,Path), + atom_concat('file:/',Rel,URI). + +:- meta_predicate with_input_from_uri(+,1). +with_input_from_uri(URI,Goal) :- + insist(string_concat("file://",LocString,URI)), + ( sub_string(LocString,PathLen,1,FragLen,"#") + -> sub_string(LocString,0,PathLen,_,Path), + sub_atom(LocString,_,FragLen,0,Frag), + absolute_file_name(archive(Path),ArchivePath,[access(read)]), + with_archive_stream(ArchivePath,Frag,Goal) + ; absolute_file_name(archive(LocString),AbsPath,[access(read)]), + with_stream(S, open(AbsPath,read,S), call(Goal,S)) + ). + +reply_from_stream(Ext,Stream) :- reply_stream(Stream,Ext). + +locator_uri(file(Parts), URI) :- atomic_list_concat(['file:/'|Parts],'/',URI). +locator_uri(archive_entry(ArchivePath,EntryName), URI) :- + atomic_list_concat(['file://',ArchivePath,'#',EntryName],URI). + +%% archive_file(+Ext:atom, +In:path, -Out:uri) is det. +%% archive_file(+In:path,-Out:uri) is det. +% +% This procedure finds a permanent home for the file In, moving it into +% the directory tree managed by the archive, giving it a unique file name, +% and returning the URI of the location. +% +% !! could add extension if necessary +archive_file(In,Out) :- archive_file('',In,Out). +archive_file(Ext,In,Out) :- + get_time(Time), + format_time(atom(Dir),'auto/%Y%m%d',Time), + expand_file_search_path(archive(Dir),FullDir), + ( exists_directory(FullDir) -> true + ; make_directory(FullDir) + ), + once( ( repeat, random_name(Ext,8,Str), + directory_file_path(FullDir,Str,Path), + \+exists_file(Path) )), + rename_file(In,Path), + uri_absolute_path(Out,Path). + +random_name(Ext,Len,String) :- + length(Chars,Len), + maplist(web_storage:random_char,Chars), + format(string(String),'~s~s',[Chars,Ext]). + + diff -r 000000000000 -r 718306e29690 cpack/dml/api/dmlvis.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/dmlvis.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,717 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dmlvis, + [ cc/3 + , recording_property/3 + ]). + +/** DML Visualisation web service + */ + + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/thread_httpd)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(http/http_json)). +:- use_module(library(http/json)). +:- use_module(library(thread_pool)). +:- use_module(library(semweb/rdf_label)). +:- use_module(library(sandbox)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_pair)). +:- use_module(library(dcg_codes)). +:- use_module(library(dcg_macros)). +:- use_module(library(fileutils)). +:- use_module(library(listutils)). +:- use_module(library(optutils)). +:- use_module(library(swipe)). +:- use_module(library(memo)). +:- use_module(library(rdfutils)). +:- use_module(library(httpfiles)). +:- use_module(library(dataset)). +:- use_module(library(computations), [rows_cols/3]). +:- use_module(library(csvutils), [uri_to_csv/2]). +:- use_module(library(insist)). +:- use_module(library(lambda)). +:- use_module(library(dcg/basics), [string_without//2, integer//1]). +:- use_module(library(solution_sequences)). + +:- use_module(components(audio)). + +:- meta_predicate cc(2,2,1). +:- meta_predicate method_result_cc(+,+,2,1). + +:- set_prolog_flag(double_quotes,codes). +:- set_prolog_flag(back_quotes,string). + +http:location(v1,root(api/v4),[]). + +:- http_handler(v1(getCollectionId), getCollectionId, []). +:- http_handler(v1(getCollectionPerspective), getCollectionPerspective, []). +:- http_handler(v1(getRecordingPerspective), getRecordingPerspective, [spawn(vis_recording)]). +:- http_handler(v1(listCollections), listCollections, []). +:- http_handler(v1(listPlaces), listPlaces, []). +:- http_handler(v1(listPerspectives), listPerspectives, []). +:- http_handler(v1(csv_time_window), csv_time_window, []). + +% ------------------------------------------------------------------------------------ + +%% vis(+Method,+Request) is det. +% +% General VIS API HTTP handler. Returns either JSON or JSONP depending on the +% format parameter. If JSONP is selected (the default), the callback parameter +% determines the Javascript callback function. The JSON result structure is of +% type +% == +% { +% query: string ~'The original query, excluding protocol and host', +% result: (error_struct|A) ~'Result structure A or error information' +% } +% == +% where +% == +% error_struct == { code: integer, decs:string } +% == +% See individual methods for more information about their return types. +vis(Method,Request) :- + get_time(T0), + method_params(Method,Params), + member(request_uri(Query),Request), + vis_parameters(Request, [format(Format), callback(Callback) | Params],ROpts), + (Format=jsonp -> Fmt=jsonp(Callback,ROpts); Fmt=json(ROpts)), + Responder=send_response(Fmt,Query,T0), + debug(dmlvis(method),'~q',[method_result_cc(Method,Params,Responder,writeln)]), + method_result_cc(Method,Params,dmlvis:Responder,error_cont(Query,Responder)). + +send_response(Fmt,Query,T0,Result,Status) :- + get_time(T1), DT=T1-T0, + debug(dmlvis(response),'Sending response after ~3f s to ~q',[DT,Query]), + once(reply_as(Fmt,Status,_{ query:Query, result: Result})). + +error_cont(Q,Cont,Ex) :- + debug(dmlvis(error),'Sending error ~W in response to ~q',[Ex,[quoted(true),max_depth(8)],Q]), + error_result(Ex,Result), + call(Cont,Result,error). + +vis_parameters(Request,Params,ReplyOpts) :- + Params1=[random(_, [optional(true)]) | Params], + http_parameters(Request, Params1, [attribute_declarations(param), form_data(AllParams)]), + findall(N, (member(N=_,AllParams), \+used_param(N,Params1)), Unused), + (select(indent,Unused,Unused1) -> ReplyOpts=[]; ReplyOpts=[width(0)], Unused1=Unused), + (select(dv,Unused1,Unused2) -> true; Unused2=Unused1), + insist(Unused2=[], unrecognised_parameters(Unused2)). + +used_param(N,ValidParams) :- + member(Q,ValidParams), + functor(Q,N,_). + +% result_response(Fmt,Q,Result,Status,Response) :- +% with_output_to(string(Response), +% reply_as(Fmt,Status,_{ query:Q, result: Result})). + +reply_as(json(Opts),Status,Dict) :- !, + write_headers([Status,type(json)]), + json_write_dict(current_output, Dict, Opts). +reply_as(jsonp(Cb,Opts),Status,Dict) :- !, + write_headers([Status,type(jsonp)]), + write(Cb), write('('), + json_write_dict(current_output, Dict, Opts), + write(');'). + + +error_result(Ex, _{ errors:[Err] }) :- error_result1(Ex,Err). + +error_result1(dml_error(Code,Descriptor),_{ code: Code, desc:Descriptor }) :- !. + +error_result1(Ex, _{ code: 500, desc: Msg }) :- + message_to_string(Ex,Msg). + +% ------------------------------------------------------------------------------------ +% Handlers with documentation + +%% getCollectionId(+Request) is det. +% +% Define a collection satisfying given search terms. Result is a collection +% ID, which may be the same as a previously defined collection if it consists +% of the same items. +% +% Parameters are as follows. In all cases, =|sclist(Type)|= denotes a semicolon +% separated list of values of given type OR the string '*', which is the default. +% The value '*' means that no filtering is done on the releveant property. The +% list is interpreted as an AND-list or an OR-list depending on which property +% is being tested. String matching is case insensitive. +% The only required parameter is =|dv|=. +% == +% dv : integer ~ database version +% library : sclist(lib_name) ~ OR-list of libraries to search +% collection : sclist(pattern) ~ OR-list of BL collection name patterns +% composer : sclist(string) ~ OR-list of composer prefixes +% performer : sclist(string) ~ OR-list of performer prefixes +% title : sclist(string) ~ AND-list of title substrings +% genre : sclist(string) ~ OR-list of genre substrings +% place : sclist(string) ~ OR-list of place substrings +% language : sclist(string) ~ OR-list of langauage name prefixes +% year : sclist(year) | range ~ OR-list of genre substrings +% sample : nonneg | 'all' ~ sample a random subset of this size +% sv : integer ~ sample version for sample +% +% lib_name --> 'bl' | 'charm' | 'ilm' | 'mazurka' | 'beets'. +% range --> year, '-', year. +% == +% NB. A =|pattern|= is a string which may contain '*' to match any sequence of +% characters. The pattern must match the WHOLE value being tested, eg to search +% for the substring 'Botswana', you must include '*' at both ends of the pattern, +% eg =|'*botswana*'|=. +% +% A successful result is of type +% == +% result(getCollectionId) == { +% cid: string ~'collection id', +% size: natural ~'number of items in collection' +% }. +% == +getCollectionId(R) :- vis(getCollectionId,R). + +%% getCollectionPerspective(+Request) is det. +% +% Get a given perspective on a previously defined collection. +% Result will depend on the particular perspective chosen. +% All perspectives require the parameter =|cid(string)|=. Most +% perspectives accept the parameters =|recompute(oneof([none,failed,force]))|= +% and =|vamp_on_demand(boolean)|=. +% Defined perspectives are +% +% == +% summary : [] -> { cid:string, size: natural, goal: string }. +% +% list : +% [ limit(natural)/5000, offset(natural)/0, sort_by(oneof([label, date]))/label ] +% -> { cid:string, items: list( {uri:uri, label:string, audio:list(link(audio)), date:string }) }. +% +% midi_pitch_histogram : +% [ weighting(oneof([none,dur,vel]))/none ] +% -> { values:list(integer), counts:list(natural) }. +% +% pitch_histogram : +% [ weighting(oneof([none,dur,vel]))/none, quant(natural)/5, min(integer)/20, max(integer)/100, lang(oneof([ml,r]))/ml ] +% -> { edges:list(nonneg), counts:list(natural) }. +% +% tempo_histogram : +% [ period(nonneg)/1, min(integer)/20, max(integer)/100, num_bins(natural)/50, lang(oneof([ml,r]))/ml ] +% -> { edges:list(nonneg), counts:list(natural) }. +% +% mean_tempo_curve : +% [ num_samples(natural)/20, lang(oneof([ml,r]))/ml ] +% -> { means:list(nonneg), std_devs:list(nonneg) }. +% +% tonic_relative_pitch_class_histogram : [] +% -> { values:list(string), counts:list(nonneg), ok_count:natural, failed:{prolog:list, python:list}}. +% +% pitch_lookup : +% [ midi_pitch(between(0,127)), weighting(oneof([none,dur,vel]))/none, +% limit(natural)/5000, offset(natural)/0 ] +% -> { }. +% +% tonic_histogram : [] -> { }. +% +% pitch_class_histogram : [] -> { }. +% +% tuning_stats : [] -> { }. +% +% tuning_stats_by_year : [] -> { }. +% +% places_hist : [] -> { }. +% +% key_relative_chord_seq : +% [ spm_minlen(natural)/2, spm_maxseqs(natural)/500, spm_algorithm(Alg)/'CM-SPADE', +% spm_ignore_n(natural)/1, spm_maxtime(number)/60, spm_minsupport(number)/50 ] +% -> { }. +% +% similarity : +% [ sim_downsample(number)/1,sim_clusters(number)/40,sim_reclimit(number)/2000, +% sim_type(string)/'euclidean',sim_features(string)/'chromagram', +% sim_compressor(string)/'zlib'] +% -> { }. +% == +getCollectionPerspective(R) :- vis(getCollectionPerspective,R). + +%% getCollectionPairPerspective(+Request) is det. +% +% Get a given comparative perspective on a pair of previously defined collections. +% Result will depend on the particular perspective chosen. Defined perspectives are: +getCollectionPairPerspective(R) :- vis(getCollectionPairPerspective,R). + +%% getMultiCollectionPerspective(+Request) is det. +% Get a given comparative perspective on a set of previously defined collections. +getMultiCollectionPerspective(R) :- vis(getMultiCollectionPerspective,R). + +%% getRecordingPerspective(+Request) is det. +% Get a given perspective for a given recording URI. Perspectives, their parameters and +% their output types are as follows (all perspectives require a uri parameter) +% == +% properties : [] -> { +% library:string, +% title:string, +% composer:list(string), +% performer:list(string), +% genre:list(string), +% place:string, +% language:string, +% recording_date:string +% }. +% +% transcription : [] -> { csv: uri(csv([time,dur,freq,vel,pitch_name])) }. +% transcription_fine : [] -> { csv: uri(csv([time,dur,freq,vel,pitch_name)) }. +% chords : [] -> { csv: uri(csv([time,chord_name])) }. +% chords_notes : [] -> { csv: uri(csv([time,dur,integer)) }. +% key : [] -> { csv: uri(csv([time,integer,string])) }. +% key_tonic : [] -> { csv: uri(csv) }. +% tempo : [] -> { csv: uri(csv([time,nonneg,tempo_string])). +% beats : [] -> { csv: uri(csv([time,tempo_string])) }. +% beatroot : [] -> { csv: uri(csv([time])) }. +% +% tempo_nonuniform : [] -> { times:list(float), values:list(float) }. +% tempo_uniform : [ lang(oneof([ml,r]))/ml ] -> { times:list(float), values:list(float) }. +% tempo_normalised : [ lang(oneof([ml,r]))/ml ] -> { times:list(float), values:list(float) }. +% tempo_histogram : +% [ period(nonneg)/1, num_bins(natural)/50, min(nonneg)/20, max(nonneg)/100, lang(oneof([ml,r]))/ml ] +% -> { edges: list(float), counts: list(natural) }. +% +% midi_pitch_histogram : +% [ weighting(note_weight)/none ] +% -> { values: list(integer), counts: list(natural) }. +% +% pitch_histogram : +% [weighting(note_weight)/none, quant(natural)/5, min(integer)/20, max(integer)/100, lang(oneof([ml,r]))/ml ] +% -> { edges: list(float), counts: list(natural) }. +% +% chord_histogram : [] -> { values:list(string), counts:list(natural) }. +% +% spectrogram : [offset(nonneg)/0, length(nonneg)/60 ] -> { csv: uri }. +% == +% +% Supplementary types: +% == +% note_weight --> 'none'; 'dur'; 'vel'; 'dur*vel'. +% +% time == float. +% dur == nonneg. +% freq == nonneg. +% vel == nonneg. +% == +getRecordingPerspective(R) :- vis(getRecordingPerspective,R). + +%% listCollections(+Request) is det. +% Lists previously defined collections and the Prolog queries that define them. +% == +% listCollections : [] -> { +% collections: list({ cid : string, +% query : string, +% dv : integer, +% size : natural, +% timestamp : string +% }) +% }. +listCollections(R) :- vis(listCollections,R). + +%% listPlaces(+Request) is det. +% Lists known place names, currently the distinct values of the dcterms:spatial predicate. +% == +% listPlaces : [] -> { +% places: list({ name : string +% }) +% }. +listPlaces(R) :- vis(listPlaces,R). + +%% listPerspectives(+Request) is det. +% Lists available perspective for a given method. +listPerspectives(R) :- vis(listPerspectives,R). + +%% csv_time_window(+Request) is det. +% +% Returns the contents of a CSV file between between given time limits, +% assuming the the first column is a time value. +% Also returns the time of the last row. Parameters and return structure are +% == +% csv_time_window : +% [uri(uri(csv)), start(float), end(float) ] +% -> { duration:float, columns: list(list) }. +% == +% URI parameter must be the URI of a CSV file. +% Data is returned a list of lists, where each inner list is one column +% of the CSV. +csv_time_window(R) :- vis(csv_time_window,R). + + +% ------------------------------------------------------------------------------------ +% Implementation of methods + +:- multifile param/2. + +param( format, [oneof([json,jsonp]), default(jsonp), description('Reply format')]). +param( callback, [atom,default(jsonp_cb), description('Callback for jsonp reply')]). +param( dv, [nonneg, optional(false), description('Database version ID')]). + +param( cid, [atom, optional(false), description('Collection ID')]). +param( pid, [atom, optional(false), description('Perspective ID')]). +param( cids, [atom, optional(false), description('Semicolon separated list of Collection IDs')]). +param( uri, [atom, optional(false), description('Item URI')]). +param( library, [atom, default(*), description('Semicolon separated list of libraries to search')]). +param( genre, [atom, default(*), description('Semicolon separated list of genre names, or "*"')]). +param( year, [atom, default(*), description('Semicolon separeted list of release years or a range (Y1-Y2) or "*"')]). +param( composer, [atom, default(*), description('Semicolon separated list of composers or "*"')]). +param( performer, [atom, default(*), description('Semicolon separated list of performers or "*"')]). +param( place, [atom, default(*), description('Semicolon separated list of place names or "*"')]). +param( language, [atom, default(*), description('Semicolon separated list of language name prefixes or "*"')]). +param( collection,[atom, default(*), description('Semicolon separated list of BL collection names or "*"')]). +param( title, [atom, default(*), description('Semicolon separated AND-list of title substrings or "*"')]). +param( method, [atom, optional(false), description('API method name')]). +param( limit, [integer, default(5000), description('Maximum number of things to return')]). +param( offset, [integer, default(0), description('Offset within list')]). +param( sort_by, [oneof([label,date]), default(label), description('Sort recordings list by this property')]). +param( start, [number, optional(false), description('Start of window in seconds')]). +param( end, [number, optional(false), description('End of window in seconds')]). +param( sample, [number, default(all), description('Sample a random subset of this size')]). +param( sv, [number, default(1), description('Version of random subset')]). +param( midi_pitch,[nonneg, default(60), description('MIDI note number 0..127')]). + +method_params(listCollections, []). +method_params(listPlaces, []). +method_params(listPerspectives, [ method(_) ]). +method_params(getCollectionId, [ dv(_), library(_), genre(_), place(_), language(_), year(_), composer(_), + performer(_), collection(_), title(_), sample(_), sv(_) ]). +method_params(csv_time_window, [ uri(_), start(_), end(_) ]). +method_params(Method, [ pid(_) | Params ]) :- + once(perspective(Method,_)), + setof(P, perspective_param_name(Method,P), Ps), + maplist(param_name_term,Ps,Params). + +param_name_term(Name,Term) :- functor(Term,Name,1). +perspective_param_name(Method,Name) :- + perspective(Method,_,Specs,_), + member(S,Specs), + optspec_name(S,Name). + + +:- multifile perspective/4. + +%% cc(+Pred:pred(-A,-cc_status), +Cont:pred(+A,+cc_status), +ErrorCont:pred(+exception)) is det. +% Call a predicate with success and error continuations. +% Pred roduces a result of type A and a status. If it succeeds, the result and status are passed +% to the continuation Cont. Otherwise, an exception is passed to ErrorCont. +cc(Goal,Cont,ErrorCont) :- catch(cc_wrapper(Goal,Cont), Ex, call(ErrorCont,Ex)). +cc_wrapper(Goal,Cont) :- insist(call(Goal,Result,Status)), call(Cont,Result,Status). + +place_name(P) :- rdf(_,dcterms:spatial,literal(P)). + +%% method_result_cc(+Method,+Params:options,+C:success_cont,+E:error_cont) is det. +% +% Perspectives are handle using continuations to allow spawning +% == +% success_cont == pred(+dict,+vis_status). +% error_cont == pred(+exception). +% vis_status ---> stable; unstable. +% == +% Method must be a method id registered in perspective/2 or handled my method_resut/4. +method_result_cc(Method,Params,Cont,ErrorCont) :- + perspective(Method,_), !, + option(pid(PId),Params), + catch(( insist( perspective(Method,PId,Specs,Pred), unknown_perspective(PId)), + insist( maplist(options_optspec(Params),Specs)), + call(Pred,Cont,ErrorCont) + ), Ex, call(ErrorCont,Ex)). + +% all non-perspective methods are handled in this thread +method_result_cc(Method,Params,Cont,ErrorCont) :- + cc( method_result(Method,Params), Cont, ErrorCont). + +%% method_result(+Method, +Opts, -Result, -Status:vis_status) is det. +% +% Handles methods =|listCollections, listPerspectives, getCollectionId, csv_time_window|=. +method_result(listCollections, _, _{ collections:List }, unstable) :- + findall( _{ cid:Id, query:QA, dv:DV, size:SZ, timestamp:TS }, + ( browse(dataset:dataset(dmlvis:Q, DV, Id, SZ, _),comp(_,Timestamp,_)-ok), + format_time(string(TS),'%FT%T%:z',Timestamp), + term_to_atom(Q,QA) + ), + List). + +method_result(listPlaces, _, _{ places:List }, unstable) :- + findall( _{ name:Name, count:N }, aggregate(count,place_name(Name),N), List). + + +method_result(listPerspectives, Opts, _{ perspectives:List }, stable) :- + option(method(Method), Opts), + findall( P, perspective(Method,P), List). + +method_result(getCollectionId, Opts, _{ cid:Id, size:Size, full_size:FullSize }, stable) :- + build_dataset_query(Query,DBV,Size-FullSize,Opts,Remaining), + insist(Remaining=[], unrecognised_search_criteria(Remaining)), + insist(dataset_query_id( Query, DBV, Id),empty_dataset(Query)), + dataset_size(Id, Size). + +method_result(csv_time_window, Opts, _{ duration:Dur, columns:Columns }, stable) :- + maplist(options_optspec(Opts), [ \uri(URI), \start(Start), \end(End) ]), + uri_to_csv(URI,Rows), + insist(Rows\=[], empty_csv(URI)), + + append(_,[EndRow],Rows), + functor(EndRow,_,NumCols), + arg(1,EndRow,Dur), + + numlist(1,NumCols,Is), + drop_while(row_before(Start),Rows,Rows1), + take_while(row_before(End),Rows1,Rows2), + rows_cols(Is,Rows2,Columns). + +row_before(T0,Row) :- arg(1,Row,T), TGoal) :- options_optspec(M,Opts,O), call(M:Goal). + +optspec_name(+O,Name) :- functor(O,Name,1). +optspec_name(O-_,Name) :- functor(O,Name,1). +% optspec_name(O>_,Name) :- optspec_name(O,Name). + +perspective(Method,Perspective) :- perspective(Method,Perspective,_,_). + +perspective(getRecordingPerspective, properties, [+uri(URI)], cc(recording_info(URI))). +perspective(getCollectionPerspective, summary, [+cid(C)], cc(collection_summary(C))). +perspective(getCollectionPerspective, list, [+cid(C),limit(Lim)-5000,offset(Off)-0,sort_by(SortBy)-label], cc(collection_list(C,Lim,Off,SortBy))). + +collection_summary(Id,Result,stable) :- + insist(dataset_size(Id,Size), unknown_collection(Id)), + findall( _{goal:GoalA, dv:DV}, ( dataset_query_dv(Id,Goal,DV), + term_to_atom(Goal,GoalA) ), Queries), + Result = _{cid:Id, size:Size, queries:Queries }. + + +collection_list(Id, Lim, Offset, SortBy, _{cid:Id, size:Size, items:Items}, stable) :- + insist(dataset_size(Id,Size), unknown_collection(Id)), + findall(SortVal-Item, dataset_itemx(SortBy,Id,Item,SortVal), KeyedItems), sort(KeyedItems,Sorted), + findall(Item,limit(Lim,offset(Offset,member(_-Item,Sorted))),Items). + +dataset_itemx(SortProp, Id, Itemx, SortVal) :- + dataset_item(Id,URI), + filter(Lib,URI,in_library), + findall(Prop:Val, ( member(Prop,[label,audio,date]), + recording_property(URI,Lib,Prop,Val) ), Props), + (member(SortProp:Val,Props) -> SortVal=just(Val); SortVal=nothing), + dict_create(Itemx,_,[uri:URI | Props]). + + +recording_info(URI, Result, stable) :- + insist(filter(Lib,URI,in_library),unknown_recording(URI)), + findall(Prop:Val, recording_property(URI,Lib,Prop,Val), Props), + dict_create(Result,_,[ library:Lib | Props ]). + +recording_property(URI,Prop,Val) :- + filter(Lib,URI,in_library), + recording_property(URI,Lib,Prop,Val). + +recording_property(URI,_,label,Label) :- + rdf_display_label(URI,Label). +recording_property(URI,_,audio,Links) :- + % !!! HACK: force scraping for BL items here.. + % DISABLED - seems to upset BL server... + % (rdf(URI,dml:blpage,_) -> once(bl_p2r:scrape_audio_link(URI,_)); true), + setof(L,F^audio_link(URI,L,F),Links). +recording_property(URI,Lib,Prop,Val) :- + lib_property_read(Lib, Prop, Reader), + pred_values(URI,Lib:Prop,Reader,Val). + + +pred_values(URI,Lib:Prop,-Converter,Val) :- + lib_property(Lib,Prop,Pred), + once(rdf(URI,Pred,Obj)), + call(Converter,Obj,Val). +pred_values(URI,LibProp,+Converter,Vals) :- + findall(Val, pred_values(URI,LibProp,-Converter,Val), Vals). + +lib_property_read(_, collection, -literal_text). +lib_property_read(_, composer, +literal_text). +lib_property_read(_, performer, +literal_text). +lib_property_read(_, title, -literal_text). +lib_property_read(_, date, -literal_text). +lib_property_read(_, place, -literal_text). +lib_property_read(_, language, +literal_text). +lib_property_read(ilm, genre, +genre_label). + +genre_label(Genre,Label) :- + rdf(Genre,rdfs:label,Lit), + literal_text(Lit,Label). + +% ------------------- DEFINING NEW COLLECTIONS ----------------------- + +build_dataset_query(Query,DBV,Size-FullSize) --> + select_option(dv(DBV)), + select_option(sample(Subset)), + select_option(sv(SV)), + full_query(FQ), + { Subset=all -> Query=FQ, Size=FullSize + ; Query=sample(Subset,SV,FQ), + aggregate_all(count,call(FQ,_),FullSize) + }. + +full_query(qc(Filters)) --> + run_left(seqmap(process_qopt, + [ qo( library, atoms(LS), libraries(LS)) + , qo( collection, atoms(CC), any(collection,CC)) + , qo( title, atoms(TS), all(title,TS)) + , qo( composer, atoms(CS), any(composer,CS)) + , qo( performer, atoms(PS), any(performer,PS)) + , qo( genre, atoms(GS), any(genre,GS)) + , qo( year, years(YS), year(YS)) + , qo( place, atoms(PS), any(place,PS)) + , qo( language, atoms(LNS), any(language,LNS)) + ]), Filters, []). + +process_qopt(qo(OptName,Parser,Filter)) --> + { Opt=..[OptName,OptVal] }, + \> option_default_select(Opt,'*'), + ( {OptVal='*'} -> [] + ; {parse_atom(Parser,OptVal)}, + \< [Filter] + ). + +sample(Size,_,Query,X) :- + setof(X, call(Query,X), All), + length(All,Total), + ( Total= Subset=All + ; randset(Size, Total, All, [], Subset) + ), + member(X,Subset). + +randset(0, _, _) --> !. +randset(K, N, [A|As]) --> + ({random(N)>=K} -> {K1=K}; {K1 is K-1}, cons(A)), + {N1 is N-1}, randset(K1,N1,As). + + +qc(Filters,X) :- maplist(filter(Lib,X),Filters), filter(Lib,X,in_library). + +%% lib_property(-Library, -Property, -Predicate) is nondet. +% +% This predicate manages the mapping from API search fields to RDF +% predicates. There are still some questions about: +% +% $ composer : marcrel cmp, arr, lyr +% $ performer : marcrel prf, sng, cnd, drt +:- rdf_meta lib_property(?,+,r). +lib_property(bl, collection, dcterms:isPartOf). +lib_property(bl, language, dcterms:language). +lib_property(bl, language, dc:language). +lib_property(bl, place, dcterms:spatial). +lib_property(ilm, genre, mo:genre). + +% lib_property(beets, date, beets:original_year). +lib_property(ilm, date, ilm:release_date). +lib_property(charm, date, charm:recording_date). +lib_property(mazurka, date, mazurka:recording_date). +lib_property(bl, date, dcterms:created). + +lib_property(charm, composer, charm:composer). +lib_property(mazurka, composer, mazurka:composer). +lib_property(bl, composer, marcrel:cmp). +lib_property(bl, composer, marcrel:arr). +lib_property(beets, composer, beets:composer). + +lib_property(charm, performer, charm:performer). +lib_property(mazurka, performer, mazurka:performer). +lib_property(bl, performer, marcrel:prf). +lib_property(bl, performer, marcrel:sng). +lib_property(beets, performer, beets:artist). +lib_property(ilm, performer, ilm:arist). + +lib_property(charm, title, charm:title). +lib_property(mazurka, title, mazurka:title). +lib_property(bl, title, dc:title). +lib_property(beets, title, beets:title). +lib_property(ilm, title, dc:title). + +lib_property_search(_,collection,X, substring(X)). +lib_property_search(_,place, X, substring(X)). +lib_property_search(_,language, X, prefix(X)). +lib_property_search(_,composer, X, prefix(X)). +lib_property_search(_,performer, X, prefix(X)). +lib_property_search(_,title, X, substring(X)). +lib_property_search(beets, date, L-U, between(L,U1)) :- succ(U,U1). +lib_property_search(_Lib, date, L-U, between(LA,U1A)) :- + % Lib\=beets, + succ(U,U1), + atom_number(LA,L), + atom_number(U1A,U1). + +%% filter(+Lib, -Resource, +SearchSpec) is nondet. +filter(Lib, _, libraries(Ls)) :- member(Lib,Ls). +filter(Lib, X, any(Prop,Vals)) :- member(Val,Vals), filter(Lib,X,Prop,Val). +filter(Lib, X, all(Prop,Vals)) :- maplist(filter(Lib,X,Prop),Vals). +filter(Lib, X, year(any(Ys))) :- member(Y,Ys), filter(Lib,X,date,Y-Y). +filter(Lib, X, year(L-U)) :- filter(Lib,X,date,L-U). +filter(Lib, X, Prop-Val) :- filter(Lib,X,Prop,Val). + +filter(charm, X, in_library) :- rdf(X,charm:file_name,_,charm_p2r). +filter(mazurka, X, in_library) :- rdf(X,mazurka:pid,_,mazurka_p2r). +filter(bl, X, in_library) :- rdf(X,rdf:type,mo:'Signal',bl_p2r). +filter(ilm, X, in_library) :- rdf(X,mo:track_number,_,ilm_p2r). +filter(beets, X, in_library) :- rdf(X,rdf:type,mo:'AudioFile',beets_p2r). + +%% filter(+Lib, -Resource, +Property, +Value) is nondet. + +% filter(beets, X,genre,G) :- rdf_has(X,beets:genre,literal(substring(G),_)). +filter(ilm, X,genre,G) :- + rdf(GR,rdfs:label,literal(substring(G),_),ilm_p2r), + rdf(GR,rdf:type,mo:'Genre',ilm_p2r), + rdf(X,mo:genre,GR). + +filter(Lib, X, Prop, Val) :- + lib_property(Lib,Prop,Pred), + lib_property_search(Lib,Prop,Val,Search), + rdf(X,Pred,literal(Search,_)). + +% --------- parsers ----------- + +% cids(Ids) --> seqmap_with_sep(",",alphanum,Ids). +cids(Ids) --> semicolon_sep(atom_codes,Ids). + +% atoms('*') --> "*", !. +atoms(AS) --> semicolon_sep(atom_codes,AS1), {maplist(downcase_atom,AS1,AS2),sort(AS2,AS)}. +whole(A) --> string_without("",Codes), {atom_codes(A1,Codes), downcase_atom(A1,A)}. + +% years('*') --> "*", !. +years(L-U) --> integer(L), "-", integer(U). +years(any(Ys)) --> semicolon_sep(number_codes,Ys1), {sort(Ys1,Ys)}. + +% alphanum(X) --> string_without(",",S), {atom_string(X,S)}. + +item(Conv,Item) --> string_without(";",Codes), {call(Conv,Item,Codes)}. +semicolon_sep(Conv,Items) --> + seqmap_with_sep(";",item(Conv),Items). + + +parse_atom(Phrase,Atom) :- + atom_codes(Atom,Codes), + insist( phrase(Phrase,Codes), parse_failure(Phrase)). + +thread_pool:create_pool(vis_recording) :- + current_prolog_flag(cpu_count,N), + thread_pool_create(vis_recording, N, [backlog(50)]). diff -r 000000000000 -r 718306e29690 cpack/dml/api/matlab.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/matlab.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,104 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(api_matlab, []). + +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(sandbox)). +:- use_module(library(insist)). +:- use_module(library(fileutils)). +:- use_module(library(swipe)). +:- use_module(library(httpfiles)). +:- use_module(library(mlserver)). + +:- set_prolog_flag(double_quotes,string). +:- set_prolog_flag(back_quotes,symbol_char). + +:- http_handler(api(matlab/render), figure_render, []). + +:- setting(matlab:pixels_per_inch,number,150,"Pixels per inch for in browser figures"). +:- setting(matlab:default_figure_format,oneof([png,svg]),svg,"Default Matlab figure rendering method"). + +:- initialization catch(mutex_create(_,[alias(matlab_fig)]),Ex,print_message(warning,Ex)). + +%% figure_render(+Request) is det. +% +% HTTP handler for rendering Matlab figures. +figure_render(Request) :- + setting(matlab:pixels_per_inch,DefPPI), + http_parameters(Request, + [ code(CodeA,[ atom, optional(false), description("Prolog rendering goal")]) + , format(F, [ oneof([eps,svg,pdf,png]), optional(false), description("Output format") ]) + , width(W, [ number, optional(true), default(10), description("Width in cm")]) + , height(H, [ number, optional(true), default(6), description("Height in cm")]) + , color_map(CMA, [ atom, optional(true), default(hot) ]) + , font_name(FN, [ atom, optional(true), default(helvetica) ]) + , font_size(FS, [ number, optional(true), default(8) ]) + , line_width(LW, [ number, optional(true), default(0.75) ]) + , marker_size(MS,[ number, optional(true), default(4) ]) + , ppi(PPI, [ number, optional(true), default(DefPPI), description("PNG resolution")]) + ]), + debug(matlab,"Attempting to parse \"~s\".",[CodeA]), + atom_to_term(CodeA,Code,[]), + atom_to_term(CMA,CM,[]), + ( user_db:logged_on(A) + -> debug(matlab,"Logged on as ~w, no checking",[A]) + ; debug(matlab,"Checking ~q for safety...",[Code]), + sandbox:safe_goal(Code), + debug(matlab,"Goal is safe.",[]) + ), + insist(with_temp_dir(Dir, ( + render(F,Code,Dir, [ size(W,H), ppi(PPI),color_map(CM),line_width(LW) + , font_name(FN),font_size(FS),marker_size(MS) ]), + atom_concat('tmp_.',F,Out), + absolute_file_name(Dir/Out,File), + reply_file(File,F) + ))). + + +render(eps,Code,D,Opts) :- with_mutex(matlab_fig,print_fig(Code,D,Opts,'-depsc2')). +render(pdf,Code,D,Opts) :- render(eps,Code,D,Opts), run(in(D,sh(0>>0, "epstopdf tmp_.eps"))). +render(svg,Code,D,Opts) :- render(pdf,Code,D,Opts), run(in(D,sh(0>>0, "pdf2svg tmp_.pdf tmp_.svg"))). +render(png,Code,D,Opts) :- + render(eps,Code,D,Opts), + option(ppi(PPI),Opts), + run(in(D,sh(0>>0, "gs -dBATCH -dNumRenderingThreads=2 -dEPSCrop -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=tmp_.png -r~d -q tmp_.eps",[\PPI]))). + +render_fig(Code,Opts) :- + option(color_map(ColorMap),Opts), + option(font_name(FontName),Opts), + option(font_size(FontSize),Opts), + option(line_width(LineWidth),Opts), + option(marker_size(MarkerSize),Opts), + option(colour(Colour),Opts,1), + option(axes_line_width_ratio(LWR),Opts,0.5), + option(figure(Fig),Opts,99), + ml_async(exec( dml_paperfig(Fig,`FontName,FontSize,LineWidth,Colour,MarkerSize,LWR); + colormap(ColorMap)),20), + debug(matlab,'Calling: ~q',[Code]), + with_output_to(string(_),call(Code)). + +print_fig(Code,Dir,Opts,PrintOpt) :- + render_fig(Code,Opts), + debug(matlab,'Saving figure to ~w',[Dir]), + absolute_file_name(Dir/'tmp_',Name), + ( option(size(Width,Height),Opts) + -> ml_async(exec(dml_fsetup(Width,Height,`centimeters)),20) + ; true), + ml_async(exec(print(`PrintOpt,`Name)),120). diff -r 000000000000 -r 718306e29690 cpack/dml/api/perspectives.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/perspectives.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,542 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(perspectives, []). + +/** VIS API Perspectives + + Todo + + - Chord sequences + - Standardise data structures +*/ +:- use_module(library(http/http_dispatch), [http_link_to_id/3]). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_label)). +:- use_module(library(dcg_core)). +:- use_module(library(insist)). +:- use_module(library(computations)). +:- use_module(library(backend_json)). +:- use_module(library(dataset)). +:- use_module(library(memo)). +:- use_module(library(async)). +:- use_module(library(mlserver)). +:- use_module(api(dmlvis)). +:- use_module(api(archive)). + +% :- setting(memoise_failures,boolean,false,"Whether or not to record failed computations to avoid retrying"). +:- setting(default_recompute_policy,oneof([none,failed,force]),none,'Default policy on recomputing memoised computations'). +:- setting(default_vamp_on_demand,boolean,false,'Default policy on doing VAMP computations on demand'). + +% registry of perspectives. +dmlvis:perspective( getRecordingPerspective, Name, + [+uri(URI),vamp_on_demand(V)-false|Params], + cc(perspectives:rla(Pred,[vamp_on_demand(V)],URI)) + ) :- rec_persp(Name, Params, Pred). + +dmlvis:perspective( getCollectionPerspective, Name, + [+cid(CID),recompute(R)-none,vamp_on_demand(V)-false,coverage(C)-summary|Params], + cc(perspectives:cla(Pred,[recompute(R),vamp_on_demand(V),coverage(C)],CID)) + ) :- coll_persp(Name, Params, Pred). + +:- meta_predicate rla(2,+,+,-,-), cla(2,+,+,-,-). + +rla(Pred,Opts,URI,Result,stable) :- + option(vamp_on_demand(V), Opts, false), + with_global(vamp_on_demand, V, call(Pred,URI,Result)). + +cla(Pred,Opts,CID,Result,stable) :- + check_collection(CID), + call(Pred,Opts,CID,Result1), + option(coverage(Cov),Opts,full), + insist(filter_coverage(Cov,Result1,Result), invalid_coverage_parameter(Cov)). + +:- op(1050,xfy,=>). +G1 => G2 --> (call_dcg(G1) -> call_dcg(G2); []). + +filter_coverage(full) --> []. +filter_coverage(summary) --> dtrans(coverage,C1,C2) => {summarise_coverage(C1,C2)}. +summarise_coverage --> foldl(replace_list_with_length,[failed,errors],[failed_count,errors_count]). +replace_list_with_length(Key) --> dtrans(Key,List,Length) => {length(List,Length)}. +replace_list_with_length(Key1,Key2) --> ddel(Key1,List) => {length(List,Len)}, dput(Key2,Len). +dtrans(Key,Val1,Val2,D1,D2) :- get_dict(Key,D1,Val1,D2,Val2). +ddel(Key,Val,D1,D2) :- del_dict(Key,D1,Val,D2). +dput(Key,Val,D1,D2) :- put_dict(Key,D1,Val,D2). +% dget(Key,Val,D,D) :- get_dict(Key,D,Val). + +check_collection(CID) :- + insist(dataset_size(CID,Size), unknown_collection(CID)), + debug(dmlvis(perspective),'Doing collection level analysis on ~d items.',[Size]). + +rec_persp( transcription, [], output_link(transcription(0))). +rec_persp( transcription_fine, [], output_link(transcription(1))). +rec_persp( chords, [], output_link(chords)). +rec_persp( chord_notes, [], output_link(chord_notes)). +rec_persp( beatroot, [], output_link(beats(beatroot))). +rec_persp( key, [], output_link(key)). +rec_persp( key_tonic, [], output_link(tonic)). +rec_persp( beats, [], output_link(beats(qm))). +rec_persp( tempo, [], output_link(tempo)). +rec_persp( chromagram, [], output_link(chromagram)). +rec_persp( mfcc, [], output_link(mfcc)). + +rec_persp( spectrogram, [offset(O)-0,length(L)-60], spectrogram_link(O,L)). +rec_persp( tempo_nonuniform, [], nonuniform_tempo). +rec_persp( tempo_uniform, [period(DT)-1,lang(L)-ml ], uniform_tempo(L,DT)). +rec_persp( tempo_normalised, [num_samples(N)-20,lang(L)-ml ], normalised_tempo(L,N)). +rec_persp( chord_histogram, [], chord_histogram). +rec_persp( midi_pitch_histogram, [weighting(W)-none], pitch_histogram(W)). +rec_persp( pitch_histogram, [weighting(W)-none, quant(Q)-5, min(Min)-0, max(Max)-127, lang(L)-ml ], + freq_histogram(L,Min,Max,Q,W)). +rec_persp( tempo_histogram, [period(DT)-1, num_bins(N)-50, min(Min)-20, max(Max)-360, lang(L)-ml ], + tempo_histogram(L,DT,Min,Max,N)). + +%% coll_persp(P:perspective(A), Params:list(param), Pred:pred(+options,+dataset,-A)) is nondet. +% +% Database of collection perspectives. The first argument is an atom denoting a perspective +% which returns results of type A. Params must be defined as in dmlvis:options_optspec/2. +% Pred must accept a list of options and a collection (dataset) id and produce a result. +coll_persp( mean_tempo_curve, [num_samples(N)-20,lang(L)-ml], mem(collection_tempo_curve(L,N))). +coll_persp( midi_pitch_histogram, [weighting(W)-none], mem(collection_pitch_histogram(W))). +coll_persp( pitch_histogram, [weighting(W)-none, quant(Q)-5, min(Min)-20, max(Max)-100, lang(L)-ml], + mem(collection_freq_histogram(L,Min,Max,Q,W))). +coll_persp( tempo_histogram, [period(DT)-1, num_bins(N)-50, min(Min)-20, max(Max)-100, lang(L)-ml], + mem(collection_tempo_histogram(L,DT,Min,Max,N))). +coll_persp( pitch_lookup, [+midi_pitch(P), weighting(W)-none, limit(Lim)-5000,offset(Off)-0], + nomem(collection_pitch_lookup(W,P,Lim,Off))). + +% using python back-end +coll_persp( tonic_relative_pitch_class_histogram, [], + mem(py_hist(transcription_tonic_duration, tonic_norm_semitone_hist:aggregate, [opts{normalisation:piece}]))). +coll_persp( tonic_histogram, [], mem(py_hist(tagged(tonic), key_tonic_hist:aggregate, []))). +coll_persp( pitch_class_histogram, [], mem(py_hist(tagged(transcription), semitone_hist:aggregate, []))). +coll_persp( tuning_stats, [], mem(py_cla(tagged(transcription(1)),tuning_stats:per_file,[]))). +coll_persp( tuning_stats_by_year, [], mem(py_cla(transcription_date,tuning_stats_byyear:per_file,[]))). +coll_persp( places_hist, [], nomem(py_cla(list_places,places_hist:per_file,[]))). +coll_persp( key_relative_chord_seq, + [ spm_minlen(MinLen)-2, spm_maxseqs(MaxSeqs)-500, spm_algorithm(Alg)-'CM-SPADE', + spm_ignore_n(Ignn)-1, spm_maxtime(Smaxt)-60, spm_minsupport(Smins)-50 ], + mem(py_cla( keys_chords,chord_seq_key_relative:aggregate, + [opts{ spm_minlen:MinLen, spm_maxseqs:MaxSeqs, spm_algorithm:Alg, + spm_ignore_n:Ignn,spm_maxtime:Smaxt,spm_minsupport:Smins } ]))). + +coll_persp( similarity, + [ sim_downsample(SimDown)-1,sim_clusters(SimClusters)-40,sim_reclimit(Limo)-2000, + sim_type(SimType)-'euclidean',sim_features(SimFeat)-'chromagram', + sim_compressor(SimComp)-'zlib'], + mem(py_cla(similarity_bundle,similarity:per_file, + [opts{sim_type:SimType,sim_clusters:SimClusters,sim_downsample:SimDown, + sim_reclimit:Limo,sim_features:SimFeat,sim_compressor:SimComp}]))). + +% adaptor to ignore collection perspective options parameter +nomem(Goal,Opts,CID,Result) :- + option(vamp_on_demand(V), Opts, false), + with_global(vamp_on_demand, V, + with_progress_stack(call(Goal,CID,Result))). + +dmlvis:param( recompute, [oneof([none,failed,force]), default(Def), + description('Controls handling of memoised collection level results')]) :- + setting(default_recompute_policy,Def). +dmlvis:param( vamp_on_demand, [boolean, default(Def), + description('Whether to run VAMP plugins if results are not already available')]) :- + setting(default_vamp_on_demand,Def). +dmlvis:param( coverage, [oneof([full,summary]), default(summary), + description('How much detail to provide about recordings not successfully included in CLA')]). +dmlvis:param( offset, [number, default(0), description('Offset into signal in seconds')]). +dmlvis:param( length, [number, default(60), description('Length of signal extract in seconds')]). +dmlvis:param( weighting, [oneof([none,dur,vel]), default(none), description('Weighting for pitch_histogram perspective')]). +dmlvis:param( quant, [nonneg, default(5), description('Subdivisions of a semitone for freq_histogram')]). +dmlvis:param( period, [number, default(1), description('Sampling period in seconds')]). +dmlvis:param( num_bins, [nonneg, default(50), description('Number of bins for histogram')]). +dmlvis:param( num_samples, [nonneg, default(50), description('Number of samples for normalised histogram')]). +dmlvis:param( max, [nonneg, default(100), description('Max pitch for pitch histogram')]). +dmlvis:param( min, [nonneg, default(20), description('Min pitch for pitch histogram')]). +dmlvis:param( lang, [oneof([ml,r]), default(r), description('Numerical computations language')]). + +/* chord sequence parameters */ +dmlvis:param( spm_minlen, [nonneg, default(2), description('Minimum length of chord sequence')]). +dmlvis:param( spm_maxseqs, [nonneg, default(500), description('Maximum number of sequences to return')]). +dmlvis:param( spm_algorithm, [atom, default('CM-SPADE'), description('CM-SPADE, TKS or ClaSP')]). +dmlvis:param( spm_ignore_n, [nonneg, default(1), description('Ignore failed chord detections')]). +dmlvis:param( spm_maxtime, [nonneg, default(60), description('Max. runtime for SPM algorithm')]). +dmlvis:param( spm_minsupport, [nonneg, default(50), description('Minimal Support in Percent')]). + + +/* similarity parameters */ +dmlvis:param( sim_type, [atom, default('euclidean'), description('Tpye of similarity measure: euclidean, compression')]). +dmlvis:param( sim_clusters, [nonneg, default(40), description('Number of clusters for vector Quantisation (40-200)')]). +dmlvis:param( sim_downsample, [nonneg, default(1), description('Downsample the audio analysis to a resolution of 1 second')]). +dmlvis:param( sim_reclimit, [nonneg, default(2000), description('Maximum number of recordings in dataset')]). +dmlvis:param( sim_features, [atom, default('chromagram'), description('Feature basis of the similarity estimation, any combination, separated by comma: chromagram,mfcc,chords')]). +dmlvis:param( sim_compressor, [atom, default('zlib'), description('Compressor for similarity estimation: zlib, zxd')]). + + +:- rdf_meta transform_computation(+,r,r). +transform_computation(Class,In,Out) :- + ( transform(Class,Fn), computation(Fn,In,Out) *-> true + ; ( nb_current(vamp_on_demand,true) + -> insist(transform(Class,Fn), unrecognised_transform_class(Class)), % picks first match + format(string(Desc),"Running computation ~w on ~w.",[Fn,In]), + simple_task(Desc,computation_memo(Fn,In,Out)) + ; throw(missing_computation(Class,In)) + ) + ). + +:- rdf_meta transform_op(+,+,r,-). +transform_op(TName,Op,In,Out) :- + transform_computation(TName,In,X), + csv_op(Op,X,Out). + +% ------- recording level perspectives ------------ + +spectrogram_link(Offs,Len,URI,_{image_url:Link}) :- + http_link_to_id(spectrogram_window, [uri(URI), offset(Offs), length(Len)], Link). + +output_link(TransformName,Input,_{csv:Output}) :- + transform_computation(TransformName,Input,Output). + +chord_histogram(URI,_{values:Chords, counts:Counts}) :- + transform_op(chords,chord_hist,URI,Hist), + unzip(Hist,Chords,Counts). + +pitch_histogram(W,URI,_{values:NNs, counts:Counts}) :- + transform_op(transcription,pitch_hist(W),URI,Hist), + unzip(Hist,NNs,Counts). + +freq_histogram(ml,Min,Max,Q,W,URI,_{edges:Edges, counts:Counts}) :- + microtone_map(Min,Max,Q,Map), + transform_op(transcription(1),freq_hist(Map,W),URI,Counts), + map_edges(ml,Map,Edges). +freq_histogram(r,Min,Max,Q,W,URI,_{edges:Edges, counts:Counts}) :- + microtone_map(Min,Max,Q,Map), + transform_op(transcription(1),freq_hist_r(Map,W),URI,Counts), + map_edges(r,Map,Edges). + +nonuniform_tempo(URI,_{times:Times, values:Values}) :- + transform_op(tempo,tempo,URI,Result), + unzip(Result,Times,Values). + +uniform_tempo(ml,DT,URI,_{times:Times, values:Values}) :- + transform_op(tempo,uniform_tempo(DT),URI,Result), + Result=Times-Values. + +uniform_tempo(r,DT,URI,_{times:Times, values:Values}) :- + transform_op(tempo,uniform_tempo_r(DT),URI,Result), + Result=Times-Values. + +normalised_tempo(ml,N,URI,_{times:Times, values:Values}) :- + transform_op(tempo,normalised_tempo(N),URI,Result), + Result=Times-Values. + +normalised_tempo(r,N,URI,_{times:Times, values:Values}) :- + transform_op(tempo,normalised_tempo_r(N),URI,Result), + Result=Times-Values. + +tempo_histogram(ml,DT,Min,Max,N,URI,_{edges:Edges, counts:Counts}) :- + insist(Min>0, domain_error(min,"positive value",Min)), + Map=expmap(Min,Max,N), + map_edges(ml,Map,Edges), + transform_op(tempo,tempo_hist(DT,Map),URI,Result), + Result=_-Counts. +tempo_histogram(r,DT,Min,Max,N,URI,_{edges:Edges, counts:Counts}) :- + insist(Min>0, domain_error(min,"positive value",Min)), + Map=expmap(Min,Max,N), + map_edges(r,Map,Edges), + transform_op(tempo,tempo_hist_r(DT,Map),URI,Result), + Result=_-Counts. + + +% ------- collection level perspectives ------------ + +collection_pitch_histogram(W,CID,Result) :- + Min-Max = 20-100, % !!! FIXME + numlist(Min,Max,NNs), + dataset_histogram(CID, dense_pitch_hist(Min,Max,W), _{values:NNs}, Result). + +collection_pitch_lookup(Weighting, Pitch, Lim, Offset, CID, Result) :- + map_reduce_dataset(rec_pitch_hist(Weighting), pitch_lookup_cont(Pitch,Lim,Offset), CID, Result). + +pitch_lookup_cont(Pitch,Lim,Offset,RecHists, _{items:Items}) :- + findall( _{ uri: Rec, label:Label, count:Count, prob:Prob }, + offset(Offset, limit(Lim, order_by( [desc(Prob)], + ( member(Rec-Hist,RecHists), + rdf_display_label(Rec,Label), + pitch_hist_prob(Hist,Pitch,Count,Prob) + )))), + Items). + +% collection_pitch_lookup_alt(Weighting, Pitch, Lim, Offset, CID, _{ items:Items, coverage:Coverage}) :- +% findall_map_coverage(dataset_item(CID), rec_transcription, RecTrans, Coverage), +% findall( _{ uri: Rec, label:Label, count:Count, prob:Prob }, +% offset(Offset, limit(Lim, order_by( [desc(Prob)], +% ( csv_pitch_count_prob(Weighting,Trans,Pitch,Count,Prob), +% member(Rec-Trans,RecTrans), +% rdf_display_label(Rec,Label) +% )))), +% Items). +% +% rec_transcription(Rec,Rec-Transcription) :- transform_computation(transcription,Rec,Transcription). + +collection_freq_histogram(Lang,Min,Max,Q,W,CID,Result) :- + Map=binmap(Min,Max,(Max-Min)*Q+1), + map_edges(Lang,Map,Edges), + dataset_histogram(CID, dense_freq_hist(Lang,Map,W),_{edges:Edges}, Result). + +collection_tempo_histogram(Lang,DT,Min,Max,N,CID,Result) :- + insist(Min>0, domain_error(min,"positive value",Min)), + Map=expmap(Min,Max,N), + map_edges(Lang,Map,Edges), + dataset_histogram(CID, tempo_hist(Lang,DT,Map), _{edges:Edges}, Result). + +collection_tempo_curve(Lang,N,CID, Result) :- + map_reduce_dataset(tempo_curve(Lang,N), tempo_curves_stats(Lang), CID, Result). + + +dataset_histogram(CID, Mapper, Dict, Result) :- + dataset_map_fold_reduce(CID,Mapper,with_dl(fold_hist),finish_hist(Dict),nothing,Result). + +fold_hist([], S, S) :- !. +fold_hist(Xs, just(C1), just(C2)) :- !, insist(seqmap(maplist(add),Xs,C1,C2)). +fold_hist([X|Xs], nothing, just(C)) :- insist(seqmap(maplist(add),Xs,X,C)). + +finish_hist(Dict,just(Counts),Hist) :- put_dict(counts,Dict,Counts,Hist). + +py_hist(Mapper, PyFunction, Args, CID, _{counts:H,values:D,coverage:C,py_coverage:PYC}) :- + py_cla(Mapper,PyFunction,Args, CID, _{stats:_{counts:H,domain:D},coverage:C,py_coverage:PYC}). + +py_cla(Mapper, PyFunction, Args, CID, Result) :- + map_reduce_dataset(Mapper, py_cla_cont(PyFunction,Args), CID, Result). + +py_cla_cont(PyFunction,Args, Ok, _{stats:Result, py_coverage:Coverage}) :- + python_apply(PyFunction,[Ok|Args],Reply), + Reply = _{result:Result, stats:Coverage}. + + +% CLA mappers +rec_pitch_hist(W,Rec,Rec-Hist) :- transform_op(transcription,pitch_hist(W),Rec,Hist). + +dense_pitch_hist(Min,Max,W,Rec,DenseHist) :- + transform_op(transcription,pitch_hist(W),Rec,SparseHist), + sparse_to_dense(Min,Max,SparseHist,DenseHist). + +dense_freq_hist(ml,Map,W,Rec,Counts) :- + transform_op(transcription(1),freq_hist(Map,W),Rec,Counts). +dense_freq_hist(r,Map,W,Rec,Counts) :- + transform_op(transcription(1),freq_hist_r(Map,W),Rec,Counts). + +tempo_hist(ml,DT,Map,Rec,Counts) :- + transform_op(tempo,tempo_hist(DT,Map),Rec,Result), + Result=_-Counts. +tempo_hist(r,DT,Map,Rec,Counts) :- + transform_op(tempo,tempo_hist_r(DT,Map),Rec,Result), + Result=_-Counts. + +tempo_curve(ml,N,Rec,Values) :- + transform_op(tempo,normalised_tempo(N),Rec,Result), + Result=_-Values. +tempo_curve(r,N,Rec,Values) :- + transform_op(tempo,normalised_tempo_r(N),Rec,Result), + Result=_-Values. + +transcription_tonic_duration(Rec, _{transcription: Transcription, tonic: Tonic, duration:0 }) :- + tagged(transcription,Rec,Transcription), + tagged(tonic,Rec,Tonic). + +transcription_date(Rec, _{transcription: Transcription, date:Date}) :- + tagged(transcription(1),Rec,Transcription), + insist(recording_property(Rec,date,Date),missing_property(Rec,date)). + +keys_chords(Rec, _{keys: Keys, chords:Chords}) :- + tagged(key,Rec,Keys), + tagged(chords,Rec,Chords). + +similarity_bundle(Rec, _{chromagram: Chromagram, mfcc:Mfcc, keys: Keys, chords:Chords, list:_{uri:Rec, label:Label}}) :- + % nb_getval(vamp_on_demand,Vamp), + % concurrent_maplist(tagged_parallel(Vamp,Rec),[chromagram,mfcc,key,chords],[Chromagram,Mfcc,Keys,Chords]), + maplist(tagged,[chromagram,mfcc,key,chords],[Rec,Rec,Rec,Rec],[Chromagram,Mfcc,Keys,Chords]), + insist(recording_property(Rec,label,Label),missing_property(Rec,label)). + +tagged_parallel(Vamp,Rec,Transform,Result) :- + nb_setval(vamp_on_demand,Vamp), + with_progress_stack(tagged(Transform,Rec,Result)). + +list_places(Rec, _{place:Place,list:_{uri:Rec, label:Label}}) :- + insist(recording_property(Rec,place,Place),missing_property(Rec,place)), + insist(recording_property(Rec,label,Label),missing_property(Rec,label)). + +% for later... +% tagged_list(Spec,Rec,Dict) :- +% maplist(tagged_item(Rec),Spec,Pairs), +% dict_create(Dict,_,Pairs). +% tagged_item(Rec,Key:Transform,Key:Value) :- tagged(Transform,Rec,Value). + +tagged(Transform,Input,csv{value:Path}) :- + transform_computation(Transform,Input,R), uri_absolute_path(R,Path). + +% --------------------------------------------------- + +:- initialization time(memo_attach(memo(perspectives),[])). + +:- persistent_memo cla_memo(+spec:ground,+cid:atom,-result:any). +cla_memo(Spec,CID,Result) :- + debug(perspectives(cla),'cla_mem: ~q',[call(Spec,CID,Result)]), + with_progress_stack(call(Spec,CID,Result)). + +%% mem(+Spec:pred(+cid,-A),+Opts:options,+CID:cid,-Result:A) is det. +% +% Asynchronous memoised collection-level computation. +% Spec must be a ground term that can be called with two arguments: the id of a +% collection and a variable, which must be bound to an arbitrary result term on exit. +% If the computation has already be done and memoised in cla_memo/3, then the result is +% retrieved. Otherwise, the computation is started asynchronously and an exception +% describing the state of the computation will be thrown. +% == +% * dml_error(10, _{status:already_waiting, position:n}) +% the goal was previously added and is now waiting at position n in the queue. +% * dml_error(11, _{status:already_running, progress:Progress}) +% the goal was previously added and is currently running, with some progress information. +% * dml_error(12, _{status:initiate, position:N}) +% Means the goal has been added to the work queue of the thread pool at position N. +% == +% Options are options passed to control interaction with async_memo. + +mem(Spec,Opts,CID,Result) :- + option(vamp_on_demand(V), Opts, false), + async_memo(vis_cla,cla_memo(Spec,CID,Result),Status, + [ progress_levels([elapsed,summary,partial_result]), + globals([vamp_on_demand-V])|Opts ]), + ( Status=done(_-ok) -> true + ; status_response(Status,Code,Dict), + ( Status=done(_) -> Dict1=Dict + ; estimate_run_time(Spec,CID,ERT), + put_dict(ert,Dict,ERT,Dict1) + ), + throw(dml_error(Code,Dict1)) + ). + +% very crude estimate +estimate_run_time(Spec,CID0,ERT) :- + findall(Size-Dur, ( browse(cla_memo(Spec,CID,_),comp(_,_,Dur)-ok), + dataset_size(CID,Size)), Pairs), + length(Pairs,N), + ( N=0 -> ERT is -1 + ; maplist(computations:pair,Sizes,Durs,Pairs), + sumlist(Sizes,TotalSize), + sumlist(Durs,TotalDur), + dataset_size(CID0,Size), + ERT is TotalDur*Size/TotalSize + ). + +status_response(spawned(ID,Pos), 12, Info) :- + Info = _{status:initiated, id:ID, position:Pos }. +status_response(waiting(ID,T,Pos), 10, Info) :- + Info = _{status:already_waiting, id:ID, submit_time:TS, position:Pos }, + time_to_string(T,TS). +status_response(running(ID,TStart,_,nothing), 11, Info) :- + Info = _{ id:ID, status:already_running, start_time:TS }, + time_to_string(TStart,TS). +status_response(running(ID,TStart,_,just(Time-[Progress,Partial])), 11, Info) :- + maplist(progress_json,Progress,Progs), + time_to_string(TStart,TS), + Elapsed is Time-TStart, + ( member(stepwise(_,Done/Total),Progress), Done>0 + -> ETA is Elapsed*(Total-Done)/Done + ; ETA is -1 + ), + Info1 = _{ id:ID + , status:already_running + , start_time:TS + , elapsed_time:Elapsed + , progress:Progs + , eta:ETA + }, + ( Partial=just(R) + -> put_dict(partial_result,Info1,R,Info) + ; Info=Info1 + ). + +status_response(recomputing(ID,Pos,Meta), 13, Info) :- + Info = _{status:recomputing, id:ID, position:Pos, meta:MD}, + meta_dict(Meta,MD). +status_response(done(Meta), 14, _{status:failed, meta:MD}) :- + meta_dict(Meta,MD). + +meta_dict(comp(_,Time,Dur)-Result, _{ date: Date, duration:Dur, reason:Reason}) :- + format_result(Result,Reason), + time_to_string(Time,Date). + +format_result(fail,'Unspecified failure'). +format_result(ex(Ex),Description) :- message_to_string(Ex,Description). + +time_to_string(Time,String) :- format_time(string(String),'%FT%T%:z',Time). + +progress_json(A,A) :- atomic(A), !. +progress_json(stepwise(Desc,Done/Total), _{ task:Task, total:Total, done:Done }) :- !, + progress_json(Desc,Task). +progress_json(T,A) :- message_to_string(T,A). + +prolog:message(map_fold(_Mapper,_Folder)) --> ['Map-fold']. + +:- multifile thread_pool:create_pool/1. +thread_pool:create_pool(vis_cla) :- + current_prolog_flag(cpu_count,N), + thread_pool_create(vis_cla, N, [backlog(20)]). + +% ------------ computations with progress ------------------ + +map_reduce_dataset(Mapper,Reducer,CID,Result) :- + dataset_map_fold_reduce(CID,Mapper,append_dl,with_dl(Reducer),H-H,Result). + +append_dl(HH-TT,H-HH,H-TT). +with_dl(P,H-[],A) :- call(P,H,A). +with_dl(P,H-[],A,B) :- call(P,H,A,B). + +dataset_map_fold_reduce(CID,Mapper,Folder,Reducer,S0,Result) :- + dataset_items(CID,Items), + with_cont( 'Map-fold-reduce', + map_fold_with_progress( safe_call(Mapper), + safe_fold(Folder), + Items, s(0,F-F,E-E,S0)), + reduce_cont(Reducer), Result). + +reduce_cont(Reducer,s(NOk,Failed-[],Erroneous-[],S), R) :- + ( NOk>0 + -> simple_task(reducing(Reducer),call(Reducer,S,R1)), + put_coverage(NOk,Failed,Erroneous,R1,R) + ; put_coverage(NOk,Failed,Erroneous,_{status:'no successfully mapped items'},D), + throw(dml_error(20, D)) + ). + +put_coverage(NOk,Failed,Erroneous,R1,R) :- + put_dict(coverage,R1,_{ok_count:NOk, failed:Failed, errors:Erroneous},R). + +safe_call(Mapper,X,Z) :- + ( catch((call(Mapper,X,Y), Z=ok(X,Y)), Ex, + ( Ex=abort(_) -> throw(Ex) + ; Z=error(X,Ex))), ! + ; Z=fail(X) + ). + +safe_fold(Folder,Items,s(NOk1,FH-FT1,EH-ET1,S1),s(NOk2,FH-FT2,EH-ET2,S2)) :- + seqmap(partition,Items,s(NOk1,OkH,FT1,ET1),s(NOk2,OkT,FT2,ET2)), + call(Folder,OkH-OkT,S1,S2). + +partition(ok(_,X),s(N,[X|O],F,E),s(M,O,F,E)) :- M is N+1. +partition(fail(X),s(N,O,[X|F],E),s(N,O,F,E)). +partition(error(X,Ex),s(N,O,F,[_{item:X, error:Msg}|E]),s(N,O,F,E)) :- message_to_string(Ex,Msg). + diff -r 000000000000 -r 718306e29690 cpack/dml/api/r_plot.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/r_plot.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,103 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(api_r_plot, []). + +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(sandbox)). +:- use_module(library(insist)). +:- use_module(library(fileutils)). +:- use_module(library(swipe)). +:- use_module(library(httpfiles)). +:- use_module(library(real)). + +:- set_prolog_flag(double_quotes,string). +:- set_prolog_flag(back_quotes,symbol_char). + +:- http_handler(api(r/render), r_figure_render, []). + +:- setting(r_plot:pixels_per_inch,number,150,"Pixels per inch for in browser figures"). +:- setting(r_plot:default_figure_format,oneof([png,svg]),svg,"Default R figure rendering method"). + +%% figure_render(+Request) is det. +% +% HTTP handler for rendering R figures. +r_figure_render(Request) :- + setting(r_plot:pixels_per_inch,DefPPI), + http_parameters(Request, + [ code(CodeA,[ atom, optional(false), description("Prolog rendering goal")]) + , format(F, [ oneof([eps,svg,pdf,png]), optional(false), description("Output format") ]) + , width(W, [ number, optional(true), default(10), description("Width in cm")]) + , height(H, [ number, optional(true), default(6), description("Height in cm")]) + , font_name(FN, [ atom, optional(true), default(helvetica) ]) + , font_size(FS, [ number, optional(true), default(10) ]) + , ppi(PPI, [ number, optional(true), default(DefPPI), description("PNG resolution")]) + ]), + debug(r_plot,"Attempting to parse \"~s\".",[CodeA]), + read_term_from_atom(CodeA,Code,[]), + ( user_db:logged_on(A) + -> debug(r_plot,"Logged on as ~w, no checking",[A]) + ; debug(r_plot,"Checking ~q for safety...",[Code]), + sandbox:safe_goal(Code), + debug(r_plot,"Goal is safe.",[]) + ), + insist(with_temp_dir(Dir, ( + render(F,Code,Dir,File, [size(W,H), ppi(PPI), font_name(FN), font_size(FS) ]), + debug(r_plot,'Replying with file ~s',[File]), + reply_file(File,F) + ))). + + +render(png,Code,D,PNGPath,Opts) :- !, + file_name_extension(tmp,png,PNGFile), + directory_file_path(D,PNGFile,PNGPath), + render(pdf,Code,D,EPSFile,Opts), + option(ppi(PPI),Opts,300), + run(sh(0>>0, "gs -dBATCH -dNumRenderingThreads=2 -dEPSCrop -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=~s -r~d -q ~s", + [PNGPath+write,\PPI,EPSFile+read])). + +% render(png,Code,D,Opts) :- !, option(ppi(PPI),Opts,300), render(png(PPI),Code,D,Opts). +render(Fmt,Code,Dir,Path,Opts) :- + file_name_extension(tmp,Fmt,File), + directory_file_path(Dir,File,Path), + debug(r_plot,'Running ~q',[print_fig(Fmt,Code,Path,Opts)]), + with_mutex(r_plot,api_r_plot:print_fig(Fmt,Code,Path,Opts)). + +print_fig(Fmt,Code,Path,Opts) :- + debug(r_plot,'In print_fig...',[]), + option(size(Width,Height),Opts), + maplist(cm_inch,[Width,Height],[WidthInches,HeightInches]), + debug(r_plot,'Getting device ~w: ~s',[Fmt,Path]), + dev(Fmt,Path,WidthInches,HeightInches,Dev), + debug(r_plot,'Got device ~q',[Dev]), + setup_call_cleanup( + r(Dev), + call_cleanup( + with_output_to(string(_),Code), + exception(Ex), + debug(r_plot,'Exception running R code: ~q',[Ex])), + r('dev.off()')). + +dev(pdf,Name,W,H,pdf(+Name,width=W,height=H)). +dev(eps,Name,W,H,cairo_ps(+Name,width=W,height=H)). +dev(svg,Name,W,H,svg(+Name,width=W,height=H)). +dev(png(PPI),Name,W,H,png(+Name,width=WP,height=HP)) :- WP is PPI*W, HP is PPI*H. + +cm_inch(CM,INCH) :- INCH is CM/2.54. + diff -r 000000000000 -r 718306e29690 cpack/dml/api/score.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/score.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,270 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(api_score, [get_link/3]). + +/** Score related services and components +*/ +:- use_module(library(thread_pool)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(fileutils)). +:- use_module(library(swipe)). +:- use_module(library(httpfiles)). +:- use_module(library(humdrum_p2r)). + +:- set_prolog_flag(double_quotes,string). + +:- initialization + current_thread_pool(sonify), !; + thread_pool_create(sonify, 20, [local(100), global(100), trail(100), backlog(100)]). + +user:term_expansion((:- file_setting(Name,Dir,Def,Desc)), (:- setting(Name,oneof(Files),Def1,Desc))) :- + absolute_file_name(Dir,Path,[file_type(directory),expand(true)]), + directory_files(Path,All), + exclude(dotfile,All,FilesUnsorted), + sort(FilesUnsorted,Files), + debug(score,'Found fluidsynth rc files: ~q',[All]), + ( member(Def,Files) -> Def1=Def + ; member(default,Files) -> Def1=default + ; member(Def1,Files) + ). + +dotfile(X) :- atom_concat('.',_,X). + +:- http_handler(api(score/render), score_render, []). +:- http_handler(api(score/get), score_get, []). +:- http_handler(api(score/sonify), score_sonify, [spawn(sonify),chunked]). + +:- setting(score:autobeam,boolean,true,"Use Lilypond autobeam when converting from XML"). +:- setting(score:default_width,number,170,"Default width of rendered score in mm"). +:- setting(score:reverse_spines,boolean,false,"Reverse order of spines when converting"). +:- setting(score:fluidsynth_sample_rate,number,44100,"Default Fluidsynth sample rate"). +:- setting(score:ogg_quality,between(-1,10),4,"Default oggenc quality"). +:- setting(score:mp3_lame_bitrate,oneof([96, 112, 128, 160, 192, 224, 256, 320]),128,"MP3 encoding bitrate"). +:- setting(score:hum2mid_tempo_scaling,number,1,"Tempo factor Humdrum to MIDI conversion"). +:- setting(score:soundfont_dir,string,"/usr/share/sounds/sf2","Soundfont directory"). +:- file_setting(score:fluidsynth_rc,dml(fluid),fluid_gm,"Fluidsynth initialisation file"). + + +%% score_get(+Request) is det. +% +% Handler for obtaining a score in one of several languages. +% +% The conversion relies on a number of executables, which must be available in the +% current PATH. +% * mvspine (humdrum) +% * hum2abc, hum2xml (humextra) +% * musicxml2ly (lilypond) +score_get(Request) :- + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of score to render")]) + , format(Fmt, [ optional(true), default(kern) + , oneof([kern,mxml,abc,lily]) + , description("Output format") ]) + % , transpose(Tr, [ optional(true), default('P1'), atom, description("Transposition interval") ]) + ]), + reply_converted_stream(get(Fmt),URI,[]). + + +%% score_sonify(+Request) is det. +% +% Handler for obtaining a score as MIDI or audio. +% Conversion to MIDI is affected by the following settings: +% Conversion is affected by the following settings: +% * score:hum2mid_tempo_scaling +% * score:fluidsynth_rc +% The name of fluidsynth initialisation file (in ~/etc/fluid) +% * score:fluidsynth_sample_rate +% * score:ogg_quality +% * score:mp3_lame_bitrate +% +% The conversion relies on a number of executables, which must be available in the +% current PATH. +% * mvspine (humdrum) +% * hum2mid, hum2abc, hum2xml (humextra) +% * oggenc (vorbis-tools) +% * lame +% * lilypond, musicxml2ly (lilypond) +% * pdf2svg +score_sonify(Request) :- + setting(score:hum2mid_tempo_scaling,Temp0), + setting(score:fluidsynth_rc,RC0), + ( member(range(Range),Request) + -> debug(score,'Got sonify request for range: ~q',[Range]) + ; true + ), + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of score")]) + , format(Fmt, [ optional(false), default(ogg) + , oneof([midi,ogg,mp3]) + , description("Output format") ]) + , tempo(Tempo,[ optional(true), default(Temp0), number, description("Tempo adjust factor") ]) + , fluidrc(RC, [ optional(true), default(RC0), atom, description("Fluidsynth intialisation") ]) + , transpose(Tr, [ optional(true), default('P1'), atom, description("Transposition interval") ]) + ]), + reply_converted_stream(sonify(Fmt,[tempo(Tempo),fluidrc(RC),transpose(Tr)]),URI,[]). + % ( uri_conversion_length(URI,sonify(Fmt,Tempo),Length) + % -> reply_converted_stream(sonify(Fmt,[tempo(Tempo),fluidrc(RC)]),URI,[length(Length),no_cache]) + % ; reply_converted_stream(sonify(Fmt,[tempo(Tempo),fluidrc(RC)]),URI,[length(Length),no_cache]), + % assert(uri_conversion_length(URI,sonify(Fmt,Tempo),Length)) + % ). + + +%% score_render(+Request) is det. +% +% Handler for score rendering web API. Takes a URI for a Humdrum score and a target +% graphical format, and uses Lilypond to layout and render musical notation. +% The layout parameter takes the following values: +% * page +% Results in a multi-page document suitable for printing. +% * snip +% Results in single, possibly very tall, image encapsulating the entire score. +% +% The rendering is affected by a number of settings (all in the score namespace): +% * autobeam +% Conversion to Lilypond goes via MusicXML and can use beaming information in the +% original score (autobeam=false), or Lilypond's own automatic beaming +% feature (autobeam=true). +% * default_width +% Default value for width parameter. This affects the number of bars per line and +% hence the overall scaling of the rendered score. +% * reverse_spines +% Humdrum scores maybe arranged with parts (spines) arranged by register from +% highest to lowest, or lowest to highest. If the latter, then it may help to +% reverse the spines to obtain a score with the highest parts at the top. +% +% Rendering requires serveral executable in addition to those required for conversion +% to a lilypond score: +% * lilypond +% * pdf2svg +score_render(Request) :- + setting(score:default_width,DefWidth), + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of score to render")]) + , format(F, [ optional(true), default(svg), oneof([svg,pdf,png]) + , description("Output format") ]) + , width(W, [ optional(true), default(DefWidth), nonneg + , description("Page width in mm") ]) + , layout(L, [ optional(true), default(snip), oneof([snip,page]) + , description("Lilypond backend") ]) + , transpose(Tr, [ optional(true), default('P1'), atom + , description("Transposition interval") ]) + ]), + reply_score(render(F,W,L,[transpose(Tr)]),URI). + +reply_score(Conversion,URI) :- + hum_uri_path(URI,In), + debug(score,"reply_score: ~q",Conversion), + with_temp_dir(Dir, + ( run(in(Dir,convert(Conversion,In,Out,Type))), + absolute_file_name(Dir/Out,File), + reply_file(File,Type))). + +reply_converted_stream(Conversion,URI,Opts) :- + hum_uri_path(URI,In), + debug(score,"~q",reply_converted_stream(Conversion,URI,Opts)), + with_temp_dir(Dir, + with_pipe_output( S, [type(binary)], + in(Dir,convert(Conversion,In,Type)), + reply_stream(S,Type,Opts))). + +% this should be in swipe... +:- meta_predicate with_pipe_output(-,+,+,0). +with_pipe_output(S, Opts, Spec, Goal) :- + command(Spec, 0>> $_, Cmd), + with_stream(S, open(pipe(Cmd), read, S, Opts), Goal). + + +get_link(URI,s-Fmt,URL) :- http_link_to_id(score_get,[uri(URI),format(Fmt)],URL). +get_link(URI,a-Fmt,URL) :- http_link_to_id(score_sonify,[uri(URI),format(Fmt)],URL). +get_link(URI,a(Ps)-Fmt,URL) :- http_link_to_id(score_sonify,[uri(URI),format(Fmt)|Ps],URL). + + + +% ----- conversion pipelines ----------- + +swipe:def(P,Q) :- def(P,Q). + +% get/1 conversion runs a pipeline into a file out in the +% current directory. +def( convert(get(F), In, out,F), In^kern :> humto(F,[]) >: out^F). + +% conversions with piped output (but might create files in current directory) +def( convert(get(F), In, F), In^kern :> humto(F,[])). +def( convert(sonify(F,Opts), In, F), In^kern :> humto(F,Opts)). + +% render/3 conversion produces a file out. in the current +% directory where F is the requested format. +def( convert(render(F,W,L,Opts),In,Out,F), In^kern :> humto(lily,Opts) >> adjust(W,L) >> render(F,L)):- + atom_concat('out.',F,Out). + + +% these all read from In and output to stdout + +def( tomidi(Out,O), hum2mid(TF,Out)) :- option(tempo(TF),O,1). + +def( humto(Fmt,O), transpose(Interval) >> humto(Fmt,O1)) :- select_option(transpose(Interval),O,O1), Interval\='P1', !. +def( humto(Fmt,O), trans(Semis) >> humto(Fmt,O1)) :- select_option(trans(Semis),O,O1), Semis\=0, !. +def( humto(kern,_), cat). +def( humto(abc,_), sh( $kern >> $abc, "~s",[dml(scripts/hum2abcp)+execute])). +def( humto(lily,O), humto(mxml,O) >> xml2ly(B)) :- setting(score:autobeam,B). +def( humto(mxml,_), Pipe) :- + ( setting(score:reverse_spines,true) + -> Pipe = sh( $kern -> $kern, "mvspine -r") >> hum2xml + ; Pipe = hum2xml + ). +def( humto(midi,O), tomidi(Out,O) * sh($midi >> $midi, 'cat ~s',[@Out])). +def( humto(ogg,O), humto(raw(B,2,R),O) >> oggenc(B,R,Quality)) :- setting(score:ogg_quality,Quality). +def( humto(mp3,O), humto(raw(B,2,R),O) >> lame(B,R,BR)) :- setting(score:mp3_lame_bitrate,BR). +def( humto(raw(16,2,Rate),O), tomidi(Out,O) * midi2raw(Out,RC,Rate,s16)) :- + setting(score:fluidsynth_sample_rate,Rate), + setting(score:fluidsynth_rc,RC0), + option(fluidrc(RC),O,RC0). + +def( hum2mid(TF,Out), sh( $kern >> 0, "hum2mid --mv 1 --hv 1 -t ~f -o ~s", [\TF,@Out])) :- Out="out.mid". +def( midi2raw(In,RC,Rate,Fmt), + sh( 0>> $audio(raw), + "~s ~w ~s ~f ~w ~s", + [ dml(scripts/midi2snd)+execute, @In, dml(fluid/RC)+read, \Rate, \Fmt, @AbsSFDir])) :- + setting(score:soundfont_dir,SFDir), + absolute_file_name(SFDir,AbsSFDir,[file_type(directory),expand(true)]). + +def( oggenc(Q), sh( $audio(F) >> $audio(ogg), "oggenc -Q -q ~d -", [\Q])) :- member(F,[wav,aiff,flac]). +def( oggenc(B,R,Q),sh( $audio(raw) >> $audio(mp3), "oggenc -Q -r -B~d -C2 -R~d -q~d -", [\B,\R,\Q])). +def( lame(B,R,BR), sh( $audio(raw) >> $audio(mp3), Fmt, [\B,\K,\BR])) :- + Fmt="lame -h -r --bitwidth ~d -s ~f -b ~d - -", + K is R/1000. + +% these all process stdin to stdout +def( adjust(W,L), sh( 0 >> $lily, "~s ~d\\\\mm",[dml(scripts/L)+execute,\W])*cat). +def( xml2ly(true), sh( $mxml >> $lily, "musicxml2ly --no-beaming -")). +def( xml2ly(false), sh( $mxml >> $lily, "musicxml2ly -")). +def( hum2xml, sh( $kern >> $mxml, "hum2xml")). +def( transpose(I), sh( $kern >> $kern, "transpose -t ~s",[\I])). +def( trans(N), sh( $kern >> $kern, "trans -d 0 -c ~d",[\N])). + +% these all read stdin and produce a file called out. +def( render(svg,snip), lilypond(eps,pdf) * sh(0>>0,"pdf2svg out.pdf out.svg")) :- !. +def( render(svg,page), lilypond(svg,svg)) :- !. +def( render(Fmt,Layout), lilypond(BE,Fmt)) :- + member(Layout/BE,[page/ps,snip/eps]). + +% lilypond produces out. where F is in {pdf,svg,png} +def( lilypond(B,F), sh($lily>>0, "lilypond -dsafe -dbackend=~w -f~w -o out -",[\B,\F])). + diff -r 000000000000 -r 718306e29690 cpack/dml/api/transcription.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/transcription.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,136 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(api_transcription, [transcription_link/3]). + +/** Score related services and components +*/ +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(fileutils), [with_temp_dir/2, with_stream/3]). +:- use_module(library(dcg_core), [seqmap//2]). +:- use_module(library(httpfiles), [reply_stream/3]). +:- use_module(library(csvutils), [uri_to_csv/2]). +:- use_module(library(computations)). +:- use_module(library(plsmf)). +:- use_module(library(swipe)). +:- use_module(api(score)). % needed for pipelines + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(api(transcription/sonify), transcription_sonify, [chunked]). + +:- dynamic uri_conversion_length/3. + +%% transcription_sonify(+Request) is det. +% +% Handler for obtaining a score as MIDI or audio. +% Conversion to MIDI is affected by the following settings: +% Conversion is affected by the following settings: +% * score:hum2mid_tempo_scaling +% * score:fluidsynth_rc +% The name of fluidsynth initialisation file (in ~/etc/fluid) +% * score:fluidsynth_sample_rate +% * score:ogg_quality +% * score:mp3_lame_bitrate +% +% The conversion relies on a number of executables, which must be available in the +% current PATH. +% * oggenc (vorbis-tools) +% * lame +transcription_sonify(Request) :- + setting(score:fluidsynth_rc,RC0), + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of transcription")]) + , format(Fmt, [ optional(false), default(ogg) + , oneof([midi,ogg,mp3]) + , description("Output format") ]) + , tempo(Tempo,[ optional(true), default(1), number, description("Tempo adjust factor") ]) + , fluidrc(RC, [ optional(true), default(RC0), atom, description("Fluidsynth intialisation") ]) + ]), + debug(transcription,'Sonify transcription ~w as ~w',[URI,Fmt]), + + % uri_conversion_length(URI,sonify(Fmt,Tempo),Length) + reply_sonfied_transcription(URI,Fmt,Tempo,RC,[]). + +reply_sonfied_transcription(URI,Fmt,Tempo,RC,Opts) :- + insist(uri_to_csv(URI,Rows)), + insist(once(( transcription_class(URI,Class), + seqmap(row_event(Class,Tempo),Rows,Events,[])))), + + with_temp_dir(Dir, + ( directory_file_path(Dir,'tmp.mid',MidiFile), + events_to_midi_file(Events,MidiFile), + with_pipe_output( S, [type(binary)], + in(Dir,sonify_events(Fmt,MidiFile,[fluidrc(RC)])), + reply_stream(S,Fmt,Opts)))). + +% this should be in swipe... +:- meta_predicate with_pipe_output(-,+,+,0). +with_pipe_output(S, Opts, Spec, Goal) :- + command(Spec, 0>> $_, Cmd), + with_stream(S, open(pipe(Cmd), read, S, Opts), Goal). + + +transcription_class(URI,Class) :- + rdf(Comp,dml:'comp/output',URI), + rdf(Comp,dml:'comp/function',Fn), + % rdf(Fn,vamp:plugin,Plugin), + computations:transform(Class,Fn). + +transcription_link(URI,a(Ps)-Fmt,URL) :- http_link_to_id(transcription_sonify,[uri(URI),format(Fmt)|Ps],URL). +transcription_link(URI,a-Fmt,URL) :- transcription_link(URI,a([])-Fmt,URL). + +events_to_midi_file(Events,File) :- + debug(transcription,'Writing events to ~w',[File]), + smf_new(SMF), + smf_add_events(SMF,Events), + smf_write(SMF,File). + +row_event(transcription,Tempo,row(Time,Dur,Freq,Vel,'')) --> !, + { freq_note_number(Freq,NN), T0 is Time/Tempo, T1 is (Time+Dur)/Tempo }, + [ smf(T0,144,NN,Vel), smf(T1,128,NN,0) ]. + +row_event(transcription,Tempo,row(Time,Dur,_,Vel,Pitch)) --> + { remove_cents(Pitch,Pitch1) }, + { pitch_name_number(Pitch1,NN), T0 is Time/Tempo, T1 is (Time+Dur)/Tempo }, + [ smf(T0,144,NN,Vel), smf(T1,128,NN,0) ]. + +row_event(chord_notes,Tempo,row(Time,Dur,NN)) --> + { T0 is Time/Tempo, T1 is (Time+Dur)/Tempo }, + [ smf(T0,144,NN,64), smf(T1,128,NN,0) ]. + + +% ----- conversion pipelines ----------- + +swipe:def(P,Q) :- def(P,Q). + +% these all read from In and output to stdout + +def( sonify_events(midi,In,_), cat(In^midi)). +def( sonify_events(ogg,In,O), sonify_events(raw(B,2,R),In,O) >> oggenc(B,R,Quality)) :- setting(score:ogg_quality,Quality). +def( sonify_events(mp3,In,O), sonify_events(raw(B,2,R),In,O) >> lame(B,R,BR)) :- setting(score:mp3_lame_bitrate,BR). +def( sonify_events(raw(16,2,Rate),In,O), midi2raw(In,RC,Rate,s16)) :- + setting(score:fluidsynth_sample_rate,Rate), + setting(score:fluidsynth_rc,RC0), + option(fluidrc(RC),O,RC0). + +remove_cents(P1,P2) :- sub_atom(P1,Bef,_,_,'-'), !, sub_atom(P1,0,Bef,_,P2). +remove_cents(P1,P2) :- sub_atom(P1,Bef,_,_,'+'), !, sub_atom(P1,0,Bef,_,P2). +remove_cents(P1,P1). + diff -r 000000000000 -r 718306e29690 cpack/dml/api/vis2.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/api/vis2.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,334 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(vis2, []). + +/** DML Visualisation web service + */ + + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(http/http_json)). +:- use_module(library(http/json)). +:- use_module(library(thread_pool)). +:- use_module(library(sandbox)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_codes)). +:- use_module(library(dcg_macros)). +:- use_module(library(fileutils)). +:- use_module(library(swipe)). +:- use_module(library(memo)). +:- use_module(library(rdfutils)). +:- use_module(library(httpfiles)). +:- use_module(library(dataset)). +:- use_module(library(insist)). +:- use_module(library(lambda)). +:- use_module(library(dcg/basics), [string_without//2, integer//1]). +:- use_module(library(solution_sequences)). + +:- set_prolog_flag(double_quotes,codes). +:- set_prolog_flag(back_quotes,string). + +http:location(v2,api(v2),[]). + +:- http_handler(v2(dataset), list_datasets, []). +:- http_handler(v2(dataset/define), define_dataset, []). +:- http_handler(v2(view/dataset/index), dataset_views, []). +:- http_handler(v2(view/dataset/items), dataset_items, []). +:- http_handler(v2(view/dataset/summary), dataset_summary, []). +:- http_handler(v2(view/recording/index), recording_views, []). +:- http_handler(v2(view/recording/properties), recording_properties, []). + +:- initialization + current_thread_pool(dmlvis), !; + thread_pool_create(vis, 8, [backlog(100)]). + +% ------------------------------------------------------------------------------------ +% Handlers with documentation + +%% list_datasets(+Request) is det. +% Lists previously defined datsets and the Prolog queries that define them. +list_datasets(R) :- vis(list_datasets,R). + +%% define_dataset(+Request) is det. +% Define a dataset satisfying given search terms. Result is a dataset +% ID, which may be the same as a previously defined dataset if it consists +% of the same items. +define_dataset(R) :- vis(define_dataset,R). + +%% dataset_views(+Request) is det. +% Lists available views for datasets. +dataset_views(R) :- vis(list_views(dataset),R). + +%% dataset_items(+Request) is det. +% Lists items in a given dataset specified by its ID.. +dataset_items(R) :- vis(dataset_items,R). + +%% dataset_summary(+Request) is det. +% Returns some summary information about a dataset. +dataset_summary(R) :- vis(dataset_summary,R). + +%% recording_views(+Request) is det. +% Lists available views for recordings. +recording_views(R) :- vis(list_views(recording),R). + +%% recording_properties(+Request) is det. +% Returns all the properties currently held in the RDF graph about a given recording. +recording_properties(R) :- vis(recording_properties,R). + + +% ------------------------------------------------------------------------------------ + +%% vis(+Method,+Request) is det. +% +% Top level predicate for implementing VIS API. Handles common tasks +% like determining the reply format, handling errors, and formatting the reply. +vis(Method,Request) :- + method_params_goal(Method,Params,Goal), + vis(Params,Goal,Request). + +vis(Params,Goal,Request) :- + http_parameters(Request, [format(Format), callback(Callback) | Params], + [attribute_declarations(param)]), + (Format=jsonp -> Fmt=jsonp(Callback); Fmt=json), + member(request_uri(Query),Request), + catch( insist(call(Goal,Result,Status)), + Ex, (error_result(Ex,Result), Status=error)), + result_response(Fmt,Query,Result,Status,Response), + write(Response). + +result_response(Fmt,Q,Result,Status,Response) :- + with_output_to(string(Response), + reply_as(Fmt,Status,_{ query:Q, result: Result})). + +reply_as(json,Status,Dict) :- + write_headers([Status,type(json)]), + json_write_dict(current_output, Dict). +reply_as(jsonp(Cb),Status,Dict) :- + write_headers([Status,type(jsonp)]), + write(Cb), write('('), + json_write_dict(current_output, Dict), + write(');'). + + +error_result(dml_error(Code,Descriptor),_{ code: Code, desc:Desc }) :- !, + format(string(Desc),'ERROR: ~w',[Descriptor]). + +error_result(Ex, _{ code: 500, desc: Msg }) :- + message_to_string(Ex,Msg). + +% ------------------------------------------------------------------------------------ +% Implementation of methods + +:- multifile param/2. + +% general +param( format, [oneof([json,jsonp]), default(jsonp), description('Reply format')]). +param( callback, [atom,default(jsonp_cb), description('Callback for jsonp reply')]). + +% define_dataset +param( library, [oneof([beets,charm,bl,ilm]), default(bl), description('Library to search within')]). +param( dv, [nonneg, optional(false), description('Database version ID')]). +param( genres, [atom, default(*), description('Semicolon separated list of genre names, or "*"')]). +param( years, [atom, default(*), description('Semicolon separeted list of release years or a range (Y1-Y2) or "*"')]). +param( composers, [atom, default(*), description('Semicolon separated list of composers or "*"')]). +param( performers,[atom, default(*), description('Semicolon separated list of performers or "*"')]). + +param( cid, [atom, optional(false), description('Collection ID')]). +param( cids, [atom, optional(false), description('Semicolon separated list of Collection IDs')]). +param( uri, [atom, optional(false), description('Recording URI')]). +param( limit, [integer, default(5000), description('Maximum number of things to return')]). +param( offset, [integer, default(0), description('Offset within list')]). + +method_params(listCollections, []). +method_params(listPerspectives, [method(_)]). +method_params(collection_id, [library(_),dv(_),genres(_),years(_),composers(_),performers(_)]). +method_params(Method, [ pid(_) | Params ]) :- + perspective(Method,_,_,_,_), + setof(P, perspective_param_name(Method,P), Ps), + maplist(param_name_term,Ps,Params). + +param_name_term(Name,Term) :- functor(Term,Name,1). +perspective_param_name(Method,Name) :- + perspective(Method,_,_,Specs,_), + member(S,Specs), + optspec_name(S,Name). + + +:- multifile perspective/5. + +method_result(listCollections, _, _{ collections:List }, unstable) :- + findall( _{ cid:Id, query:QA, dv:DV, size:SZ }, + ( browse(dataset:dataset(dmlvis:Q, DV, Id, SZ, _)), + term_to_atom(Q,QA) + ), + List). +method_result(Method,Opts,Result,stable) :- + method_result(Method,Opts,Result). + + + +method_result(listPerspectives, Opts, _{ perspectives:List }) :- + option(method(Method), Opts), + findall( P, perspective(Method,P,_,_,_), List). + +method_result(collection_id, Opts, _{ cid:Id, size:Size }) :- + option(dv(DBV),Opts), + option(library(Coll),Opts), + collection_query(Coll, Opts, Query), + dataset_query_id( Query, DBV, Id), + dataset_size(Id, Size). + +options_optspec(_,Opts,\O) :- option(O,Opts). +options_optspec(_,Opts,O-Def) :- option(O,Opts,Def). +options_optspec(M,Opts,O>Goal) :- options_optspec(M,Opts,O), call(M:Goal). + +optspec_name(\O,Name) :- functor(O,Name,1). +optspec_name(O-_,Name) :- functor(O,Name,1). +optspec_name(O>_,Name) :- optspec_name(O,Name). + +perspective(getRecordingPerspective, properties, dmlvis, [\uri(URI)], recording_info(URI)). +perspective(getCollectionPerspective, summary, dmlvis, [\cid(C)], collection_summary(C)). +perspective(getCollectionPerspective, list, dmlvis, [\cid(C),limit(Lim)-5000,offset(Off)-0], collection_list(C,Lim,Off)). +% perspective(getCollectionPairPerspective, summary, dmlvis, [\cids(A)>parse_atom(cids([C1,C2]),A)], binary(summary,C1,C2)). +% perspective(getMultiCollectionPerspective, summary, dmlvis, [\cids(A)>parse_atom(cids(Cs),A)], multi(summary,Cs)). + +collection_summary(Id,Result) :- + insist(browse(dataset:dataset(Goal,DV,Id,Size,_)), unknown_collection(Id)), + term_to_atom(Goal,GoalA), + Result = _{cid:Id, size:Size, goal:GoalA, dv:DV }. + +collection_list(Id, Lim, Offset, _{cid:Id, size:Size, items:Items}) :- + dataset_size(Id,Size), + findall(Item,limit(Lim,offset(Offset,dataset_item(Id,Item))),Items). + +% --------------- recording_properties ----------------------------- + +recording_info(URI, Result) :- + ( a(mo:'AudioFile',URI) -> G=audiofile_info(URI) + ; a(mo:'Track',URI) -> G=track_info(URI) + ; a(mo:'Signal',URI) -> G=signal_info(URI) + ; rdf(URI,charm:file_name,_) -> G=charm_info(URI) + ; throw(not_a_recording(URI)) + ), + insist(call(G,Result),failed(G)). + +audiofile_info(URI,Result) :- + rdf_text(URI,beets:title,Title), + rdf_text(URI,beets:album,AlbumName), + rdf_text(URI,beets:artist,ArtistName), + rdf_number(URI,beets:length,Duration), + Result = _{ type:audiofile, title:Title, artist:ArtistName, album:AlbumName, duration:Duration }. + +track_info(Track, Result) :- + rdf_number(Track,mo:duration,DurationMs), Duration is DurationMs/1000.0, + rdf_text(Track,dc:title,Title), + rdf(Record,mo:track,Track), + rdf(Release,mo:record,Record), + rdf_text(Release,dc:title,AlbumName), + rdf(Artist,foaf:made,Track), + rdf_text(Artist,foaf:name,ArtistName), + Result = _{ type:track, title:Title, artist:ArtistName, album:AlbumName, duration:Duration }. + +signal_info(Signal, _{type:signal, tracks:Infos}) :- + setof(T,rdf(T,mo:publication_of,Signal),Tracks), + maplist(track_info,Tracks,Infos). + +charm_info(URI, PropDict) :- + setof(Pred-Vals,setof(Val1,Val^(rdf(URI,Pred,literal(Val)),atomise_literal(Val,Val1)),Vals),Info), + dict_pairs(PropDict,_,Info). + +atomise_literal(type(_,Val),Val) :- !. +atomise_literal(lang(_,Val),Val) :- !. +atomise_literal(Val,Val). + +% -------------------- defining a dataset ------------------------------ + +qc(beets,Opts,X) :- maplist(filter(beets,X),Opts), a(mo:'AudioFile',X). +qc(charm,Opts,X) :- maplist(filter(charm,X),Opts), rdf(X,charm:file_name,_). +qc(bl,Opts,X) :- maplist(filter(bl,X),Opts), rdf(X,rdf:type,mo:'Signal',bl_p2r). + +filter(_,_,genres(*)) :- true. +filter(beets,X,genres(any(Gs))) :- member(G,Gs), rdf_has(X,beets:genre,literal(substring(G),_)). + +filter(_,_,years(*)) :- true. +filter(D,X,years(any(Ys))) :- member(Y,Ys), filter(D,X,years(Y-Y)). +filter(D,X,years(L-U)) :- succ(U,U1), atom_number(LA,L), atom_number(U1A,U1), filter(D,X,years(LA,U1A)). +filter(beets,X,years(L,U)) :- rdf(X, beets:original_year, literal(between(L,U),_)). +filter(charm,X,years(L,U)) :- rdf(X, charm:recording_date, literal(between(L,U),_)). +filter(bl,X,years(L,U)) :- rdf(X, dcterms:created, literal(between(L,U),_)). + +filter(_,_,composers(*)) :- true. +filter(D,X,composers(any(List))) :- member(C,List), filter(D,X,composer(C)). +filter(charm,X,composer(C)) :- rdf(X, charm:composer, literal(prefix(C),_)). +filter(bl,X,composer(C)) :- rdf(X, marcrel:cmp, literal(prefix(C),_)). +filter(_,_,performers(*)) :- true. +filter(D,X,performers(any(List))) :- member(C,List), filter(D,X,performer(C)). +filter(charm,X,performer(C)) :- rdf(X, charm:performer, literal(prefix(C),_)). +filter(bl,X,performer(C)) :- rdf(X, marcrel:prf, literal(prefix(C),_)). +filter(beets,X,performer(C)) :- rdf(X, beets:artist, literal(prefix(C),_)). +filter(charm,X,title(C)) :- rdf(X, charm:title, literal(substring(C),_)). +filter(bl,X,title(C)) :- rdf(X, dc:title, literal(substring(C),_)). +filter(beets,X,title(C)) :- rdf(X, beets:title, literal(like(C),_)). + + +collection_query(Coll, Opts, qc(Coll,Filters)) :- + seqmap(process_qopt(Opts), + [ qo( genres(GA), genres(GS), genres(*), parse_atom(atoms(GS), GA)) + , qo( composers(CA), composers(CS), composers(*), parse_atom(atoms(CS), CA)) + , qo( performers(PA), performers(PS), performers(*), parse_atom(atoms(PS), PA)) + , qo( years(YA), years(YS), years(*), parse_atom(years(YS), YA)) + , qo( title(T), title(T), title(*), true) + ], + Filters, []). + +process_qopt(Opts,qo(Opt,Filter,NullFilter,Goal)) --> + {option(Opt,Opts,'*'), call(Goal)}, + ({Filter=NullFilter} -> []; [Filter]). + + +% --------- parsers ----------- + +% cids(Ids) --> seqmap_with_sep(",",alphanum,Ids). +cids(Ids) --> semicolon_sep(atom_codes,Ids). + +atoms('*') --> "*", !. +atoms(any(AS)) --> semicolon_sep(atom_codes,AS). + +years('*') --> "*", !. +years(L-U) --> integer(L), "-", integer(U). +years(any(Ys)) --> semicolon_sep(number_codes,Ys). + + + +% alphanum(X) --> string_without(",",S), {atom_string(X,S)}. + +item(Conv,Item) --> string_without(";",Codes), {call(Conv,Item,Codes)}. +semicolon_sep(Conv,Items) --> + seqmap_with_sep(";",item(Conv),Items). + + +parse_atom(Phrase,Atom) :- + atom_codes(Atom,Codes), + debug(vis,'Attempting to parse ~q with ~q...',[Atom,Phrase]), + insist( phrase(Phrase,Codes), parse_failure(Phrase)), + debug(vis,'...got ~q',[Phrase]). + diff -r 000000000000 -r 718306e29690 cpack/dml/applications/audio_ui.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/audio_ui.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,263 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(audio_ui, []). + +:- use_module(cp_application('config-enabled/dml_permission')). + +:- use_module(library(thread_pool)). +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(dcg_core)). +:- use_module(library(swipe)). +:- use_module(library(decoration)). +:- use_module(library(rdfutils)). +:- use_module(library(httpfiles)). +:- use_module(library(dsp)). + +:- use_module(library(musicbrainz), [mb_id_uri/3]). +:- use_module(library(spotify/spotify), [spotify_player//2]). +:- use_module(library(spotify/echotools), [mb_to_spotify/2]). +:- use_module(library(spotify/spotools)). + +:- use_module(components(matlab)). +:- use_module(components(audio)). + +:- use_module(cliopatria(hooks)). + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(api(audio/get), audio_get, [chunked,spawn(audio)]). +:- http_handler(api(audio/spectrogram), spectrogram_handler, []). +:- http_handler(root(dml/audio/spectrogram/window), spectrogram_window, []). +:- http_handler(root(dml/audio/spotify), spotify_handler, []). +% :- http_handler(api(audio/mpc), audio_mpc, []). + +:- setting(audio_decoration,oneof([link,player]),player,"Decoration for AudioFile URIs"). +:- setting(specgram_color_map,ground,hot,"Matlab colour map for spectrograms"). +% :- setting(mpd_host,atom,m5,"Name of MPD host"). + +:- rdf_meta reply_audio_stream(r,+,+). + +% Disabled: was causing excessive scraping of BL pages to get audio links. +% decoration:resource_decoration(URI,Link) --> +% { setof(URL-Fmt,audio_link(URI,URL,Fmt),URLS), !, +% setting(audio_decoration,Decoration) +% }, +% audio_decoration(Decoration,l(URLS),Link). + +decoration:resource_decoration(URI,Link) --> + { bagof(URL-Fmt,audio_link(URI,URL,Fmt),URLS), !, + setting(audio_decoration,Decoration) + }, + audio_decoration(Decoration,URLS,Link). + +decoration:resource_view(URI,_) --> + { mb_id_uri(recording,MBID,URI) + ; rdf(URI,mo:publication_of,Recording), + mb_id_uri(recording,MBID,Recording) + }, + { http_link_to_id(spotify_handler,[mbid(MBID)],SpotifyURL)}, + html( [ iframe([ name=spotify, seamless=seamless, src=SpotifyURL, allowtransparency=true + , style="border:0px solid #ccc;width:320px;height:80px" + ], []) + % , iframe([name=spotifyPlayer,seamless=seamless,width=320,height=80, + % frameborder=0,allowtransparency=true],[]) + , br([]) + ]). + +decoration:resource_view(URI,_) --> + % !!! HACK: force scraping for BL items here.. + {rdf(URI,dml:blpage,_) -> ignore(bl_p2r:scrape_audio_link(URI,_)); true}, + if( bagof(URL-Fmt,audio_link(URI,URL,Fmt),AudioLinks), audio_player(AudioLinks)), + if( (audio_file(URI,_,_); audio_link(URI,_,_)), html(div(\spectrogram(URI,[height(6)])))). + +%% spectrogram_window(+Request) is det. +% Returns an HTML page containing spectrogram of the the requested URI over the +% requested time range, with controls for moving forwards or backwards in the +% signal and for zooming in or out. +spectrogram_window(Request) :- + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of audio file")]) + , offset(O, [ number, optional(true), default(0), description("Offset in seconds")]) + , length(L, [ number, optional(true), default(60), description("Length of extract in seconds")]) + , width(W, [ number, optional(true), default(15)]) + , height(H, [ number, optional(true), default(8)]) + ], + [form_data(Params)]), + setting(specgram_color_map,CM), + seqmap(remove_option, [offset(_),length(_),format(_)], Params, Params2), + + ( rdf_number(URI,beets:length,Dur) + ; rdf_number(URI,mazurka:duration,Dur) + ; rdf(Sig,mo:sampled_version_of,URI), + rdf_number(Sig,mo:duration,Millis), + Dur is Millis/1000.0 + ; Dur = 36000000 + ), + OffsetPrev is max(0,O-L), + OffsetNext is min(Dur-L,O+L), + LZoomIn is L/2, OffsetZoomIn is O+L/4, + LZoomOut0 is min(Dur,L*2), OffsetZoomOut is max(0,O-L/2), + ( OffsetZoomOut + LZoomOut0 > Dur + -> LZoomOut is Dur-OffsetZoomOut + ; LZoomOut is LZoomOut0 + ), + + http_link_to_id(spectrogram_window, [offset(OffsetPrev), length(L) | Params2], URLPrev), + http_link_to_id(spectrogram_window, [offset(OffsetNext), length(L) | Params2], URLNext), + http_link_to_id(spectrogram_window, [offset(OffsetZoomIn), length(LZoomIn) | Params2], ZoomIn), + http_link_to_id(spectrogram_window, [offset(OffsetZoomOut), length(LZoomOut) | Params2], ZoomOut), + http_link_to_id(spectrogram_window, [offset(0), length(60) | Params2], Home), + + reply_html_page(cliopatria(bare),[title("Spectrogram viewer")], + [ \html_requires(font_awesome) + , \figure( spectrogram(URI,O,L), W, H, + [ format(png), color_map(CM) | Params2]) + , div(style="display:inline-block;vertical_align:middle", + [ a(href=Home, i(class='fa fa-home',[])), br([]) + , a(href=ZoomIn, i(class='fa fa-plus',[])), br([]) + , a(href=ZoomOut, i(class='fa fa-minus',[])), br([]) + , a(href=URLPrev, i(class='fa fa-chevron-left',[])), br([]) + , a(href=URLNext, i(class='fa fa-chevron-right',[])) + ]) + ], + [stable]). + +remove_option(Opt,O1,O2) :- select_option(Opt,O1,O2,_). + +%% spectrogram_handler(+Request) is det. +% Returns an image file containing a spectrogram of the requested URI over +% a given time window. +spectrogram_handler(Request) :- + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of audio file")]) + , offset(O, [ number, optional(true), default(0), description("Offset in seconds")]) + , length(L, [ number, optional(true), default(60), description("Length of extract in seconds")]) + ], + [form_data(Params)]), + select(uri(_),Params,P1), + Code=dsp:spectrogram(URI,O,L), + term_to_atom(Code,CodeAtom), + http_link_to_id(api_matlab:figure_render,[code(CodeAtom)|P1],URL), + http_redirect(see_other,URL,Request). + +%% spotify_handler(+Request) is det. +% Looks up a Spotify track URLs for the given Musicbrainz recording ID. +% If one is found, then returns an HTML page containing just a Spotify +% player component for all the Spotify tracks. If no tracks are found, +% then an HTML page containing a message is returned. +spotify_handler(Request) :- + http_parameters(Request, + [ mbid(MBID, [ optional(false), description("MusicBrainz recording ID")]) + ]), + with_output_to(string(_),findall(S,mb_to_spotify(MBID,S),SpotifyURIs)), + Head=[title("Spotify tracks for MBZ recording ~w"-MBID)], + ( SpotifyURIs=[] + -> reply_html_page(cliopatria(bare),Head,html(h3('Not found on Spotify')),[stable]) + ; reply_html_page(cliopatria(bare),Head, + \spotify_player(tracks('RecordingTracks',SpotifyURIs),[width(320),height(80)]),[stable]) + ). + +% list of Spotify URIs and a Spotify player +% spotify_handler(Request) :- +% http_parameters(Request, +% [ mbid(MBID, [ optional(false), description("MusicBrainz recording ID")]) +% ]), +% with_output_to(string(_),findall([S],mb_to_spotify(MBID,S),SpotifyURIs)), +% reply_html_page(cliopatria(bare), [title("Spotify tracks for recording")], +% table([ thead(td("Spotify URIs")) +% , \seqmap(table_row(spotify_link),SpotifyURIs) +% ])). + +% spotify_link(URI) --> +% { spotify_player_url(track(URI),[],URL) }, +% html(a([href=URL,target=spotifyPlayer ],URI)). + +% table_row(Format,Cells) --> html(tr(\seqmap(td(Format),Cells))). +% td(Format,Cell) --> html(td(\call(Format,Cell))). + + +% spotify_player(ID) --> +% ( {with_output_to(string(_),catch(mb_to_spotify(ID,SPID),_,fail))} +% -> spotify:spotify_player(SPID,[]) +% ; html(p("Not found on Spotify")) +% ). + + +audio_get(Request) :- + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of audio file")]) + , format(T, [ optional(true), default(original) + , oneof([original,ogg,mp3]), description("Audio format") ]) + ]), + debug(audio_ui,"Requested audio as ~w: ~s",[T,URI]), + insist(audio_file(URI,In,just(T0))), + insist(file_permission(In,public), access_denied), + ( (T=original; T0=T) + -> debug(audio_ui,"Returing original (~q) file ~q",[T0,In]), + reply_file(In,T0) + ; insist(command(transcode(In,URI,T0,T),Cmd)), + insist(reply_file(pipe(Cmd),T)) + ). + +% audio_mpc(Request) :- +% http_parameters(Request, +% [ uri(URI, [ optional(false), description("URI of audio file")]) +% ]), +% atom_concat('audio:',Rel,URI), +% setting(mpd_host,MPDHost), +% run(mpc_insert(MPDHost,Rel) * mpc_next(MPDHost)). + +% ----- conversion pipelines ----------- + +find_script(Name,Path) :- absolute_file_name(dml(scripts/Name),Path,[access(execute)]). + +swipe:def(P,Q) :- def(P,Q). + +def( mpc_insert(Host,Rel), sh(0>>0, "MPD_HOST=~w ~s ~w",[\Host,@MPC,@Rel])) :- find_script(mpc_insert,MPC). +def( mpc_next(Host), sh(0>>0, "MPD_HOST=~w mpc next",[\Host])). + +def( transcode(In,_,T1,T2), sox(In,T1,T2)) :- + sox_supported(T1). + +def( transcode(In,URI,aac,T2), faad(In,Bits) >> soxraw(af(Bits,C,SR),T2)) :- + ( rdf_number(URI,beets:samplerate,SR), + rdf_number(URI,beets:channels,C) + ; rdf(URI,mazurka:pid,_), + SR=44100, C=2 + ). + +def( faad(In,16), sh( 0 >> $audio(raw), "faad -f 2 -w ~s", [In+read])). +def( sox(In,F1,F2), sh( 0 >> $audio(F2), "sox -t ~w ~s -t ~w -",[\F1,In+read,\F2])). +def( soxraw(AF,Fmt), sh( $audio(raw) >> $audio(Fmt), F,[\Rate,\Bits,\Chans,\Fmt])) :- + F="sox -t raw -r ~d -b ~d -e signed -c ~d - -t ~w -", + AF=af(Bits,Chans,Rate). + +sox_supported(mp3). +sox_supported(wav). +sox_supported(ogg). +sox_supported(au). +sox_supported(aiff). + +:- initialization + current_thread_pool(audio), !; + thread_pool_create(audio, 20, [local(100), global(100), trail(100), backlog(100)]). + diff -r 000000000000 -r 718306e29690 cpack/dml/applications/callgraph_ui.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/callgraph_ui.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,139 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(callgraph_ui, []). + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(http/http_host)). +:- use_module(library(http/js_write)). +:- use_module(library(semweb/rdfs)). +:- use_module(library(dcg_core)). +:- use_module(library(fileutils)). +:- use_module(library(callgraph)). +:- use_module(library(decoration)). +:- use_module(library(httpfiles)). +:- use_module(components(icons)). + + +:- http_handler(root(dml/callgraph/ui), callgraph_ui, []). +:- http_handler(root(dml/callgraph/view), callgraph_viewer, []). +:- http_handler(api(callgraph/render), callgraph_render, []). + +:- html_resource(js('callgraph.js'), [requires(jquery)]). + +cliopatria:menu_item(500=help/callgraph_ui,'Module callgraph'). + +% adds a cube icon to all module URIs to link to rendered callgraph +decoration:resource_decoration(URI,Link) --> + {rdfs_individual_of(URI,memo:'Module')}, !, + {uripattern:pattern_uri(dml:module/prolog/enc(Mod),URI)}, + {http_link_to_id(callgraph_viewer,[module(Mod)],URL)}, + html_requires("//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css"), + html(span([ a(href(URL),[' ',\icon(cube)]), \Link])). + +%% callgraph_viewer(+Request) is det. +% Web page displaying the callgraph for a given module. +% Uses the callgraph_view//1 component for the view area. +callgraph_viewer(Request) :- + http_parameters(Request, + [ module(Module, [ optional(false), description("Name of module to graph") ]) ]), + reply_html_page(cliopatria(wide), [title(["Module callgraph: ",Module])], + [ h1(["Module callgraph: ",Module]), \callgraph_view(Module) ], + [ stable ]). + + +%% callgraph_view(+Module:module)// is det. +% +% HTML component containing a pannable/zoomable SVG callgraph of the named module. +% The graph itself is rendered by callgraph_render/1 via an HTTP request made just +% by Javascript code inserted directly after the view element. +callgraph_view(Module) --> + html_requires(js('callgraph.js')), + html_requires(js('svg-pan-zoom.min.js')), + html_requires(jquery), + html_post(head,style("svg text {font-family:Times}")), + {http_link_to_id(callgraph_render,[module(Module),format(svg)],URL)}, + html( [ div([style="width:100%;height:25em;padding:0em",id=output,class="output-box"],[]) + , \js_script({|javascript(URL)|| load_svg('#output',URL);|}) + ]). + +%% callgraph_render(+Request) is det. +% +% Replies with a the predicate dependency graph for a given module, created using library(callgraph). +% Default reply format is SVG. In some formats, each predicate contains a link to the documentation +% for that predicate. +callgraph_render(Request) :- + http_parameters(Request, + [ module(Module, [ optional(false), description("Name of module to graph") ]), + chain(Chain, [ optional(true), default(4), nonneg, description("unflatten -c parameter") ]), + link(Link, [ optional(true), default(4), nonneg, description("unflatten -l parameter") ]), + format(Fmt, [ optional(true), default(svg), atom, description("Graphviz output format") ]) + ]), + debug(callgraph_ui,"Calling callgraph on ~w.",[Module]), + http_link_to_id(pldoc_object,[object=''],DocBase), + Method=unflatten([fl(Link),c(Chain)]), + with_mutex(callgraph, + with_temp_dir(Dir, ( + atomic_list_concat([Dir,'/',Module,'.',Fmt],File), + with_output_to(string(_), module_render(Module,[ filename(File), linkbase(DocBase), format(Fmt), method(Method)])), + reply_file(File,Fmt)))). + + +%% callgraph_ui(+Request) is det. +% Web page containing a form for a module name and an output area for +% rendered graphs. The form and view area are created using the callgraph_view//1 component. +callgraph_ui(_) :- + reply_html_page(cliopatria(wide), [title("Module callgraph")], + [ h1("Module callgraph") , \callgraph ], + [ stable ]). + +callgraph --> + {http_location_by_id(callgraph_render,Loc)}, + html_requires(js('callgraph.js')), + html_requires(js('svg-pan-zoom.min.js')), + html_requires(jquery), + html_post(head,style("svg text {font-family:Times}")), + % html_post(head,script(type("text/javascript"), + % "$(document).ready(function() { $('#output').on('load',activate_obj); });")), + html( div(class="callgraph-ui", + [ form([class=forms,target=dummy,method=post,action="about:blank",onsubmit="return false;"], + [ label(["Module" + , div(class="input-groups", + [ input([type=text,autocomplete=on,name=module,id=module],[]) + , \seqmap( append_control, + [ %number(chain,1-10,4) + button(graph,"update_svg('~w');"-[Loc], "graph") + , button(clear,"clear_output();", "clear") + ]) + ])]) + , label(["Output" + , div([style="width:100%;height:25em;padding:0em",id=output,class="output-box"],[])]) + ]) + , iframe([id=dummy,style="display:none",src="about:blank"],["Dummy"]) + ])). + +append_control(B1) --> html(span(class="btn-append",\B1)). + +number(Id,Min-Max,Val) --> + html(input([type=number,id=Id,name=Id,min=Min,max=Max,value=Val,style="min-width:7ex"],[])). + +button(Id,OnClick,Label) --> + html(button([class="btn", onclick=OnClick,id=Id], Label)). diff -r 000000000000 -r 718306e29690 cpack/dml/applications/csv_ui.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/csv_ui.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,77 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(csv_ui, []). + +/** UI for viewing CSV files +*/ +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(decoration)). +:- use_module(library(htmlutils), [paginator//3]). +:- use_module(library(csvutils), [uri_to_csv/2]). +:- use_module(library(listutils), [drop/3,take/3]). +:- use_module(components(table), [table_from_goal//2]). +:- use_module(components(icons)). +:- use_module(cliopatria(hooks)). + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(root(dml/csv/view), csv_view, []). + +decoration:resource_view(URI,_) --> + { sub_string(URI,_,_,0,".csv") }, + { http_link_to_id(archive_get,[uri(URI)],EntryURL) }, + { http_link_to_id(csv_view,[uri(URI)],ViewURL) }, + html_requires(font_awesome), + html([ a(href=EntryURL, [\icon(download)," Download"]), &('MediumSpace') + , a(href=ViewURL, [\icon(table)," View"])]). + +decoration:resource_decoration(URI,Link) --> + { sub_string(URI,_,_,0,".csv") }, !, + { http_link_to_id(csv_view,[uri(URI)],ViewURL) }, + html_requires(font_awesome), + html( span( [ a(href(ViewURL),\icon(table)) + , &(nbsp), \Link + ])). + +csv_view(Request) :- + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of CSV file")]) + , page(Page, [ nonneg, default(1) ]) + , limit(Limit, [ nonneg, default(50) ]) + ]), + uri_to_csv(URI,Rows), + length(Rows,Total), + Offset is Limit*(Page-1), + Pages is ceil(Total/Limit), + insist(Page= Rows1=Rows2; take(Limit,Rows1,Rows2)), + format(string(FullTitle),"CSV view for ~w",[URI]), + reply_html_page(cliopatria(demo), [title(FullTitle)], + [ h1(FullTitle) + , \paginator(csv_view-[uri(URI),limit(Limit)],Page,Pages) + , \table_from_goal(csv_row(Rows2),[]) + , \paginator(csv_view-[uri(URI),limit(Limit)],Page,Pages) + ]). + +csv_row(Rows,Row) :- member(R,Rows), R=..[_|Row]. + diff -r 000000000000 -r 718306e29690 cpack/dml/applications/dml_overview.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/dml_overview.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,93 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_overview, []). + +/** DML Overview pages +*/ + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(dcg_core)). +:- use_module(library(rdfutils)). +:- use_module(library(httpfiles),[reply_html_page/4]). +% :- use_module(components(score)). +% :- use_module(api(score)). + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(root(dml/overview/top), dml_overview, []). + +dml_overview(_Request) :- + rdf(Rec,beets:title,literal(substring('I want to talk about you'),_)), + reply_html_page(cliopatria(demo), [title("DML Overview")], + [ html_post(head,style( ["h2 { margin-top:1em }"])) + , h1("Digital Music Lab Overview") + , h2("Knowledge representation: relational models and RDF") + , h2("Exploring the collections") + , p([ "The music libraries are organised in to 'graphs' (RDF sub-databases) on the basis of their origin. " + , "One way to explore them is to start from the page for each graph, and examine the predicates and classes " + , "the use to describe their content. For example, one can browse a list of values of the 'charm:composer' " + , "predicate and from their find recordings that have particular values of that property."]) + , p(\ll(list_predicates,[graph(bl_p2r)],"Predicates in the British Library recordings graph")) + , \ll(list_predicates,[graph(charm_p2r)],"Predicates CHARM collection graph") + % , p("The CHARM collection contains works by many composers. This pie chart shows the top 25 composer by number of recordings.") + % , \charm_composers_plot + , h2("The semantic web") + , p([ "DML can follow Musicbrainz URIs to retrieve information from the Linkedbrainz SPARQL endpoint and " + , "the Musicbrainz XML web service. Information from Linkedbrainz is already in Music Ontology format, " + , "but information from Musicbrainz is reorganised on import to conform to the Music Ontology's schema " + , "of events to describe composition, recordinging, and other music related data." ]) + , p(\ll(list_resource,[r(Rec)],"A recording with Musicbrainz links.")) + , h2("Symbolic scores") + , p("The database includes symbolic scores in Humdrum/Kern format obtained from the KernScores website.") + , p(\ll(list_predicate_resources,[side=object,graph=humdrum_p2r,predicate='http://dml.org/humdrum/schema/refcode/COM'],"Humdrum scores by Bach")) + , h2("Computation and memoisation") + , \ll(list_instances,[graph=memo_p2r,class='http://dml.org/memo/Function'],"Memoised functions") + , h2("SWISH: collaborative web-based Prolog") + , p([ "DML embeds a SWISH server to provide a web-based Prolog programming environment with access to the " + , "DML database and analsis functions, as well as facilities for visualising results and collaborative development." ]) + , p(html(a(href('/cp/swish/p/c3examples.swinb#'),"Music library statistics visualised using C3 graphics"))) + ], + [stable]). + +ll(ID,Params,HTML) --> line(\link(ID,Params,HTML)). +link(ID,Params,HTML) --> + {http_link_to_id(ID,Params,Link)}, + html(a(href(Link),HTML)). + +line(HTML) --> html(HTML), html(br([])). + +:- rdf_meta collection_property_hist(+,r,+,-). +collection_property_hist(Coll,P,Min,c3{data:_{columns:Pairs, type:pie}}) :- + setof([C,N], (collection_property_value_count(Coll,P,literal(C),N),N>Min), Pairs). + +collection_property_value_count(Collection,Property,Value,Count) :- + aggregate(count, R^(collection(Collection,R), rdf_has(R,Property,Value)), Count). + +collection(charm,X) :- rdf(X,charm:file_name,_). +collection(bl,X) :- rdf(X,rdf:type,mo:'Signal',bl_p2r). + +charm_composers_plot --> + {swish_render:renderer(c3,C3Mod,_)}, + {collection_property_hist(charm,dml:composer,25,Pairs)}, + % !!! This is not working. + C3Mod:term_rendering(Pairs,_,[]). + diff -r 000000000000 -r 718306e29690 cpack/dml/applications/memo_ui.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/memo_ui.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,159 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(memo_ui, []). + +/** UI for viewing memoised functions +*/ +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(decoration)). +:- use_module(library(htmlutils)). +:- use_module(library(memo)). +:- use_module(library(async)). +:- use_module(library(listutils)). +:- use_module(library(httpfiles)). +:- use_module(components(table)). +:- use_module(components(icons)). +:- use_module(cliopatria(hooks)). + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(root(dml/memo/view), memo_view, []). +:- http_handler(root(dml/jobs/view), job_view, []). +:- http_handler(root(dml/jobs/cancel), cancel_job, []). + +decoration:resource_view(URI,_) --> + { rdf(URI,rdf:type,memo:'Function'), !, + uripattern:pattern_uri(\func(Mod,Pred,Arity),URI), + format(string(Name),"~w:~w/~d",[Mod,Pred,Arity]), + http_link_to_id(pldoc_object,[object=Name],DocLink), + http_link_to_id(memo_view,[uri(URI)],ViewURL) + }, + html_requires(font_awesome), + html( [ a(href=ViewURL, [\icon(table)," View"]), ' ' + , a(href=DocLink, [\icon(book)," Documentation"]) + ]). + +decoration:resource_decoration(URI,Link) --> + { rdf(URI,rdf:type,memo:'Function'), !, + % uripattern:pattern_uri(dml: \func(Mod,Pred,Arity),URI), + % format(string(Name),"~w:~w/~d",[Mod,Pred,Arity]), + % http_link_to_id(pldoc_object,[object=Name],DocLink), + http_link_to_id(memo_view,[uri=URI],ViewLink) + }, + html_requires(font_awesome), + html( span( [ a(href(ViewLink),\icon(table)), &(nbsp) + % , a(href(DocLink),\icon(book)), &(nbsp) + , \Link ])). + +memo_view(Request) :- + http_parameters(Request, + [ uri(URI, [ optional(false), description("URI of CSV file")]) + , page(Page, [ nonneg, default(1) ]) + , limit(Limit, [ nonneg, default(50) ]) + ]), + format(string(FullTitle),"View for ~w",[URI]), + uripattern:pattern_uri(\func(Mod,Pred,Arity),URI), + length(Args,Arity), + Head =.. [Pred|Args], + aggregate_all(count,browse(Mod:Head),Total), + ( Total=0 + -> Content=p("This function has no successful memoised computations.") + ; Offset is Limit*(Page-1), + Pages is ceil(Total/Limit), + insist(Page= Rows1=Rows2; take(Limit,Rows1,Rows2)), + Content = [ \paginator(memo_view-[uri(URI),limit(Limit)],Page,Pages) + , \table_from_goal(goal_row(limit(Limit,offset(Offset,browse(Mod:Head))),Args),[]) + , \paginator(memo_view-[uri(URI),limit(Limit)],Page,Pages) + ] + ), + reply_html_page(cliopatria(demo), [title(FullTitle)], [ h1(FullTitle) | Content ], [unstable]). + +cancel_job(Request) :- + insist(user_db:logged_on(_),not_authorised(cancel_job)), + http_parameters(Request, + [ pool(Pool, [ atom, optional(false) ]) + , id(Id, [ atom, optional(false) ]) + , return_to(ReturnTo, [ atom, default(_) ]) + ]), + async_cancel(Pool,Id), % !!! this could throw an error + (var(ReturnTo) -> member(referer(ReturnTo),Request); true), + debug(async,'Cancelling job ~w:~w, returning to ~w',[Pool,Id,ReturnTo]), + http_redirect(see_other,ReturnTo,Request). + +job_view(Request) :- + http_parameters(Request, [pool(Pool, [atom, default(vis_cla)])]), + format(string(FullTitle),"Current jobs in thread pool ~w",[Pool]), + findall(job(Goal,ID,TSub,Status),async_current_job(Pool,Goal,ID,TSub,Status),Jobs), + reply_html_page(cliopatria(demo), [title(FullTitle)], + [h1(FullTitle), \job_tables(Pool,Jobs)], + [unstable]). + +job_tables(Pool,Jobs) --> + {partition(is_waiting, Jobs, Waiting, Running)}, + ( {Running=[]} -> html(h3("No jobs running.")) + ; html( [ h3("Running jobs") + , \table_from_goal(running_job(Pool,Running), + [headings(['Started','Elapsed','Progress','Goal','Actions'])]) + ]) + ), + ( {Waiting=[]} -> html(h3("No jobs waiting.")) + ; html( [ h3("Waiting jobs") + , \table_from_goal(waiting_job(Pool,Waiting), + [headings(['Position','Submitted','Goal','Actions'])]) + ]) + ). + + +is_waiting(job(_,_,_,waiting(_))). + +waiting_job(Pool,Jobs,[Pos,TSubmit,GoalCell,a(href(Cancel),cancel)]) :- + member(job(Goal,ID,TSubmit,waiting(Pos)),Jobs), % !!! add submit time to table? + http_link_to_id(cancel_job,[pool=Pool,id=ID],Cancel), + goal_cell(Goal,GoalCell). +running_job(Pool,Jobs,[StartS,ElapsedS,ProgressS,GoalCell,a(href(Cancel),cancel)]) :- + member(job(Goal,ID,_TSubmit,running(Thread,Start)),Jobs), + http_link_to_id(cancel_job,[pool=Pool,id=ID],Cancel), + format_time(string(StartS),'%FT%T%:z',Start), + debug(async,'Getting running job progress from thread ~w...',[Thread]), + catch(( async_thread_progress(Thread,[summary],TNow,[Progress]), + progress_string(Progress,ProgressS), + Elapsed is TNow-Start, format(string(ElapsedS),'~2f',[Elapsed]) + ), Ex, ( debug(async,'Failed to get job progress ~q',[Ex]), + ElapsedS="N/A", ProgressS="ENDED")), + copy_term(Goal,Goal1), + numbervars(Goal1,0,_), + goal_cell(Goal1,GoalCell). + +goal_cell(Mod:Head,a(href(URL),GoalS)) :- + functor(Head,Pred,Arity), + uripattern:pattern_uri(\func(Mod,Pred,Arity),URI), + http_link_to_id(list_resource,[r(URI)],URL), + term_cell(Mod:Head,GoalS). + +progress_string(Progress,String) :- memberchk(stepwise(_Desc,Done/Total), Progress), !, format(string(String),'~d/~d',[Done,Total]). +progress_string(_Terms, "-"). + +goal_row(Pred,Vals,Cells) :- call(Pred), maplist(term_cell,Vals,Cells). +term_cell(Term,Cell) :- + with_output_to(string(Cell),write_term(Term,[quoted(true),max_depth(6),numbervars(true)])). + diff -r 000000000000 -r 718306e29690 cpack/dml/applications/score_ui.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/score_ui.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,165 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(score_ui, [ sonify_ui//2]). + +/** Score related pages and hooks + + This module provides a web pages for displaying rendered scores and for + an audio player to play sonified scores. + It also module provides resource decorations and local view customisations + for Humdrum scores. +*/ + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(semweb/rdfs)). +:- use_module(library(semweb/rdf_label)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_codes)). +:- use_module(library(decoration)). +:- use_module(library(rdfutils)). +:- use_module(library(httpfiles)). +:- use_module(components(score)). +:- use_module(components(icons)). +:- use_module(api(score)). + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(root(dml/score/audio), score_audio, []). +:- http_handler(root(dml/score/view), score_view, []). + +decoration:resource_decoration(URI,Link) --> + {rdfs_individual_of(URI,hum:'File')}, !, + {http_link_to_id(score_view,[uri(URI)],ScoreURL)}, + {http_link_to_id(score_sonify,[uri(URI),format(ogg)],AudioURL)}, + html_requires(font_awesome), + html_requires(js('add_dummy_iframe.js')), + html( span( [ a(href(ScoreURL),\icon(music)) + , &(nbsp), a([href(AudioURL),target(dummy)],\icon(play)) + , &(nbsp), a([href('about:blank'),target(dummy)],\icon(stop)) + , &(ensp), \Link + ])). + +rdf_label:label_hook(URI,literal(Lit)) :- + rdf(URI,rdf:type,hum:'File'), + (var(Lit) -> Lit=Label; Lit=lang(_,Label)), + phrase_string(uri_label(URI),Label). + +uri_label(URI) --> + {atom_concat('kern:',File,URI)}, + file_label(URI,File). + +file_label(URI,File) --> + { suffix(30,File,ShortFile) }, + at(ShortFile), + if(rdf_text(URI,hum:'refcode/OTL',Title), (" - ",at(Title)," ")), + if((rdf_text(URI,hum:'refcode/COM',Composer),short_name(Composer,Comp)), + paren(at(Comp))). + +suffix(MaxLen,String,Shorter) :- + string_length(String,N), + ( N= + {rdfs_individual_of(URI,hum:'File')}, + {http_link_to_id(score_view,[uri(URI)],ViewURL)}, + html([ a(href=ViewURL, [\icon(music), " View score"]), &('MediumSpace') + , br([]), "Download as:" + , \seqmap(link(URI),[s-kern,s-mxml,s-lily,s-abc,a-midi]) + , \seqmap(render_link(URI),[pdf]) + , h2("Score sonification") + % , br([]), "Download audio as:" + % , \seqmap(link(URI),[a-ogg,a-mp3]) + % , br([]) + % , \score_audio_player(URI) + , \sonify_ui(URI,score_ui:score_audio) + , \pitch_class_histogram(URI) + ]). + + +score_audio(Request) :- + http_parameters(Request, + [ uri(URI, [optional(false), description("URI of score to render")]) + , autoplay(Auto, [boolean, default(false)]) + ], [form_data(Params)]), + reply_html_page(cliopatria(bare), [title("Audio element")], + \score_audio_player(URI,[autoplay(Auto)],Params), + [stable]). + +score_view(Request) :- + http_parameters(Request, + [ uri(URI, [optional(false), description("URI of score to render")]) + , width(W, [ optional(true), default(170), nonneg + , description("Page width in mm") ]) + ]), + ( (rdf_text(URI,hum:'refcode/OPT',Parent);rdf_text(URI,hum:'refcode/OPR',Parent)) + -> (rdf_text(URI,hum:'refcode/OTL',Title); Title=""), + format(string(FullTitle),"~w, ~w",[Parent,Title]) + ; (rdf_text(URI,hum:'refcode/OTL',FullTitle); FullTitle="") + ), + (rdf(URI,hum:'refcode/COM',Composer); Composer=""), + reply_html_page(cliopatria(demo), [title(FullTitle)], + [ h1(FullTitle) + , h2(['By ',Composer]) + , p([ "Resource view: ", \(cp_label:rdf_link(URI,[decoration(false), resource_format(nslabel)])) + % , br([]) + % , "Download as:" + % , \seqmap(link(URI),[s-kern,s-mxml,s-lily,s-abc,a-midi]) + % , \seqmap(render_link(URI),[pdf]) + , \sonify_ui(URI,score_ui:score_audio) + % , br([]), "Download audio as:" + % , \seqmap(link(URI),[a-ogg,a-mp3]) + % , br([]) + % , \score_audio_player(URI) + , br([]) + ]) + , \score(URI,W) + ], + [stable]). + +render_link(URI,Fmt) --> + {http_link_to_id(score_render,[uri(URI),layout(page),format(Fmt)],URL), + string_concat("score.",Fmt,Filename)}, + html([" ",a([href=URL,download=Filename],Fmt)]). + +link(URI,R-Fmt) --> + { variant_sha1(URI,Hash), + atomics_to_string([score,Hash,'.',Fmt],Filename), + get_link(URI,R-Fmt,URL) + }, + html([" ",a([href=URL,download=Filename],Fmt)]). + diff -r 000000000000 -r 718306e29690 cpack/dml/applications/transcription_ui.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/applications/transcription_ui.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,101 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(transcription_ui, []). + +/** Score related pages and hooks + + This module provides a web pages for displaying rendered scores and for + an audio player to play sonified scores. + It also module provides resource decorations and local view customisations + for Humdrum scores. +*/ + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(computations)). +:- use_module(library(csvutils)). +:- use_module(library(decoration)). +:- use_module(library(httpfiles)). +:- use_module(library(sandbox)). +:- use_module(library(real)). +:- use_module(api(transcription)). +:- use_module(components(audio), [audio_player//2]). +:- use_module(components(r_fig), [figure//4]). +:- use_module(applications(score_ui)). + +:- set_prolog_flag(double_quotes,string). + +:- http_handler(root(dml/transcription/audio), transcription_audio, []). + +decoration:resource_view(URI,_) --> + { once(rdf(Comp,dml:'comp/output',URI)), + rdf(Comp,dml:'comp/function',Transform), + rdf(Transform,vamp:plugin,vamp_plugins:'silvet#silvet') }, + html([ h2("Transcription sonification") + , \sonify_ui(URI,transcription_ui:transcription_audio) + , \figure(piano_roll(URI),20,8,[]) + ]). + +decoration:resource_view(URI,_) --> + { once(rdf(Comp,dml:'comp/output',URI)), + rdf(Comp,dml:'comp/function',Transform), + computations:transform(chord_notes,Transform) }, + html([ h2("Chord notes sonification") + , \sonify_ui(URI,transcription_ui:transcription_audio) + ]). + +transcription_audio(Request) :- + http_parameters(Request, + [ uri(URI, [optional(false), description("URI of transcription to sonify")]) + , autoplay(Auto, [boolean, default(false)]) + ], [form_data(Params)]), + maplist(transcription_audio_link(URI,Params),[ogg,mp3],Links), + reply_html_page(cliopatria(bare), [title("Audio element")], + \audio_player(Links,[autoplay(Auto)]), + [stable]). + +transcription_audio_link(URI,Params,Fmt,URL-just(Fmt)) :- + transcription_link(URI,a(Params)-Fmt,URL). + +freq_pitch_name_number(Freq,'',NN) :- !, freq_note_number(Freq,NN). +freq_pitch_name_number(_,Pitch,NN) :- remove_cents(Pitch,Pitch1), pitch_name_number(Pitch1,NN). + +piano_roll(URI) :- + uri_to_csv(URI,Rows), + maplist(computations:column(transcription),[time,dur,freq,vel,pitch],Cols), + rows_cols(Cols,Rows,[Time,Dur,Freq,Vel,Pitch]), + maplist(freq_pitch_name_number,Freq,Pitch,NoteNum), + aggregate_all(min(NN)-max(NN),member(NN,NoteNum),MinNN-MaxNN), + % using ggplot2? ... + % r( ggplot() + % +geom_rect('data.frame'([t=Time,d=Dur,v=Vel,nn=NoteNum]), + % mapping(xmin=t,xmax=t+d,ymin=nn-0.4,ymax=nn+0.4,alpha=0.25+v/256)) + % +theme_minimal()), + r(par(ps=10,mar=[2.1,2.2,0.1,0],yaxs="i",xaxs="i")), + r(plot(x='NULL',y='NULL',xlim=c(0,max(Time+Dur)),ylim=c(MinNN-0.5,MaxNN+0.5),type="n",xlab="time/s",ylab="notenum",tcl=0.2)), + r(rect(Time,NoteNum-0.4,Time+Dur,NoteNum+0.4,border='NA',col=rgb(0,0,0,64+Vel,maxColorValue=255))). + +remove_cents(P1,P2) :- sub_atom(P1,Bef,_,_,'-'), !, sub_atom(P1,0,Bef,_,P2). +remove_cents(P1,P2) :- sub_atom(P1,Bef,_,_,'+'), !, sub_atom(P1,0,Bef,_,P2). +remove_cents(P1,P1). + +sandbox:safe_primitive(transcription_ui:piano_roll(_)). diff -r 000000000000 -r 718306e29690 cpack/dml/components/audio.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/audio.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,143 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(cp_audio, + [ audio_player//1 + , audio_player//2 + , audio_decoration//3 + , spectrogram//2 + , audio_link/3 + , audio_file/3 + , audio_playlist//2 + , finder_player/2 + , finder_player/3 + ]). + +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_path)). +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/js_write)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_label),[rdf_label/2]). +:- use_module(library(dcg_core)). +:- use_module(library(httpfiles)). +:- use_module(library(optutils)). +:- use_module(components(icons)). + +:- multifile audio_link/3, audio_file/3. +:- rdf_meta audio_link(r,-,-). + +:- html_resource(js('add_dummy_iframe.js'), [requires(jquery)]). + + +%% audio_decoration(+Type:oneof([none,link,player]), +Links:list(pair(url,maybe(filetype))), +Content:phrase) is det. +% +% Emits the HTML content specified by Content, but optionally decorated with controls +% that allow any associated audio to be played. Links is a list of pairs of links to audio +% content with an optional filetype, where a filetype is a standard audiofile extension like +% mp3, ogg, wav etc. +audio_decoration(none,_,Link) --> phrase(Link). + +audio_decoration(link,[URL|_],Link) --> + html_requires(font_awesome), + html_requires(js('add_dummy_iframe.js')), + html(span( [ a([href(URL),target(dummy)],\icon(play)) + , &(nbsp), a([href('about:blank'),target(dummy)],\icon(stop)) + , &(ensp), \Link + ])). + +audio_decoration(player,URLS,Link) --> + html(span(style="display:inline-block;width=auto", + [ div(\audio_player(URLS)), div(\Link) ])). + +audio_player(Links) --> audio_player(Links,[]). +audio_player(Links,Attribs) --> + html(audio([ controls, preload=none | Attribs ], + [ \seqmap(audio_source,Links), + "Your browser does not support HTML5 audio." ])). + +audio_playlist(ID,Links) --> + % html_requires(js('playlist.js')), + {http_absolute_location(js('playlist.js'),PlaylistJS,[])}, + {Links=[item(Src1,_,_)|_]}, + html( div(class(playlist), + [ style([ 'div.playlist ul {list-style-type:none; margin:0px;padding:0px;height:10em;overflow:auto }' + , 'div.playlist li div {display:block}' + , 'div.playlist li div a {color:#ccc;text-decoration:none;overflow-x:hidden}' + , 'div.playlist li div a:hover {color:white}' + , 'div.playlist li.active {color:black;background-color:#eee}' + , 'div.playlist li.active div a {color:black}' + , 'div.playlist {padding:1ex;background-color:#222;width:400px;border-radius:1ex}' + ]) + , audio([ id('~w-audio'-[ID]), controls, preload=none ], + [ source([src=Src1],[]), "Your browser does not support HTML5 audio." ]) + , ul(id('~w-list'-[ID]), \alinks(1,Links)) + , \js_script({|javascript(PlaylistJS,ID)|| + $.getScript(PlaylistJS, function(x,y,z){init_playlist(ID)})|}) + % , script(type('text/javascript'),'init_playlist(~w)'-ID) + ])). + +alinks(NSelected,Links) --> alinks(NSelected,1,Links). +alinks(_,_,[]) --> !. +alinks(N,N,[Item|Links]) --> !, {succ(N,M)}, html(li(class(active),\alink(Item))), alinks(N,M,Links). +alinks(S,N,[Item|Links]) --> !, {succ(N,M)}, html(li(\alink(Item))), alinks(S,M,Links). +alink(item(URL,Label,Page)) --> + html(div([ a([href(Page),target('_blank')],\icon('external-link')),' ' + , a([class(audio),href(URL)],Label)])). + + +audio_source(URL-Fmt) --> + ( {Fmt=just(Type), mime_type(Type,MimeType)} + -> html(source([src=URL,type=MimeType],[])) + ; html(source([src=URL],[])) + ). + + +%% spectrogram(+URI, +Options) is det. +% +% Emits HTML for a spectrogram viewer for a given recording URI. The viewer +% includes controls for controlling the time window extracted from the full signal. +spectrogram(URI,Opts) --> + { seqmap( option_default_select, + [offset(Off), length(Len), width(W), height(H)], + [0, 60, 15, 7], + Opts,Opts1), + http_link_to_id(spectrogram_window, + [ uri(URI), offset(Off), length(Len), width(W), height(H) | Opts1 ], + SpectroURL ) + }, + html_requires(font_awesome), + html(iframe([ frameborder=0, seamless=seamless, src=SpectroURL, + scrolling=no, style="width:100%;height:~dcm"-[H] ],[])). + +:- meta_predicate finder_player(1,-). +%% finder_player(+Finder:pred(-uri), -Player:html_term) is det. +finder_player(Finder,html(\audio_playlist(ID,Items))) :- + gensym(pl,ID), + findall(item(H,L,P),( call(Finder,X), + http_link_to_id(list_resource,[r(X)],P), + audio_link(X,H,_), + rdf_label(X,L) + ), Items). + +%% finder_player(@URI:uri, +Finder:goal, -Player:html_term) is det. +:- meta_predicate finder_player(-,0,-). +finder_player(R,Goal,Player) :- finder_player(call1(R,Goal),Player). +call1(R,Goal,R) :- call(Goal). + diff -r 000000000000 -r 718306e29690 cpack/dml/components/icons.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/icons.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,9 @@ +:- module( icons, [icon//1]). + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). + +icon(Name) --> + {string_concat("fa fa-",Name,Class)}, + html_requires(font_awesome), + html(i(class(Class),[])). diff -r 000000000000 -r 718306e29690 cpack/dml/components/matlab.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/matlab.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,115 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(cp_matlab, + [ figure//4 + , figure//3 + , term_rendering//3 + ]). + +:- meta_predicate figure(0,+,+,+,?,?). +:- meta_predicate figure(0,+,+,?,?). +:- meta_predicate figure(0,+,?,?). + +:- use_module(library(http/http_dispatch),[http_link_to_id/3]). +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(dcg_core)). +:- use_module(library(listutils)). +:- use_module(library(optutils)). +:- use_module(library(pengines_io)). +:- use_module(library(swish/render)). +:- use_module(library(mlserver)). +:- use_module(library(code_cache)). +:- use_module(library(insist)). +:- use_module(components(smartimg)). + +:- register_renderer(matlab,"Render Matlab figures"). + +:- html_resource(js('smartimg.js'), []). % no requirements + +%% term_rendering(FigSpec,Something,Opts)// is det. +% +% Matlab term rendering. +% Output from Matlab code is send to current_output of Matlab server thread (usually user_output). +% Options are: +% * timeout(T:float) +% * format(F:oneof([svg,png])) +% And any accepted by api_matlab:figure_render/1.r +term_rendering(fig(Code),_,Opts) --> + {rendering_options(T,Opts,Opts1)}, + figure(mlserver:ml_async(exec(Code),T), Opts1). +term_rendering(fig(Code,W,H),_,Opts) --> term_rendering(fig(Code),_,[width(W),height(H)|Opts]). +term_rendering(fig(Code,FOpts),_,Opts) --> + {merge_options(FOpts,Opts,Opts1)}, + term_rendering(fig(Code),_,Opts1). + +rendering_options(T) --> + seqmap(option_default_select,[module(_),numbervars(_),quoted(_)],_), + option_default_select(timeout(T),60). + +user:portray(ws(X)) :- ml_ws_name(X,Var,Eng), format('ws(|~w:~w|)',[Eng,Var]). +pengines_io:blob_rendering(ws,_Blob,_) --> + html(span(class='pl-blob','ws:_')). + +%% figure(+Code:callable, +Width:natural, +Height:natural, +Params:list)// is det. +%% figure(+Code:callable, +Width:natural, +Height:natural)// is det. +% +% Component to render a Matlab figure into a HTML code. Code must be a Prolog +% goal that renders the desired figure into Matlab's current figure. +% The default figure format (eg SVG or PNG) is taken from the default_figure_format +% setting. Options are +% * cache(boolean) +% If true (default: false), put the code in a cache and use its unique id to call +% it. Useful for code that is to long to encode in a URL. +% * downloadable(boolean) +% If true (default: false), add download links (for PDF and EPS formats) below the image. +% * smart(boolean) +% If true (default: false), then use Javascript image loading code instead of a standard HTML +% tag. If the server returns an error HTML page, this is displayed +% instead of the image. +% See api_matlab:figure_render/1 for other valid options. +figure(Code,W,H) --> figure(Code,[width(W),height(H)]). +figure(Code,W,H,Params) --> figure(Code,[width(W),height(H)|Params]). +figure(Code,Params) --> + { debug(cp_matlab,"figure(~q,~q)",[Code,Params]), + process_options(Download,Smart,Code,Params,Params1), + insist(option(width(W),Params1), missing_parameter(width)), + insist(option(height(H),Params1), missing_parameter(height)), + http_link_to_id(figure_render, Params1,URL) + }, + ( {Download=true} + -> { option_default_select(format(_),_,Params1,Params2)}, + html(div([\image(Smart,URL,W,H),br([]), 'Download as:', \download(pdf,Params2), \download(eps,Params2)])) + ; image(Smart,URL,W,H) + ). + +download(F,Params) --> + {http_link_to_id(figure_render,[format(F)|Params],URL)}, + html([' ',a([href(URL),download],F)]). + +process_options(Download,Smart,Code) --> + {setting(matlab:default_figure_format,Fmt0)}, + seqmap(option_default_select, [format(Fmt), cache(Cache), downloadable(Download), smart(Smart)], + [Fmt0,false,false,false]), + (select_option(color_map(CM)) -> {term_to_atom(CM,CMA)}, cons(color_map(CMA)); []), + (select_option(size(W,H)) -> cons(width(W)), cons(height(H)); []), + {Cache=true -> cache_code(Download,Code,Code1); Code=Code1}, + {term_to_atom(Code1,CodeAtom)}, + cons(format(Fmt)), + cons(code(CodeAtom)). diff -r 000000000000 -r 718306e29690 cpack/dml/components/r_fig.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/r_fig.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,92 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(cp_r_fig, + [ figure//4 + , figure//3 + , term_rendering//3 + ]). + +:- meta_predicate figure(0,+,+,+,?,?). +:- meta_predicate figure(0,+,+,?,?). + +:- use_module(library(http/http_dispatch),[http_link_to_id/3]). +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(dcg_core)). +:- use_module(library(listutils)). +:- use_module(library(optutils)). +:- use_module(library(pengines_io)). +:- use_module(library(swish/render)). +:- use_module(library(code_cache)). +:- use_module(library(insist)). +:- use_module(library(real)). +:- use_module(components(smartimg)). + +:- register_renderer(rfig,"Render R figures"). + +term_rendering(rfig(Code),_,Opts) --> + {rendering_options(Opts,Opts1)}, + figure(r(Code),Opts1). +term_rendering(rfig(Code,W,H),_,Opts) --> + term_rendering(rfig(Code),_,[width(W),height(H)|Opts]). +term_rendering(rfig(Code,FOpts),_,Opts) --> + {merge_options(FOpts,Opts,Opts1)}, + term_rendering(rfig(Code),_,Opts1). + +rendering_options --> + seqmap(option_default_select,[module(_),numbervars(_),quoted(_)],_). + + +%% figure(+Code:callable, +Width:natural, +Height:natural, +Params:list)// is det. +%% figure(+Code:callable, +Width:natural, +Height:natural)// is det. +% +% Component to render an R figure into a HTML code. Code must be a Prolog +% goal that renders the desired figure. +% The default figure format (eg SVG or PNG) is taken from the default_figure_format +% setting. See figure_render/1 for valid parameters. +figure(Code,W,H) --> figure(Code,[width(W),height(H)]). +figure(Code,W,H,Params) --> figure(Code,[width(W),height(H)|Params]). +figure(Code,Params) --> + { debug(r_fig,"figure(~q,~q)",[Code,Params]), + process_options(Download,Smart,Code,Params,Params1), + insist(option(width(W),Params1), missing_parameter(width)), + insist(option(height(H),Params1), missing_parameter(height)), + http_link_to_id(r_figure_render, Params1, URL) + }, + ( {Download=true} + -> { option_default_select(format(_),_,Params1,Params2)}, + html(div([\image(Smart,URL,W,H),br([]),'Download as:', \download(pdf,Params2), \download(eps,Params2)])) + ; image(Smart,URL,W,H) + ). + +download(F,Params) --> + {http_link_to_id(r_figure_render,[format(F)|Params],URL)}, + html([' ',a([href(URL),download],F)]). + + +process_options(Download,Smart,Code) --> + {setting(r_plot:default_figure_format,Fmt0)}, + seqmap(option_default_select, [format(Fmt), cache(Cache), downloadable(Download), smart(Smart)], + [Fmt0,false,false,false]), + (select_option(color_map(CM)) -> {term_to_atom(CM,CMA)}, cons(color_map(CMA)); []), + (select_option(size(W,H)) -> cons(width(W)), cons(height(H)); []), + {Cache=true -> cache_code(Download,Code,Code1); Code=Code1}, + {term_to_atom(Code1,CodeAtom)}, + cons(format(Fmt)), + cons(code(CodeAtom)). diff -r 000000000000 -r 718306e29690 cpack/dml/components/score.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/score.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,132 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(cp_score, + [ score//2, score//3 + , sonify_ui//2 + , score_audio_player//1 + , score_audio_player//3 + , pitch_class_histogram//1 + ]). + +:- use_module(library(http/html_write)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(dcg_core)). +:- use_module(library(musiclab)). +:- use_module(library(humdrum_p2r)). +:- use_module(library(mlserver)). +:- use_module(library(real)). +:- use_module(library(sandbox)). +:- use_module(components(matlab),[]). +:- use_module(components(r_fig),[]). +:- use_module(components(audio),[audio_player//2]). +:- use_module(api(score)). + +:- set_prolog_flag(double_quotes,string). + +%% score(+R:uri,+Width:number)// is det. +% +% Generates an HTML DIV element containing a rendered score. URI is assumed +% to refer to a Humdrum file. Width is in mm and is passed to Lilypond as +% the desired staff width. +score(URI,Width) --> score(URI,Width,[]). +score(URI,Width,Opts) --> + {option(transpose(T),Opts,'P1')}, + {http_link_to_id(score_render,[uri(URI),width(Width),layout(snip),format(svg),transpose(T)],URL)}, + html(div([id=score,width='100%',height=auto],[img([src=URL],[])])). + + +%% sonify_ui(+R:uri,+ID:hander_id)// is det +% +% Generates an interface for setting parameters and sonifying a Humdrum score. +sonify_ui(URI,HandlerID) --> + { http_link_to_id(HandlerID,[],AudioPlayerURL), + setting_property(score:fluidsynth_rc,type(oneof(RCs))), + setting(score:fluidsynth_rc,RC0), + Intervals=['-P5','-d5','-P4','-M3','-m3','-M2','-m2','P1','m2','M2','m3','M3','P4','d5','P5'] + }, + html([ form([class=forms,target=player,method=get,action=AudioPlayerURL], + [ input([type=hidden,name=uri,value=URI]) + , input([type=hidden,name=autoplay,value=true]) + %, input([type=hidden,name=format,value=ogg]) + , table([class=form], + [ tr([ th(class=label,"Tempo scaling factor"), + td(input([type=number,min=0,max=4,step=0.1,name=tempo,value=1],[]))]) + % , tr([ th(class=label,"Transposition in semitones"), + % td(input([type=text,name=transpose,value='P1'],[]))]) + , tr([ th(class=label,"Transposition interval"), + td(\html_select(transpose,Intervals,'P1'))]) + , tr([ th(class=label,"Fluidsynth initialisation"), + td(\html_select(fluidrc,RCs,RC0))]) + ]) + , input([type=submit,class=btn,value="Sonify"],[]) + , iframe([name=player,seamless=seamless,style="display:inline-block;height:3.2em"],[]) + ]) + ]). + +html_select(Name,Values,Initial) --> + html(select([name=Name], \seqmap(html_option(Initial),Values))). + +html_option(X,X) --> !, html(option(selected=selected,X)). +html_option(_,X) --> html(option(X)). + + +%% score_audio_player(+R:uri,+As:list(html_attrib),+Ps:list(http_param))// is det. +%% score_audio_player(+R:uri)// is det. +% +% Generates an HTML 5 audio player to play a sonified score. Ps is a list +% of HTTP parameters to be passed ultimately to score_sonify/1. As is a list +% of HTML element attributes to be added to the HTML AUDIO element. +score_audio_player(URI) --> score_audio_player(URI,[],[]). +score_audio_player(URI,Attr,Params) --> + {maplist(score_audio_link(URI,Params),[ogg],Links)}, + audio_player(Links, Attr). + +score_audio_link(URI,Params,Fmt,URL-just(Fmt)) :- get_link(URI,a(Params)-Fmt,URL). + + +%% pitch_class_histogram(+Lang:oneof([ml,r]),+R:uri)// is det. +% +% Generates a graphical rendering of the pitch class histogram computed +% from the given URI, assumed to refer to a Humdrum file. Figure is +% generated using Matlab. +pitch_class_histogram(URI) --> + cp_r_fig:figure( cp_score:pitch_class_histogram(r,URI), 12, 6, []). + % cp_matlab:figure( cp_score:pitch_class_histogram(ml,URI), 12, 6, []). + +pitch_class_histogram(Lang,URI) :- + hum_uri_path(URI,Path), + kern_pc_hist(Path,Hist1), + findall(PCN-X, (member(PC-X,Hist1), pitch_class_number(PC,PCN)), Hist2), + numlist(0,11,PCNs), + maplist(pc_number_name,PCNs,PCNames), + maplist(pcn_count(Hist2),PCNs,Counts), + ( Lang=r + -> r(par(ps=10,mar=[2.1,2.2,1.1,0])), + r(barplot(Counts,'names.arg'=PCNames,main="Pitch class histogram")) + ; Lang=ml + -> ?? ( bar(PCNs,Counts); + xticks(PCNs,cell(PCNames)); + title("Pitch class histogram"); + caxis([0,3])) + ). + +pcn_count(Hist,PCN,Count) :- member(PCN-Count,Hist) -> true; Count=0. + + +sandbox:safe_primitive(cp_score:pitch_class_histogram(_,_)). diff -r 000000000000 -r 718306e29690 cpack/dml/components/smartimg.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/smartimg.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,31 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +:- module(smartimg, [image//4]). + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/js_write)). + +image(false,URL,W,H) --> html(img([src=URL, class=matlabfig, style=("width:~dcm;height:~dcm"-[W,H])],[])). +image(true,URL,W,H) --> + html_requires(js('smartimg.js')), + {gensym(img,ID)}, + html(img([alt="loading image data", id=ID, class=matlabfig, + style=("width:~dcm;height:~dcm"-[W,H])],[])), + js_script({|javascript(ID,URL)||load_img2(ID,URL)|}). + diff -r 000000000000 -r 718306e29690 cpack/dml/components/table.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/components/table.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,45 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(cp_table, + [ table_from_goal//2 + ]). + +:- meta_predicate table_from_goal(1,+,?,?). + +:- use_module(library(http/http_dispatch),[http_link_to_id/3]). +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(dcg_core)). + +table_from_goal(Goal,Opts) --> + {findall(Row,call(Goal,Row),Rows)}, + ( {option(headings(Heads),Opts)} + -> html(table([\table_heads(Heads), \seqmap(table_row,Rows)])) + ; html(table(\seqmap(table_row,Rows))) + ). + +table_heads(Row) --> + html(tr(\seqmap(table_head,Row))). +table_row(Row) --> + html(tr(\seqmap(table_cell,Row))). + +table_cell(Cell) --> html(td(Cell)). +table_head(Cell) --> html(th(Cell)). + + diff -r 000000000000 -r 718306e29690 cpack/dml/config-available/dml.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/config-available/dml.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,192 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml, + [ call_debugging/2 + , call_nodebug/1 + , view_computations/0 + , start_matlab/0 + , stop_matlab/0 + , start_r_server/0 + , update/1 ]). + +/** DML main loader + */ + +:- set_prolog_flag(double_quotes, string). +:- debug_message_context(+time('%FT%T')). + +user:file_search_path(memo, cp_application(memo_db)). + +:- use_module(cp_application('config-enabled/dml_permission')). + +:- use_module(library(rcutils)). +:- use_module(library(http/http_dispatch)). +:- use_module(skin(minimal)). +:- use_module(library(dml_data)). +:- use_module(applications(callgraph_ui)). +:- use_module(applications(audio_ui)). +:- use_module(applications(score_ui)). +:- use_module(applications(csv_ui)). +:- use_module(applications(memo_ui)). +:- use_module(applications(transcription_ui)). +:- use_module(applications(dml_overview)). + +:- use_module(library(code_cache)). +:- use_module(library(dml_crawler)). +:- use_module(library(dml_spotify)). +:- use_module(library(dml_musicbrainz)). +:- use_module(library(dml_swish)). +:- use_module(library(dml_misc)). +:- use_module(library(musiclab)). +:- use_module(library(rdfutils)). +:- use_module(library(dlogic)). +:- use_module(library(dataset)). +:- use_module(library(mlserver), except([start_matlab/0,start_matlab/1])). +:- use_module(library(real)). +:- use_module(library(backend_json)). +:- use_module(library(dovamp)). +:- use_module(api(matlab)). +:- use_module(api(r_plot)). +:- use_module(api(archive)). +:- use_module(api(dmlvis)). +:- use_module(api(perspectives)). +:- use_module(api(transcription)). +:- use_module(components(audio)). +:- use_module(cliopatria(hooks)). + +cliopatria_openid:insecure_host('mirg.city.ac.uk'). + + +% Hooks for audio related services +cp_audio:audio_file(URI,File,Fmt) :- beets_p2r:audio_file(URI,File,Fmt). +cp_audio:audio_file(URI,File,Fmt) :- charm_p2r:audio_file(URI,File,Fmt). +cp_audio:audio_file(URI,File,Fmt) :- bl_p2r:audio_file(URI,File,Fmt). +cp_audio:audio_file(URI,File,Fmt) :- mazurka_p2r:audio_file(URI,File,Fmt). + +cp_audio:audio_link(URI,Link,just(mp3)) :- bl_p2r:audio_link(URI,Link). +cp_audio:audio_link(URI,URL,just(Fmt)) :- + bl_p2r:audio_file(URI,File,just(Fmt)), + file_permission(File,public), + http_link_to_id(audio_get,[uri(URI),format(Fmt)],URL). +cp_audio:audio_link(URI,Link,just(mp3)) :- charm_p2r:audio_link(mp3,URI,Link). +cp_audio:audio_link(URI,URL,just(Fmt)) :- + Formats=[ogg,mp3], % in order of preference + ( beets_p2r:audio_file(URI,File,just(Orig)) + ; mazurka_p2r:audio_file(URI,File,just(Orig)) + ), + file_permission(File,public), + (member(Orig,Formats) -> member(Fmt,Formats); member(Fmt,[Orig|Formats])), + http_link_to_id(audio_get,[uri(URI),format(Fmt)],URL). + +%:- rdf_set_cache_options([enabled(true),global_directory(cache)]). + +% ------------------ string portrayal ------------- +% user:portray(String) :- +% string(String), !, +% truncate(50,String,Short), +% writeq(Short). + +% truncate(Max,S,S) :- string_length(S,L), L remove_periodical(Id) + ; true + ), + periodically(3600,clean_code_cache(3600)). + +:- dynamic log_stream/1. +open_log :- + (log_stream(S) -> close(S), retractall(log_stream(_)); true), + expand_file_name('~/var/log/dml.log',[LogFile]), + open(LogFile,append,LogStream,[buffer(line)]), nl(LogStream), + assert(log_stream(LogStream)), + debug(log), debug(log,'Started logging.',[]). + + +:- meta_predicate call_debugging(?,0), call_nodebug(0). +call_debugging(Topic,Goal) :- setup_call_cleanup(debug(Topic), Goal, nodebug(Topic)). +call_nodebug(Goal) :- + setup_call_cleanup( (setof(T,debugging(T),Topics),maplist(nodebug,Topics)), Goal, maplist(debug,Topics)). + +view_computations :- + call_debugging(computations(item),termutils:with_status_line(get_single_char(_))). + +logging(dmlvis(method)). +logging(dmlvis(perspective)). +logging(log). + +prolog:debug_print_hook(computations(item),Fmt,Args) :- + termutils:status(Fmt,Args). + +prolog:debug_print_hook(Topic,Fmt,Args) :- + logging(Topic), log_stream(S), + get_time(T), + format(S,'~@ ~w | ~@\n',[format_time(current_output,'%FT%T',T), Topic, format(Fmt,Args)]), + fail. + +update(dml) :- + debug(log,'Updating dml-cliopatria repository.',[]), + shell('cd cpack/dml && hg pull && hg update'), + make. + +start_matlab :- start_matlab([]). +start_matlab(Opts) :- mlserver:start_matlab([path([dml(matlab)])|Opts]). +start_r_server :- real:r_start_server. + +:- multifile sandbox:safe_primitive/1. +:- multifile sandbox:safe_directive/1. +sandbox:safe_primitive(dml_permissions:file_permission(_,_)). +sandbox:safe_primitive(cp_audio:audio_link(_,_,_)). + +initiate_bl_scraping(Status) :- + format('% Initiating BL audio link scraping...\n',[]), + async:async_memo(vis_cla, bl_p2r:scrape_all([],_), Status, [recompute(failed),status_var(time-progress(summary))]). + +after_load :- + warm_indices, + initiate_bl_scraping(_), + start_r_server, + start_matlab. diff -r 000000000000 -r 718306e29690 cpack/dml/config-available/dml_permission.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/config-available/dml_permission.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,41 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_permissions, [file_permission/2]). + +/** control public access to DML resources + */ + +%% file_permission(+File,-Permission:oneof([public,user,private])) is det. +% This predicate is called to check whether or not the contents of a given +% file should be available. There are three levels of access: +% * public +% Accessible to everyone. +% * user +% Accessible to registered, logged in Cliopatria users. +% * private +% Accessible to no-one. +% The default level is private for all files. If you wish to make some files +% available, you must copy (not link) this file to the 'config-available' directory +% of your Cliopatria installation and edit the definition of file_permission/2 +% as you see fit. + +%file_permission(Path,public) :- atom_concat('/home/dml/lib/mazurka/',_,Path), !. +file_permission(_,public) :- user_db:logged_on(admin). +file_permission(_,private). + diff -r 000000000000 -r 718306e29690 cpack/dml/examples/c3examples.swinb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/examples/c3examples.swinb Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,56 @@ +
+ +
+# C3 Rendering examples + +This is an example of how to use C3 graphics to illustrate the content in the DML collection. +
+ +
+:- use_rendering(c3). + +%% collection(-C:oneof([charm,bl]), -X:uri) is nondet. +collection(charm,X) :- rdf(X,charm:file_name,_). +collection(bl,X) :- rdf(X,rdf:type,mo:'Signal',bl_p2r). + +collection_property_value_count(Collection,Property,Value,Count) :- + aggregate(count, R^(collection(Collection,R), rdf_has(R,Property,Value)), Count). + +% Unfortunately rdf_meta is not legal in sandbox yet. +%:- rdf_meta collection_property_hist(+,r,+,-). +%% collection_property_hist(+C:atom, +P:uri, +Min:nonneg, -Chart:dict) is det. +collection_property_hist(Coll,P,Min,c3{data:_{columns:Pairs, type:pie}}) :- + rdf_global_id(P,Prop), % expand Namespace:Local resource representation + setof( [C,N], (collection_property_value_count(Coll,Prop,literal(C),N),N>Min), Pairs). +
+ +
+Next a little test that we can use this to get pairs of composer and count. +
+ +
+aggregate(count, X^(collection(charm,X), rdf_has(X,dml:composer,C)), N). +
+ +
+Next a pie chart showing the proportions of different composers in the CHARM collection. (This query should run automatically when this notebook loads). If you click on the labels in the legend, that segment is removed and the pie redrawn. +
+ +
+collection_property_hist(charm,dml:composer,25,Pairs). +
+ +
+Finally, a couple more distributions over language and composer in the BL collection. Press the white-on-green arrow to run the query. +
+ +
+collection_property_hist(bl,dc:language,150,Pairs). +
+ +
+% top 20 composers +collection_property_hist(bl,dml:composer,20,Pairs). +
+ +
diff -r 000000000000 -r 718306e29690 cpack/dml/examples/csv_op_viewer.swinb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/examples/csv_op_viewer.swinb Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,65 @@ +
+ +
+:- use_module(library(computations)). +:- use_module(library(mlserver)). +:- use_module(library(real)). +:- use_module(library(dml_c3)). +:- include(search). +:- use_rendering(rdf,[resource_format(nslabel)]). +:- use_rendering(c3). + +transform_memo(Class,Transform,In,Out) :- + transform(Class,Transform), + computation_memo(Transform,In,Out). + +op_chart(Op,CSV,Chart) :- + csv_op(Op,CSV,Result), + csv_op_chart(Op,Result,Chart). +
+ +
+Histogram of durations of computations on CSV files. +
+ +
+findall(Dur,browse(computations:csv_op_memo(A,B,_C),comp(_,_,Dur)-ok),_Durs), +[Counts,Map] === hist1d(transpose(_Durs),edgemap(0:0.01:2)), +array_list(Counts,_LC), +c3_hist(steps,dur,Map,_LC,Chart). +
+ +
+Recording level analyses... +
+ +
+distinct(A,browse(computations:csv_op_memo(A,B,_C),comp(_,_,Dur)-ok)), +computation(_,Rec,B), +writeln(doing(A,B)), +csv_op_chart(A,_C,D). +
+ +
+Collection level analyses... +
+ +
+distinct(Name/Arity, + ( browse(perspectives:cla_memo(A,B,_C),comp(_,_,Dur)-ok), + functor(A,Name,Arity))), +cla_op_chart(A,_C,Chart), +dataset_size(B,Size). +
+ +
+This example shows how VAMP computations can be triggered on demand. +
+ +
+X :: title(piano) /\ title(sonata), +transform_memo(tempo,_,X,Y), +op_chart(uniform_tempo_r(linear,2),Y,Chart). +
+ +
diff -r 000000000000 -r 718306e29690 cpack/dml/examples/index.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/examples/index.json Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,9 @@ +// list of examples, represented as a JSON list +[ +"--", +{ "file":"c3examples.swinb", "title":"Using C3 graphics to visualise collection statistics" }, +{ "file":"csv_op_viewer.swinb", "title":"Graphical viewers for recording level analyses" }, +{ "file":"system_metrics.swinb","title":"Analytics on collection level performance" }, +"--", +{ "file":"visuals.pl", "title":"Plots and term renderings" } +] diff -r 000000000000 -r 718306e29690 cpack/dml/examples/system_metrics.swinb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/examples/system_metrics.swinb Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,217 @@ +
+ +
+## Analysis of collection level computation performance + +This following block of code defines some predicates for browsing the database of collection level computations and tagging them by what kind of computation it was, what the implementation language was, the date and time of the computation, the size of the collection and the duration of the computation. + +Scroll down the query boxes below and press the green arrow to run each query. +
+ +
+:- use_module(library(computations)). +:- use_module(library(mlserver)). +:- use_module(library(real)). +:- use_module(library(dml_c3)). + +:- use_rendering(rdf,[resource_format(nslabel)]). +:- use_rendering(matlab,[format(svg),size(15,10)]). +:- use_rendering(c3). + +% Enumerates collection level analysis events, providing +% Func=Label/Lang, collection size, and computation duration. +cla_op(Lab,Size,Dur) :- cla_op(label>>relabel-size-dur,Lab-Size-Dur). + +% main CLA browser predicate. Uses Filter to determine which computations +% are returned and what information is provided. +cla_op(Filter,Out) :- + browse(perspectives:cla_memo(Op,CID,_),comp(_,Time,Dur)-ok), + dataset_size(CID,Size), + x(Filter,op(Op,Time,Size,Dur),Out). + +% field extractor predicate (a v. small arrow interpreter!) +x(id,X,X). +x(F>>G,X,Y) :- x(F,X,Z), x(G,Z,Y). +x(fst(F),X1-Y,X2-Y) :- x(F,X1,X2). +x(snd(F),X-Y1,X-Y2) :- x(F,Y1,Y2). +x(F1-F2,X,Y1-Y2) :- x(F1,X,Y1), x(F2,X,Y2). +x(H,X,Y) :- defx(H,F), x(F,X,Y). +x(add(N),X,Y) :- Y is X+N. +x(arg(N),X,Y) :- arg(N,X,Y). +x(log,X,Y) :- Y is log10(X). +x(jitter(L,U),X,Y) :- random(D), Y is L+(U-L)*D+X. +x(divide,X-Y,Z) :- Z is X/Y. +x(diff,X-Y,Z) :- Z is Y-X. +x(quant(Q),X,Y) :- Y is Q*floor(X/Q). +x(event,T1-_,T1-start). +x(event,T1-DT,T2-stop) :- T2 is T1+DT. + +% gets month number and name from timestamp +x(month_num_name,Time,Num-Name) :- + format_time(atom(Name),'%B',Time), + stamp_date_time(Time,Date,local), + date_time_value(month,Date,Num). + +% Transforms collection level operation spec to Label/Lang, +% where Lang is in { ml, pl, r, py }. +x(relabel,Op,Label/Lang) :- cla_label_lang(Op,Label,Lang). +x(lang,_/Lang,Lang). + +defx(op, arg(1)). +defx(time, arg(2)). +defx(size, arg(3)). +defx(dur, arg(4)). +defx(month, time>>month_num_name). + +normalise_hist(Name-Pairs,Name-Pairs2) :- + unzip(Pairs,Vals,Counts), + stoch(Counts,Probs), + unzip(Pairs2,Vals,Probs). + +stoch(Xs,Ys) :- sumlist(Xs,Total), maplist(divby(Total),Xs,Ys). +divby(Z,X,Y) :- Y is X/Z. + +concurrency([T0-start|StartStopEvents],ConcurrencyEvents) :- + foldl(conc,StartStopEvents,ConcurrencyEvents,T0-1,_). + +conc(T2-Event,(T1-T2)-N1,T1-N1,T2-N2) :- + ( Event=start -> succ(N1,N2) + ; Event=stop -> succ(N2,N1) + ). + +% ------- tools for building C3 charts ----------- + +%% add_points(+Data:pair(term,list(pair(number,number))))// is det. +% Adds a set of points to a scatter plot +add_points(Name-Pairs) --> + {unzip(Pairs,Xs,Ys)}, + add_points(Name,Xs,Ys). + +%% add_points(+Name:term,+X:list(number),+Y:list(number),+C1:c3,-C2:c3) is det. +% adds a named set of points to a C3 scatter plot. +add_points(Name1,Xs,Ys,Ch1,Ch2) :- + term_to_atom(Name1,Name), + atom_concat(Name,'_x',NameX), + Ch2=Ch1.put(data/columns,[[NameX|Xs],[Name|Ys]|Ch1.data.columns]) + .put(data/xs/Name,NameX). +
+ +
+This query shows the relationship between collection size and computation time for all collection level analyses, grouped by month of computation. Note that the axis scales +are _logarithmic_. +
+ +
+setof(Size-Dur, + cla_op(month-size>>log>>jitter(0,0.05)-dur>>log,(_-M)-Size-Dur), + _Points), +call_dcg(( c3:scat('log size','log dur'), + add_points(all-_Points), + c3:legend(false), + c3:zoom(true) + ), + c3{},Ch0). +
+ +
+Histogram of logarithm of computation time per item, quantised to 0.1 bins (a ratio of about 1.26). +
+ +
+Q=0.1, % size of quantisation bin (in log domain) +histof(T, cla_op((dur-size)>>divide>>log>>quant(Q),T), _Hist), +call_dcg(( c3:bar('log dur','count'), + add_points(all-_Hist), + c3:put(bar/width/ratio,Q) + ), c3{},Chart). +
+ +
+Histogram of logarithm of computation time per item, quantised to bins of width 0.25, grouped computation label and language. +
+ +
+findall(L-Hist, + histof(T, + cla_op(op>>relabel-(dur-size)>>divide>>log>>quant(0.25),L-T), + Hist), + _Hists), +maplist(normalise_hist,_Hists,_Dists), +call_dcg(( c3:bar('log dur','count'), + foldl(add_points,_Dists), + c3:put(bar/width/ratio,0.5) + ), c3{}, Ch0). +
+ +
+Histogram of logarithm of computation time per item, quantised to bins of width 0.25, grouped language. +
+ +
+findall(L-Hist, + histof(T, + cla_op(op>>relabel>>lang - (dur-size)>>divide>>log>>quant(0.25),L-T), + Hist), + Hists), +maplist(normalise_hist,Hists,_Dists), +call_dcg(( c3:bar('log dur','fraction'), + foldl(add_points,_Dists), + c3:put(bar/width/ratio,0.45) + ), c3{}, Ch0). +
+ +
+This next query shows how collection size vs computation duration varies with the kind of analysis being done and the implementation language. Note that computations in Prolog have the lowest overheads, and that computations in Matlab seem to have the most variable range of durations for a given collection size. +
+ +
+findall(Op-_Ps, + setof(Size-Dur, + cla_op(op>>relabel-(size>>log)-dur>>log,Op-Size-Dur), + _Ps), + _Rs), +foldl(add_points,_Rs,c3{}.scat('log size','log dur'),Ch1). +
+ +
+This query is like the previous one, but grouped by language only. +
+ +
+findall(Op-_Ps, + setof(Size-Dur, + cla_op(op>>relabel>>lang-(size>>log)-dur>>log,Op-Size-Dur), + _Ps), + _Rs), +foldl(add_points,_Rs,c3{}.scat('log size','log dur'),Ch1). +
+ +
+This query breaks down the performance of analysis method by month. There does not seem to be any significant pattern in this other than the overall volume of computation done in each month. +
+ +
+setof(Month-_Ps, + setof(Size-Dur, + cla_op( month - op>>relabel - size>>log - dur>>log, + Month - Label - Size - Dur), + _Ps), + _Rs), +call(foldl(add_points,_Rs), c3{}.scat(log_size,log_dur), Ch). +
+ +
+This query analyses the degree of concurrency of collection level computations. It works by getting a complete set of point events describing the beginning and ending times of computations. Then the predicate concurrency/2 (defined in the initial code block) folds over these events and produces a list of time interval events of the form (StartTime-EndTime)-Concurrency, where Concurrency is the number of concurrent computations occuring over that interval. Then, the time intervals are mapped to durations and a histogram of concurrency weighted by duration is produced. +
+ +
+setof(Ev,cla_op((time-dur)>>event,Ev),_Evs), +concurrency(_Evs,_CEvs), +maplist(x(fst(diff)),_CEvs,_CEvs2), +weighted_histof(Dur,Conc,member(Dur-Conc,_CEvs2),Hist), +select(0-_,Hist,_Hist1), +unzip(_Hist1,_Values,_Durs), +c3_bar(concurrency-_Values,duration-_Durs,Chart). +
+ +
diff -r 000000000000 -r 718306e29690 cpack/dml/examples/visuals.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/examples/visuals.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,62 @@ +:- use_module(library(mlserver)). +:- use_module(library(semweb/rdf_label)). +:- use_module(components(matlab)). +:- use_module(components(audio)). +:- use_module(components(score)). +:- use_rendering(matlab,[size(12,8),cache(true)]). +:- use_rendering(html). + +%:- include(search). + +/** + ?- test_plot(X). + ?- test_html(X). + ?- X=html(\figure(??bar(rand(10,1)),5,3)), Y=fig(plot(1:10),5,3), hold. + ?- ml_fig(??bar(1:10),5,3), ml_fig(??plot(sin(0:0.05:12)),5,3). + ?- finder_player(title(brandenburg),Player). + ?- finder_player(title('prelude and fugue')/\composer(bach),Player). + ?- R::title(prelude)/\title(cello)/\humdrum, + X=html(\score(R,150)), + Y=html(\score_audio_player(R)). + +*/ + +bar(Opts,X-Y,Fig) :- decorate(fig(bar(X,Y),15,5),Opts,Fig). +plot(Opts,X-Y,Fig) :- decorate(fig(plot(X,Y),15,5),Opts,Fig). + +ml_fig(Cmd,W,H) :- write_html(\figure(Cmd,W,H)). + +decorate(fig(Cmd,W,H),Opts,fig(Cmd2,W,H)) :- + ( option(labels(XL,YL),Opts) + -> Cmd1 = (Cmd;xlabel(q(XL));ylabel(q(YL))) + ; Cmd1 = Cmd + ), + ( option(title(T),Opts) + -> Cmd2 = (Cmd1;title(q(T))) + ; Cmd2 = Cmd1 + ). + + +/* Note that there is a subtle problem which affects + * the use of the figure//3 HTML component: the first argument + * is a module-qualified goal, and gets tagged with the name + * of the module created to run the current pengine query. + * The component results in an HTML IMAGE element whos + * URL encodes the goal and its module. If the pengine query + * has terminated by the time the image URL is dereferenced, + * the call fails. Thus, to make this work with write_html/1 + * you need either a delay (eg sleep(3)) after the call, to allow + * the image to render before the query terminates, or you need + * to introduce some nondeterminism so that the query remains + * active. To make it work with html term rendering, only the + * non-determinism method will work. To do this, you can add the + * following hold as a final goal - it succeeds but leaves a choice point. + */ +hold :- true; fail. + +test_plot(fig(plot(X,X.^2))) :- X= -1:0.01:1. + +test_html(html(span([b(hello),' ',i(world)]))). +test_html(html(\figure(??imagesc(magic(5)),3,3))). +test_html(_) :- fail. + diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/bassoon --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/bassoon Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/bassoon.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/cello --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/cello Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/cello_solo.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/fluid_gm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/fluid_gm Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/FluidR3_GM.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/fluid_gs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/fluid_gs Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/FluidR3_GS.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/genuser_fs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/genuser_fs Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/GeneralUser-FluidSynth.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/genuser_ms --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/genuser_ms Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/GeneralUser-MuseScore.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/organ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/organ Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/organ.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/piano --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/piano Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/piano.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/rhodes --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/rhodes Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/rhodes.sf2 1 0 +set synth.gain 0.8 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/violin --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/violin Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,13 @@ +load SFDIR/stavi_violin.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 +select 0 1 0 3 +select 1 1 0 3 +select 2 1 0 3 +select 3 1 0 3 +select 4 1 0 3 +select 5 1 0 3 +select 6 1 0 3 +select 7 1 0 3 diff -r 000000000000 -r 718306e29690 cpack/dml/fluid/yamaha_dx7 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/fluid/yamaha_dx7 Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,5 @@ +load SFDIR/Piano_Yamaha_DX7.sf2 1 0 +set synth.gain 1 +set synth.chorus.active no +chorus off +select 9 1 0 0 diff -r 000000000000 -r 718306e29690 cpack/dml/lib/async.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/async.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,469 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(async, + [ async_memo/4 + , async_current_job/5 + , async_thread_progress/4 + , async_get_progress_callback/1 + , async_set_progress_callback/1 + , async_unset_progress_callback/0 + , async_cancel/3 + , async_cancel/2 + , with_progress_stack/1 + , with_cont/4 + , simple_task/2 + , stepwise_task/4 + , updatable_status_task/3 + , map_with_progress/3 + , map_fold_with_progress/5 + , with_global/3 + , with_new_ref/3 + ]). + +/** Asynchronous memoised computations with progress and partial results + + This module provides services for managing memoised computations in a thread pool + with the ability to check on the progress of running jobs and receive partial + results if they are available. Completed computations are memoised using + library(memo). + + ---++ Job control + The first half of the module is concerned with managing memoised computations. + Computations are requested using async_memo/4. If the result is already available in + the memoised database, the result is returned. If the computation is already running, + status information about the job is returned. Otherwise, a new job is started. Status + information is returned as the type =|async_status(A)|=. + == + async_status(A) ---> done(metadata) + ; initiated(job_id,natural) + ; waiting(natural) + ; running(job_id,A)) + ; recompute(job_id,natural,metadata). + + job_id == atom. + == + The type =|metadata|= is defined in library(memo). + + + ---++ Helper meta-predicates + The second half of the module provides a collection of predicates for computations + to use to handle requests for progress information, in the form of a stack of tasks. + It recognises the following levels of progress information: + == + summary :: progress_level(list(any)). + partial_result :: progress_level(any). + == +*/ +:- meta_predicate + async_set_progress_callback(2) + , async_memo(+,0,-,+) + , with_global(+,+,0) + , with_new_ref(-,+,0) + , with_progress_stack(0) + , with_progress_handler(2,0) + , with_cont(+,1,2,-) + , simple_task(+,0) + , stepwise_task(+,+,-,0) + % , stepwise_partial_task(+,+,-,-,0) + % , fold_with_progress(3,+,+,-) + , map_with_progress(2,+,-) + , map_fold_with_progress(2,3,+,+,-). + +:- use_module(library(thread_pool)). +:- use_module(library(insist)). +:- use_module(library(memo)). +:- use_module(library(dcg_core),[seqmap/4]). + +%% async_memo(+P:thread_pool, +G:memo_goal, -S:async_status(_), Opts:options) is det. +% +% Start running a goal asynchronously in a thread pool if it is not +% already running. +% In order for the goal to provide progress information, it must use nb_setval/2 +% to set the global variable =|progress|=. +% +% Options: +% * status_var(Var:status_var(A)) +% If computation is already running, information of type =|A|= +% associated with job is returned in Stats. Default is =|progress(summary)|=. +% * recompute(R:oneof([none,failed,test(Pred)])) +% If =|none|=, then a previously failed computation is not retried, and the +% status =|done(Comp-Result)|= is returned, where Comp includes +% the computation time and host and Result is =|fail|= or =|ex(Exception)|=. +% If =|failed|=, unsuccessful computations are retried and the status +% =|recomputing(ID,Pos,Meta)|= is returned, where =|ID|= is the ID of the +% new job, =|Pos|= its initial position in the queue, and =|Meta=Comp-Result|= +% the status of the previous computation. +% If =|test(Pred)|=, then the computation is retried if =|call(Pred,Meta)|= +% succeeds, where Meta is the memoisied computation metadata and the variables +% in Goal will be unified with their values resulting from that computation. +% The status returned is =|initiated(ID,Pos)|=. Pred must include its module +% specifier as a I am too lazy to worry about meta-predicate options right now. +% * globals(list(pair(atom,any))) +% Set global variables to given values in new thread. +% +% The value of the =|status_var(_)|= option determines the information returned +% if the status of the computation is =|running(ID,StatusVals)|=. +% == +% progress(progress_level(A)) :: status_var(A). +% stats(list(stats_key)) :: status_var(list(stats_vals)). +% time :: status_var(pair(time,float)). % start and elapsed times +% status_var(A)-status_var(B) :: status_var(pair(A,B)). +% +% time==float. % as returned by get_time/1. +% == +% The type =|stats_key|= denotes any atom accepted by thread_statistics/3, and +% =|stats_vals|= the type of values returned. + +async_memo(_,Goal,done(Meta),Opts) :- + option(recompute(none),Opts,none), + browse(Goal,Meta), !. + +async_memo(Pool,Goal,Status,Opts) :- + with_mutex(async,unsafe_async_memo(Pool,Goal,Status,Opts)). + +unsafe_async_memo(Pool,Goal,Status,Opts) :- + option(globals(Globals),Opts,[]), + ( browse(Goal,Meta) + -> option(recompute(Recompute),Opts,none), + ( recompute(Recompute,Meta) + -> clear_all(Goal,Meta), + spawn(Pool,Goal,Globals,ID,Waiting), + Status=recomputing(ID,Waiting,Meta) + ; Status=done(Meta) + ) + ; % !!! it's possible that another thread might be computing + % this goal and complete at this point. If this happens, + % that job will not be detected and a new a job will be started + % here. If that happens, the newly created job will find the result + % and complete quickly. + ( async_current_job(Pool,Goal,ID,T0,S) + -> option(progress_levels(Levels),Opts,[summary]), + % !!! it's possible that the job will complete here + % and so the progress request will create an error + goal_status(ID,T0,Levels,S,Status) + ; spawn(Pool,Goal,Globals,ID,Waiting), + Status=spawned(ID,Waiting) + ) + ). + +recompute(failed,_-fail). +recompute(failed,_-ex(_)). +recompute(test(P),M) :- call(P,M). + +goal_status(ID, TSubmit, _, waiting(Pos), waiting(ID,TSubmit,Pos)). +goal_status(ID, _, Levels, running(Thread,TStart), running(ID,TStart,Thread,Progress)) :- + catch( ( async_thread_progress(Thread,Levels,T,Vals), Progress=just(T-Vals)), Ex, + ( print_message(warning,error_getting_job_progress(Thread,Ex)), Progress=nothing)). + +spawn(Pool,Goal,Globals,ID,Waiting) :- + uuid(ID), + (thread_pool_property(Pool,backlog(Waiting)) -> true; Waiting=0), + get_time(Time), + setup_call_catcher_cleanup( + recordz(Pool,job(ID,Time,Goal),Ref), + thread_create_in_pool(Pool,spawnee(ID,Goal,Globals),_, + [ detached(true), at_exit(erase(Ref))]), + exception(_), + erase(Ref)). + +spawnee(ID,Goal,Globals) :- + setup_call_cleanup( + with_mutex(async, + ( recorded(ID,async:cancelled,Ref) + -> debug(async,'Cancelled before starting: ~q',[Goal]), + erase(Ref), fail + ; pairs_keys_values(Globals,GNames,GVals), + maplist(nb_setval,GNames,GVals), + get_time(T0), + thread_self(Thread), + recordz(ID,running(Thread,T0),Ref) + )), + ( freeze(Res,check_result(Res)), % prevent memoisation if abort(_) is caught + debug(async,"Running asyc goal ~q",[Goal]), + memo(Goal,_-Res)), + erase(Ref)). + +check_result(Ex) :- + ( Ex=ex(abort(Reason)) + -> debug(async,'Computation aborted (~w)',[Reason]), + throw(abort(Reason)) + ; true + ). + +%% async_current_job(+Pool:thread_pool, -Goal:callable, -ID:job_id, -T:time, -S:job_status) is nondet. +% Retrieves information about current pending jobs. A job is pending if it is running +% or waiting to run in the specified thread pool. T is the time the job was submitted. +% Job status is: +% == +% job_status ---> waiting(natural) % queued at given postion +% ; running(thread_id,time). % with start time +% == +async_current_job(Pool,Goal,ID,Time,Status) :- + recorded(Pool,job(ID,Time,Goal)), % this finds ALL jobs + ( recorded(ID,running(Thread,StartTime)) + -> Status=running(Thread,StartTime) + ; thread_pool_property(Pool,waiting(Waiting)), + nth1(Pos,Waiting,create(Pool,async:spawnee(ID,_,_),_,_,_)) + -> Status=waiting(Pos) + ; print_message(warning, async_job_status_indeterminate(Pool,ID,Goal)), + Status=indeterminate % could be finished, or transferring from waiting to running + ). + + +%% async_thread_progress(+Thread:thread_id,+Levels:list(progress_level), -T:time, -Vals:list) is det. +% Called in main thread to get information about job running in thread Thread. +% Will throw an exception if: +% - the thread has terminated +% - the thread does not respond with progress info in less than 3 seconds +% - the thread does not have a progress handler call back registered +% - the progress handler fails on any of the progress levels requested. +async_thread_progress(Thread,Levels,Time,Vals) :- + thread_self(Me), + gensym(prog,RID), % progress request ID + flush_all_messages(Me,progress(_,_,_,_)), + thread_signal(Thread,report_progress(RID,Levels,Me)), + ( thread_get_message(Me,progress(RID,Time,Vals,St),[timeout(3)]) -> true + ; throw(get_thread_progress_timeout(Thread,Levels)) + ), + debug(async,'Got progress ~w from thread ~w: ~w',[Levels,Thread,Vals]), + memo:reflect(St). + +flush_all_messages(Queue,Pattern) :- + repeat, \+thread_get_message(Queue,Pattern,[timeout(0)]), !. + +%% report_progress(+RID:atomic, +Var:status_var(A), +Thread:thread_id) is det. +% Called from job thread in response to a signal, to send progress information to thread Thread. +report_progress(RID,Levels,Thread) :- + get_time(Time), + memo:reify(async:my_progress(Levels,Vals),St), !, + debug(async,'reporting progress(~w): ~q',[Levels,Vals]), + thread_send_message(Thread,progress(RID,Time,Vals,St)). + +my_progress(Levels,Vals) :- nb_getval(async_progress,G), insist(maplist(G,Levels,Vals)). + + +%% async_cancel(+Pool:thread_pool, +ID:job_id, +Ex:term) is det. +%% async_cancel(+Pool:thread_pool, +ID:job_id) is det. +% Cancel job with given ID, if it is currently pending. If it is running, the +% exception term Ex is thrown (=|abort(cancel)|= in async_cancel/2). +% If not, the recorded database is used to mark the job for immediate failure +% as soon as it is started. +async_cancel(Pool,ID) :- async_cancel(Pool,ID,abort(cancel)). +async_cancel(Pool,ID,Ex) :- + debug(async,'Cancelling ~w:~w with ~w',[Pool,ID,Ex]), + with_mutex(async, (async_current_job(Pool,_,ID,_,S) -> cancel(ID,S,Ex); true)). + +cancel(ID,waiting(_),_) :- recordz(ID,async:cancelled). +cancel(_, running(Thread,_),Ex) :- + catch( thread_signal(Thread,throw(Ex)), E, + print_message(warning,error_signalling_job_thread(Thread,E))). +cancel(ID,indeterminate,_) :- print_message(warning,indeterminate_job_state_on_cancel(ID)). + +%% async_set_progress_callback(+P:pred(+Level:any,-Info:any)) is det. +% Sets the progress handler for the current thread. +async_set_progress_callback(Pred) :- nb_setval(async_progress,Pred). + +%% async_get_progress_callback(-P:pred(+Level:any,-Info:any)) is semidet. +% Gets the progress handler for the current thread, if one has been set. +async_get_progress_callback(Pred) :- nb_current(async_progress,Pred). + +%% async_unset_progress_callback is det. +% Unsets the progress handler for the current thread. Subsequent calls to +% async_get_progress_callback/1 will fail. +async_unset_progress_callback :- nb_delete(async_progress). + +% ----------------------------------------------------------------------- + + +%% with_progress_stack(+Goal:callable) is nondet. +% +% Runs Goal with the current thread's progress handler (which must be initially +% unset) set to an empty task stack. Tasks (goals which run in cooperation with a +% a progress handler) can be pushed on to the task stack using with_progress_handler/2. +% Fails if progress callback has already been set to something else. +% +% The progress handler recognises progress level terms: +% * summary :: progress_level(list(any)) +% Yields a list of progress terms, one for each entry in the task stack. +% * partial_result :: progress_level(any) +% Yields partial results of the computation if they are available. +with_progress_stack(Goal) :- + async_get_progress_callback(CB), !, + CB=async:get_stack_progress, + call(Goal). +with_progress_stack(Goal) :- + with_global(async_progress_stack, nil, + setup_call_cleanup( + async_set_progress_callback(get_stack_progress), Goal, + async_unset_progress_callback)). + +%% get_stack_progress(+Level:progress_level(A),-Info:A) is semidet. +% Gets the request level of progress information from the currently installed +% progress stack. +get_stack_progress(summary,P) :- + nb_getval(async_progress_stack,H), + call(H,progress(summary),P). + +get_stack_progress(partial_result,R) :- + nb_getval(async_progress_stack,H), + call(H,partial_result,R). + + +%% with_progress_handler(+H:progress_handler, +Goal:callable) is nondet. +% Pushes the progress handler H to the top of the task stack associated with +% the current thread and calls Goal. The handler is removed on exit. +with_progress_handler(H,Goal) :- + nb_getval(async_progress_stack,H0), call(H0,push(H),H1), + setup_call_cleanup( nb_setval(async_progress_stack,H1), Goal, + nb_setval(async_progress_stack,H0)). + +nil(progress(_),[]). +nil(push(H),chain(H,nil)). +nil(partial_result,nothing). +nil(partial_result(Cont),R) :- call(Cont,nothing,R). + +chain(Head,Tail1,push(H),chain(Head,Tail2)) :- call(Tail1,push(H),Tail2). +chain(Head,Tail,progress(L),[PH|PT]) :- + call(Head,progress(L),PH), + call(Tail,progress(L),PT). +chain(Head,Tail,partial_result,MR) :- + call(Tail,partial_result,R1), + (call(Head,partial_result(R1),R) -> MR=just(R); MR=nothing). + + +%% simple_task(+Desc,+Goal:callable) is det. +% +% Calls goal with a progress handler that reports Desc when progress +% information is requested. No partial results are available. +simple_task(Desc,Goal) :- with_progress_handler(simple_progress(Desc),Goal). + +simple_progress(Desc,progress(_),Desc). + + +%% with_cont(+Desc,+Pred:pred(-A),+Cont:pred(+A,-B),-Result:B) is det. +% +% Calls Pred and then passes the result to Cont yielding Result. +% A progress handler is installed such that any partial results yielded by +% subtasks in Pred are passed to Cont to yield a partial result. Progress requests +% yield Desc. +with_cont(Desc,Pred,Cont,Result) :- + with_progress_handler(cont(Desc,Cont), + (call(Pred,R),call(Cont,R,Result))). + +cont(_,Cont,Tail1,push(H),cont(Cont,Tail2)) :- call(Tail1,push(H),Tail2). +cont(Desc,_,progress(_),Desc). +cont(_,Cont,partial_result(just(R1)),R) :- call(Cont,R1,R). + +%% stepwise_task(+Desc,+Total:nonneg,-Step:callable,+Goal:callable) is det. +% +% Calls Goal with a progress handler that is able to report progress as a term +% =|stepwise(Desc,Done/Total)|=. Goal is permitted to call Step in order to increment +% the =|Done|= counter. Partial results are not available. +stepwise_task(Desc,Total,async:increment(Counter),Goal) :- + with_new_ref(Counter,0, with_progress_handler(stepwise_progress(Desc,Total,Counter), Goal)). + +stepwise_progress(Desc,Total,Counter,progress(_),stepwise(Desc,Done/Total)) :- b_getval(Counter,Done). + + +%% updatable_status_task(+Initial,-Update:pred(any),+Goal:callable) is det. +% +% Calls goal with Update set to a predicate which can be used to set the +% current status of the task. This will be reported if progress is requested. +% No partial results are available. Initial is the status before Update is called. +:- meta_predicate updatable_status_task(+,-,0). +updatable_status_task(Initial,async:set_ref(Status),Goal) :- + with_new_ref(Status,Initial, with_progress_handler(status_progress(Status),Goal)). + +status_progress(Status,progress(_),S) :- b_getval(Status,S). + + +map_with_progress(P,Xs,Ys) :- + length(Xs,Total), + stepwise_task(map(P),Total,Step, maplist(call_and_step(Step,P),Xs,Ys)). + +call_and_step(Step,P,X,Y) :- call(P,X,Y), call(Step). + +/* +fold_with_progress(Folder,Items,S0,S1) :- + length(Items,N), + stepwise_partial_task(folding(Folder),N,Step,Update, + seqmap(step_update(Step,Update,Folder),Items,S0,S1)). + +step_update(Step,Update,P,X,S0,S1) :- + call(P,X,S0,S1), + call(Update,S1), + call(Step). +*/ + +:- setting(map_fold_batch,nonneg,512,"Batch size for flushing fold queue."). + +%% map_fold_with_progress(+Mapper:pred(A,B), +Folder:pred(list(B),S,S), +Items:list(A), +S1:S, -S2:S) is det. +% +% Map Mapper over Items and fold over the results with Folder, with progress information +% partial results available. Note that Folder operates on a _list_ of items, not just one +% item at a time. Mapper is used to accumulate up to N items before folding them batchwise +% into the accumulator, where N is the value of the setting =|map_fold_batch|=. +% +% Progress information is returned as a term =|stepwise(Desc,Done/Total)|=, where +% =|Desc=map_fold(Mapper,Folder)|=. If partial results are requested, the current batch +% of mapped items is first folded in before returning the value of the accumulator. +map_fold_with_progress(Mapper,Folder,Items,S1,S2) :- + length(Items,Total), + setting(map_fold_batch,M1), + with_new_ref(StateRef,s(Items,0,M1,Head,Head,S1), + ( Handler=map_fold_progress(map_fold(Mapper,Folder),Total,StateRef), + with_progress_handler(Handler, + ( map_fold_loop(Mapper,Folder,StateRef), + call(Handler,partial_result(nothing),S2))))). + +map_fold_loop(Mapper,Folder,StateRef) :- + b_getval(StateRef,s(Xs1,N1,M1,Head,Ys1,S)), + ( Xs1=[] -> Ys1=[] + ; Xs1=[X|Xs2] + -> call(Mapper,X,Y), !, + Ys1=[Y|Ys2], succ(N1,N2), + State1=s(Xs2,N2,M2,Head,Ys2,S), + ( succ(M2,M1) -> State2=State1 + ; simple_task(folding,flush_fold(Folder,State1,State2)) + ), + b_setval(StateRef,State2), !, + map_fold_loop(Mapper,Folder,StateRef) + ). + +map_fold_progress(Desc,Total,StateRef,progress(_),stepwise(Desc,Done/Total)) :- + b_getval(StateRef,s(_,Done,_,_,_,_)). +map_fold_progress(map_fold(_,Folder),_,StateRef,partial_result(_),S2) :- + b_getval(StateRef,State1), + flush_fold(Folder,State1,State2), + b_setval(StateRef,State2), + State2=s(_,_,_,_,_,S2). + +flush_fold(Folder,s(Xs,Done,_,Head,[],S1),s(Xs,Done,M1,H2,H2,S2)) :- + setting(map_fold_batch,M1), + call(Folder,Head,S1,S2), !. + +% for managing global variable +new_ref(Ref) :- gensym('$ref',Ref). +new_ref(Ref,Val) :- new_ref(Ref), b_setval(Ref,Val). + +with_global(Name,Val,Goal) :- setup_call_cleanup(b_setval(Name,Val), Goal, nb_delete(Name)). +with_new_ref(Name,Val,Goal) :- new_ref(Name), with_global(Name,Val,Goal). + +set_ref(Ref,Val) :- nb_setval(Ref,Val). +increment(Counter) :- b_getval(Counter,N), succ(N,M), b_setval(Counter,M). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/backend_json.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/backend_json.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,53 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(backend_json, + [ python_json/3 + , python_apply/3 + , python_call/3 + , python_call/4 + , python_call/5 + ]). + +:- use_module(library(http/json)). + +python_apply(Module:Function,Args,Result) :- !, + Input = _{ module:Module, function:Function, arguments:Args }, + python_json('json_wrapper.py', Input, Output), + ( Output=error{value:Msg} -> throw(python_json_error(Msg,Module:Function)) + ; Output=ok{value:Result} + ). +python_apply(Function,Args,Result) :- atom(Function), + python_apply('__builtin__':Function,Args,Result). + +python_call(ModFunc,A1,Result) :- python_apply(ModFunc,[A1],Result). +python_call(ModFunc,A1,A2,Result) :- python_apply(ModFunc,[A1,A2],Result). +python_call(ModFunc,A1,A2,A3,Result) :- python_apply(ModFunc,[A1,A2,A3],Result). + +python_json(Script,Input,Output) :- + setup_call_cleanup( + process_create( dml(python/Script),[], + [ cwd(dml(python)), process(PID), + stdin(pipe(ToScript)), stdout(pipe(FromScript))]), + call_cleanup( + ( call_cleanup(json_write_dict(ToScript,Input,[width(0),tag(tag)]), close(ToScript)), + json_read_dict(FromScript,Output,[tag(tag)]) + ), exception(_), process_kill(PID)), + (close(FromScript), process_wait(PID,_)) + ). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/backend_rdf.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/backend_rdf.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,82 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(backend_rdf, + [ rdf//3 + , in/5 + ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/turtle)). +:- use_module(library(semweb/rdf_turtle_write)). +:- use_module(library(dcg_core)). + +:- rdf_meta rdf(r,r,o,?,?). +rdf(S,P,O) --> [rdf(S,P,O)]. + +:- rdf_meta to_literal(+,o). +to_literal(integer(X), literal(type(xsd:integer,Y))) :- atom_number(Y,X). +to_literal(float(X), literal(type(xsd:float,Y))) :- atom_number(Y,X). +to_literal(double(X), literal(type(xsd:double,Y))) :- atom_number(Y,X). +to_literal(string(X), literal(type(xsd:string,Y))) :- atom_string(Y,X). +to_literal(atom(X),literal(X)). + +comp(Comp,Function,Input) --> + {once(to_literal(Input,InputLit))}, + rdf(Comp,dmlcla:function,literal(Function)), + rdf(Comp,dmlcla:input,InputLit). + + +inx(Triples,SS,PP,OO,_) :- + in(Triples,S,P,O,_), + rdf_global_id(S,SS), + rdf_global_id(P,PP), + rdf_global_object(O,OO). + +in(Triples,S,P,O,_) :- + number_vars_as_uris(Triples), + member(rdf(S,P,O),Triples). + +phrase_triple(Phrase,S,P,O,_) :- + phrase(Phrase,Triples), + number_vars_as_uris(Triples), + member(rdf(S,P,O),Triples). + + +:- meta_predicate python_rdf(//,-). +python_rdf(Input,Output) :- + phrase(Input,Triples), + number_vars_as_uris(Triples), + setup_call_cleanup( + process_create( dml('python/rdf_wrapper.py'),[], + [ cwd(dml(python)), process(PID), + stdin(pipe(ToScript)), stdout(pipe(FromScript))]), + ( call_cleanup(rdf_save_turtle(stream(ToScript),[expand(in(Triples)), silent(true)]), close(ToScript)), + rdf_read_turtle(stream(FromScript),Output,[base_uri('_:tmp#')]) + ), + (close(FromScript), process_wait(PID,Status)) + ), + debug(backend,'Process exit status was: ~q',[Status]). + +number_vars_as_uris(Term) :- + term_variables(Term,Vars), + seqmap(number_var_as_uri,Vars,1,_). +number_var_as_uri(Var,N,M) :- + atom_number(NN,N), + rdf_global_id(dmlcla:NN,Var), + succ(N,M). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/beets_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/beets_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,160 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(beets_p2r, []). + +/** Access to beets database + */ + + +:- use_module(library(prosqlite)). +:- use_module(library(musicbrainz)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(rdfutils)). +:- use_module(entailment(p2r)). + +:- set_prolog_flag(double_quotes,string). + +:- rdf_register_prefix(beets,'http://dml.org/beets/props/item/'). +:- rdf_register_prefix(beets_album,'http://dml.org/beets/props/album/'). +:- rdf_register_prefix(audio,'audio:'). +:- rdf_register_prefix(dml,'http://dml.org/dml/'). +:- rdf_register_prefix(mb,'http://musicbrainz.org/'). + +:- setting(db_file,string,"~/lib/beets/music-ro.db","Location of beets database"). +:- setting(audio_root,string,"/usr/local/share/Music/","Root of audio file directory tree"). + + +rdf(audio:tail(Rel), rdf:type, mo:'AudioFile'), +rdf(audio:tail(Rel), mo:encoding, literal(Enc)) <== + setting(audio_root,Root), + expand_file_name(Root,[Root1]), + item(Id,path,Path), + item(Id,format,Enc), + atom_concat(Root1,Rel,Path). + +rdf(audio:tail(Rel), beets:enc(Prop), literal(Val)) <== + audio_item_path(Id,Rel), + item(Id,Prop,Val1), + ( Prop=path -> exists_file(Val1); true), + as_typed_literal(Val1,Val). + +rdf(Signal,rdf:type,mo:'Signal') <== + item(_,mb_trackid,ID), % track id is actually a Recording. + mb_id_uri(recording,ID,Signal). + +rdf(Signal,mo:available_as,audio:tail(Rel)) <== + setting(audio_root,Root), + expand_file_name(Root,[Root1]), + item(Id,path,Path), + exists_file(Path), + atom_concat(Root1,Rel,Path), + item(Id,mb_trackid,ID), % track id is actually a Recording. + % need to ask Linkedbrainz to get Signal URI + mb_id_uri(recording,ID,Signal). + +rdf(audio:tail(Rel), dml:file_artist, URI) <== + audio_item_path(Id,Rel), + item(Id,mb_artistid,ID), + mb_id_uri(artist,ID,URI). + +rdf(audio:tail(Rel), dml:file_release, URI) <== + audio_item_path(Id,Rel), + item(Id,mb_albumid,ID), + mb_id_uri(release,ID,URI). + +rdf(audio:tail(Rel), dml:file_recording, URI) <== + audio_item_path(Id,Rel), + item(Id,mb_trackid,ID), + mb_id_uri(recording,ID,URI). + +% rdf(URI,mo:release_type,mo: +rdf(URI,rdf:type,mo:'Release') <== + item(_,mb_albumid,ID), + mb_id_uri(release,ID,URI). + +audio_item_path(Id,Rel) :- + setting(audio_root,Root), + expand_file_name(Root,[Root1]), + item(Id,path,Path), + atom_concat(Root1,Rel,Path). + +:- public import/0. +import :- with_beets_db(assert_all(beets_p2r)). + +with_beets_db(Goal) :- + setting(db_file,DBFile), + expand_file_name(DBFile,[Path|_]), + setup_call_cleanup( + sqlite_connect(Path,Con,[alias(beets),ext(''),as_predicates(true),arity(unary),at_module(beets)]), + Goal, + sqlite_disconnect(Con)). + +:- dynamic beets:items/1. +item(Id) :- beets:items([id=Id]). + +item(Id,path,Path) :- + ( var(Path) -> beets:items([id=Id,path=Path]) + ; var(Id) -> sqlite_format_query(beets,"select id from items where path like '~s'"-[Path],row(Id)) + ; sqlite_format_query(beets,"select null from items where id=~w and path like '~s'"-[Id,Path],row(_)) + ). + +item(Id,Prop,Val) :- + table_column(items,Prop), Prop\=path, Prop\=comp, + beets:items([id=Id,Prop=Val]), + \+invalid(Prop,Val). + + +% album(Id) :- beets:albums([id=Id]). +% album(Id,Prop,Val) :- +% table_column(albums,Prop), +% beets:albums([id=Id,Prop=Val]), Val\=''. + +table_column(T,C) :- + sqlite_table_column(beets,T,C1), C=C1. + +invalid(_,''). +invalid(Prop,0) :- nonzero(Prop). +invalid(mtime,0.0). + +nonzero(bitdepth). +nonzero(bitrate). +nonzero(samplerate). +nonzero(track). +nonzero(tracktotal). +nonzero(disc). +nonzero(disctotal). +nonzero(bpm). +nonzero(day). +nonzero(month). +nonzero(year). +nonzero(original_day). +nonzero(original_month). +nonzero(original_year). + +:- public audio_file/3. + +audio_file(URI,File,just(T0)) :- + rdf(URI,beets:path,literal(File)), !, + rdf(URI,beets:format,literal(F0)), + format_type(F0,T0). + +format_type('MP3',mp3). +format_type('OGG',ogg). +format_type('AAC',aac). +format_type('ALAC',mp4). % !!! ?? diff -r 000000000000 -r 718306e29690 cpack/dml/lib/bl_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/bl_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,501 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(bl_p2r,[ audio_file/3, audio_link/2, scrape_audio_link/2, has_available_audio/1 ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(xmlarchive)). +:- use_module(library(xpath)). +:- use_module(library(settings)). +:- use_module(library(sandbox)). +:- use_module(library(fileutils)). +:- use_module(library(termutils)). +:- use_module(library(rdfutils)). +:- use_module(library(insist)). +:- use_module(library(memo)). +:- use_module(entailment(p2r)). +:- use_module(cliopatria(hooks)). +:- use_module(library(http/http_client)). + +:- set_prolog_flag(double_quotes,string). + +/* + METS to RDF conversion. + + Useful info: + 0. Each top-level mets:mets element contains several sections. + 1,4 x dmdSec .. 1 x mdWrap + 1 x amdSec .. [ N x techMD, {0,1} x rightsMD, {0,1} x sourceMD ] + 1 x fileSec .. 1-4 x fileGrp .. 1-36 x file + 1 x structLink .. {1,3} x smLink + 2-3 x structMap .. 1 x div + + 1. Each dmdSec only ever contains one mdWrap element + 5. each techMD or sourceMD contains exactly 1 mdWrap + 6. each rightsMD contains an mdRef + 7. The rightsMD is not interesting to look at. + 8. dmdSec mdWraps can be empty + + List of all dmdSec tags in dataset + blapsi:id3album + blapsi:id3artist + blapsi:id3comment + blapsi:id3songtitle + blapsi:id3year + dc:description + dc:identifier + dc:language + dc:rights + dc:source + dc:subject + dc:title + dc:type + dcterms:created + dcterms:isPartOf + dcterms:spatial + dcterms:temporal + marcrel:CMP + marcrel:CND + marcrel:IVE + marcrel:IVR + marcrel:LYR + marcrel:PRF + marcrel:RCE + marcrel:SPK + mods:accessCondition + mods:identifier + mods:name + mods:recordInfo + mods:titleInfo + + amdSec tags + blapsi:audioObject + blapsi:file_bitrate + blapsi:file_channels + blapsi:file_duration + blapsi:file_sample + blapsi:resolution + + sourceMD .. blapsi:audioObject + blapsi:face + blapsi:format + blapsi:physicalProperties + blapsi:face + blapsi:format + blapsi:physicalProperties + blapsi:primaryIdentifier + blapsi:secondaryIdentifier + blapsi:primaryIdentifier + blapsi:secondaryIdentifier + + would prefer to have mo predicates to foaf:Person resources for these. + marcrel:'CMP',dml:composer). + marcrel:'CND',dml:conductor). + marcrel:'PRF',dml:performer). + + */ + +:- setting(audio_root,ground,nothing,'Root directory of audio file collection'). +:- setting(archive_pattern,atom,'~/lib/datasets/mets/BL_metadata_complete.7z','Pattern to match METS metadata files'). + +:- rdf_register_prefix(bldata,'http://sounds.bl.uk/resource/'). +:- rdf_register_prefix(marcrel,'http://id.loc.gov/vocabulary/relators/'). +:- rdf_register_prefix(blapsi,'http://sounds.bl.uk/blapsi#'). +:- rdf_register_prefix(blterms,'http://www.bl.uk/schemas/bibliographic/blterms#'). + +% https://code.google.com/p/libarchive/issues/detail?id=328&colspec=ID%20Type%20Status%20Priority%20Milestone%20OpSys%20Owner%20Summary + +:- public import/0. +import :- assert_all(bl_p2r). + +rdf(dml:blpage,rdfs:range,foaf:'Document') <== true. +rdf(dml:blpage,rdfs:subPropertyOf,foaf:page) <== true. +rdf(S,P,O) <== bl_archive_triple(T), once(expand_triple(T,rdf(S,P,O))). + +expand_triple(rdf(SS,PP,OO),rdf(S,P,O)) :- + uripattern:pattern_uri(SS,S), + uripattern:pattern_uri(PP,P), + ( OO=literal(_) -> rdf_global_object(OO,O) + ; uripattern:pattern_uri(OO,O) + ). + +%% import_directory(+Dir:atom, +Graph:atom) is det. +% +% Import contents of a given directory into a named RDF graph. +% The directory must be a subdirectory of the directory named in the +% bl_p2r:audio_root setting (whose value is either =|just(Dir)|= or +% =|nothing|=). +import_directory(Dir,Graph) :- + forall( directory_triple(Dir,T), (once(expand_triple(T,rdf(S,P,O))), rdf_assert(S,P,O,Graph))). + +directory_triple(Dir,T) :- + Ext=txt, + setting(audio_root,just(AudioRoot)), + atom_concat(AudioRoot,'/',Prefix), + find_files(under(AudioRoot/Dir),FullPath), + atom_concat(Prefix,Path,FullPath), + split_path(Path,Loc,Ext), + with_stream(Str,open(FullPath,read,Str), ext_loc_stream_triple(Ext,Loc,Str,T)). + + +%% bl_archive_triple(-T:rdf) is nondet. +% This predicate generates triples from the metadata archive files whose names +% match the pattern stored in the setting bl_p2r:archive_pattern. +bl_archive_triple(T) :- + setting(archive_pattern, ArchivePattern), + find_files(like(ArchivePattern), Archive), + with_archive_stream(Archive, Path, path_triple_stream(Path,T)). + +path_triple_stream(Path,T,S) :- + status('Importing ~s',[Path]), + catch(( insist(split_path(Path,Loc,Ext)), + ext_loc_stream_triple(Ext,Loc,S,T) + ), Ex, (nl,print_message(warning,Ex),fail)). + +split_path(Path,Dirs-Base,Ext) :- + % split_string(Path,'/','',Parts), + atomic_list_concat(Parts,'/',Path), + exclude(ignore_dir,Parts,Parts1), + append(Dirs,[Name],Parts1), + sub_atom(Name,_,3,0,Ext), % NB this assumes three character extension + sub_atom(Name,0,_,4,Base). + +%% ext_loc_stream_triple(+Ext:atom, +Loc:pair(list(atom), atom), +S:stream, -T:rdf) is nondet. +% +% This predicate succeeds once for each RDF triple that can be derived from +% an archive stream whose path in the archive Loc=Dirs-Base consist of the directories +% Dirs and whose name is Base,'.',Ext. It understands entries with extensions +% xml and txt. XML streams are decoded as full METS documents. TXT streams are decoded +% as the DMD section of a METS document. Other extensions generate a warning and then fail. + +ext_loc_stream_triple(xml,Dirs-Base,S,T) :- !, + insist(load_xmlns(S,Doc)), + insist(member(element(mets:mets,_,METS),Doc)), + ( insist(get_bl_url(Base,Dirs,URL)), + T=rdf(bldata:Base,dml:blpage,URL) + ; T=rdf(bldata:Base,rdf:type,mo:'Signal') + ; insist(multi,member(element(Tag,_,Content),METS),no_content(mets,Dirs-Base)), + mets_triple(Tag,Content,Dirs,Base,T) + ). + +ext_loc_stream_triple(txt,Dirs-Base,S,T) :- !, + % TXT streams appear to be LATIN-1 encoded, not UTF-8 + Base\=combined, % exclude combined metadata files + set_stream(S,encoding(iso_latin_1)), + insist(load_xmlns(S,Doc)), + txt_triple(Doc,Dirs,Base,T). + +ext_loc_stream_triple(Ext,Dirs-Base,_,_) :- + warning(unrecognised_extension(Ext,Dirs-Base)). + + +%% get_bl_url(+Name:atom,+Dirs:list(atom),-URL:atom) is det. +% Deduces the sounds.bl.uk URL from entry name and directory. +get_bl_url(Name,Dirs,URL) :- + sub_atom(Name,0,4,_,CatCode), + category(CatCode,Category), + append(_,[Collection],Dirs), + atomic_list_concat([ 'http://sounds.bl.uk', + Category,Collection,Name],'/',URL). + +category('021M','Oral-history'). +category('025M','World-and-traditional-music'). +category('023M','Jazz-and-popular-music'). +category('026M','Classical-music'). +category('028M','Jazz-and-popular-music'). +category('020A','Classical-music'). + +ignore_dir('_Metadata'). +ignore_dir('_Non-music'). +ignore_dir('_Audio_Metadata'). + +% --------------------- TOP LEVEL STRUCTURE ------------------------------- + +unwrap([element(mets:mdWrap,MDAttr,[element(mets:xmlData,_,XMLContent)])],MDAttr,XMLContent). + +% for complete METS documents +mets_triple(mets:dmdSec,DMDContent,_,ID,T) :- !, + unwrap(DMDContent,MDAttr,XMLContent), + member('MDTYPE'='DC',MDAttr), + dmd_triple(XMLContent,bldata:ID,T). + +mets_triple(mets:amdSec,AMDContent,_,ID,T) :- !, + member(element(Tag,Attr,Content),AMDContent), + amd_triple(Tag,Attr,Content,ID,T). + +mets_triple(mets:fileSec,FileSecContent,Dirs,ID,T) :- !, + member(element(T1,GAttr,GroupContent),FileSecContent), insist(T1=mets:fileGrp), + member(element(T2,FAttr,FileContent),GroupContent), insist(T2=mets:file), + \+member('ID'='WEBRESOURCES',GAttr), + FileContent=[element(Tag,Attr,Content)], + file_triple(Tag,Attr,Content,GAttr-FAttr,Dirs,ID,T). + +mets_triple(mets:metsHdr,_,_,_,_) :- !, fail. +mets_triple(mets:structLink,_,_,_,_) :- !, fail. +mets_triple(mets:structMap,_,_,_,_) :- !, fail. +mets_triple(Tag,_,_,_,_) :- warning(unrecognised_tag(Tag,mets:mets)). + +% for txt, partial XML documents +txt_triple(_,_,ID,rdf(bldata:ID,rdf:type,mo:'Signal')). +txt_triple(Doc,Dirs,ID,T) :- + insist(multi,member(element(Tag,_,Content),Doc),no_content(txt)), + txt_tag_triple(Tag,Content,Dirs,ID,T). + +identifier_file_ext(F,F1,mp3) :- sub_atom(F,Bef,_,_,'.mp3'), !, insist(sub_atom(F,0,Bef,_,F1)). +identifier_file_ext(F,F1,wav) :- sub_atom(F,Bef,_,0,'.wav'), !, insist(sub_atom(F,0,Bef,_,F1)). +identifier_file_ext(F,F1,m4a) :- sub_atom(F,Bef,_,0,'.m4a'), !, insist(sub_atom(F,0,Bef,_,F1)). + +txt_tag_triple(dc:identifier, [F], Dirs, ID, rdf(bldata:ID, bldata:path, literal(Path))) :- !, + % NB some of the txt files have the file name written twice. Hence I am going to discard + % everything after the first dot. Relies on sub_atom returning matches starting from the beginning + ( identifier_file_ext(F,F1,Ext) + -> file_name_extension(F1,Ext,Name), + atomics_to_string(Dirs,"/",Dir), + directory_file_path(Dir,Name,Path) + ; print_message(warning,txt_triple_identifier_fail(ID,F)), + fail + ). + +% !!! MUSICALS only. Should not really have mo:duration in them either... +txt_tag_triple(dml:rating,Content, _, ID, rdf(bldata:ID, dml:rating, literal(Content))) :- !. +txt_tag_triple(mo:duration,Content, _, ID, rdf(bldata:ID, mo:duration, literal(type(xsd:float,Millis)))) :- !, + insist(Content=[Dur],bad_content(Content,mo:duration)), + insist(atom_number(Dur,Millis)). +txt_tag_triple(blapsi:file_duration,Content, _, ID, rdf(bldata:ID, mo:duration, literal(type(xsd:float,Millis)))) :- !, + insist(Content=[Dur],bad_content(Content,blapsi:file_duration)), + % insist(parse_duration_millis(Dur,Millis)). + ( parse_duration_millis(Dur,Millis) -> true + ; warning(bad_duration(ID,Dur)) + ). +txt_tag_triple(Tag,Content,_,ID,T) :- dmd_tag_triple(Tag,Content,bldata:ID,T). + + +% --------------- Document meta data -------------------------- + +dmd_triple(DMD,URI,T) :- + member(element(Tag,_,Content),DMD), + dmd_tag_triple(Tag,Content,URI,T). + +dmd_tag_triple(dcterms:contributor,Content,ID,T) :- !, dmd_triple(Content,bldata:ID,T). +dmd_tag_triple(dc:contributor,Content,ID,T) :- !, dmd_triple(Content,bldata:ID,T). +dmd_tag_triple(marcrel:REL,Content,URI,rdf(URI,marcrel:Rel,literal(Lit))) :- !, + Content=[Lit],%empty_tag(marcrel:REL,Content)), + downcase_atom(REL,Rel). +dmd_tag_triple(Tag,Content,URI,rdf(URI,Tag,literal(Lit))) :- keep_tag(Tag), !, Content=[Lit]. +dmd_tag_triple(Tag,_,_,_) :- ignore_tag(Tag), !, fail. +dmd_tag_triple(Tag,_Content,URI,_) :- warning(unrecognised_tag(Tag,dmd,URI)). + +% !!!FIXME - sometimes dates are given in D/M/Y instead of Y-M-D +keep_tag(dc:title). +keep_tag(dc:description). +keep_tag(dc:source). +keep_tag(dc:subject). +keep_tag(dc:language). +keep_tag(dc:created). +keep_tag(dcterms:language). +keep_tag(dcterms:abstract). +keep_tag(dcterms:created). +keep_tag(dcterms:spatial). +keep_tag(dcterms:temporal). +keep_tag(dcterms:extent). % !!!FIXME need to parse this +keep_tag(blterms:mechanism). +keep_tag(dcterms:isPartOf). +keep_tag(blapsi:format). + +ignore_tag(dc:identifier). +ignore_tag(blapsi:marker). +ignore_tag(dc:rights). +ignore_tag(dc:type). +ignore_tag(rdf:about). +ignore_tag('ARK'). + +% ------------------------- ADMINISTRATIVE METADATA SECTION ----------------------------- + +amd_triple(mets:sourceMD,_,SMDContent,ID,T) :- + insist(unwrap(SMDContent,_,XMLContent),no_xml_content(SMDContent,smd)), + atom_concat(ID,'#source',Src), + ( T=rdf(bldata:ID,dml:source,bldata:Src) + ; insist(multi,member(element(Tag,Attr,Content),XMLContent),no_xml_content(smd)), + smd_xml_triple(Tag,Attr,Content,bldata:Src,T) + ). + +amd_triple(mets:techMD,Attr,TMDContent,ID,T) :- + insist(member('ID'=TMDId,Attr)), + unwrap(TMDContent,_,XMLContent), + ( T=rdf(bldata:ID/TMDId, mo:sampled_version_of, bldata:ID) +% ; T=rdf(bldata:ID/TMDId, dml:annotation,literal(Label)), member('LABEL'=Label,TMDAttr) + ; member(element(Tag,_,Content),XMLContent), + blapsi_triple(Tag, Content, bldata:ID/TMDId, T) + ). + +blapsi_triple(blapsi:Tag, [Text], Signal, rdf(Signal, Pred, literal(Lit))) :- + insist(blapsi_info(Tag, Text, Pred, Lit)). + +% ------------ Source --------------- + +smd_xml_triple(blapsi:audioObject,Attr,AOContent,SrcURI,rdf(SrcURI,Pred,literal(Lit))) :- !, + ( member(A=Lit,Attr), A\='ID', Pred=bldata:A + ; insist(multi,member(element(Tag,Attr1,Content),AOContent),no_content(blapsi:audioObject,AOContent)), + ao_tag_info(Tag,Attr1,Content,Pred,Lit) + ). + +smd_xml_triple(blapsi:Tag,Content,SrcURI,rdf(SrcURI,blapsi:Tag,literal(Lit))) :- !, + insist(Content=[Lit],bad_content(blapsi:Tag,Content,smd_xml_triple)). + +ao_tag_info(blapsi:primaryIdentifier,_,_,_,_) :- !, fail. +ao_tag_info(blapsi:secondaryIdentifier,_,_,_,_) :- !, fail. +ao_tag_info(blapsi:format,_,Content,blapsi:format,Lit) :- !, + insist(Content=[Lit],bad_content(Content,blapsi:format)). +ao_tag_info(blapsi:face, Attr, Content, Pred, Lit) :- !, + %insist(member('ID'=ID,Attr)), + insist(member('label'=Label,Attr)), + insist(Content=[],non_empty_content(blapsi:face,Content)), + ( fail % Pred=bldata:face_id, Lit=ID IGNORE FOR NOW + ; Pred=bldata:face_label, Lit=Label + ). +ao_tag_info(blapsi:physicalProperties, _, PPContent, Tag, Lit) :- !, + insist(multi,member(element(Tag,_,Content),PPContent),no_content(blapsi:physicalProperties)), + insist(Content=[Lit],bad_content(Tag,Content)). +ao_tag_info(Tag,_,_,_,_) :- + warning(unrecognised_tag(Tag,blapsi:audioObject)). + +% identifier_pred('ASR Root ID',asr_root_id). +% identifier_pred('Sound Archive accession number',accession_number). + + + +% -------------- FILE SECTION --------------------------- + +file_triple(mets:'FLocat',Attr,LocContent,GAttr-FAttr,Dirs,ID,T) :- !, + ( member('MIMETYPE'=MimeType,FAttr) + -> audio_mimetype(MimeType), + insist(member('AMDID'=TMDId1,FAttr)), + insist(member('LOCTYPE'='URL',Attr)), + insist(member((xlink:href)=Link,Attr)), + insist(LocContent=[],non_empty(mets:'FLocat',LocContent)), + insist(member('USE'=Use1,FAttr);member('USE'=Use1,GAttr)), + % TMDId1 is sometimes "techMDxx digiprovXX" - need to get rid of second word + atomic_list_concat([TMDId|_],' ',TMDId1), + downcase_atom(Use1,Use), + ( T=rdf(bldata:ID/TMDId,dml:mimetype,literal(MimeType)) + ; file_path_triple(bldata:ID/TMDId,Dirs,Link,T) + ; T=rdf(bldata:ID/TMDId,bldata:use,literal(Use)) + ) + ; insist(\+member('AMDID'=_,FAttr)), + insist(member('ID'=FileID,FAttr)), + insist(member('LOCTYPE'='URL',Attr)), + insist(member((xlink:href)=Link,Attr)), + sub_atom(Link,_,3,0,Ext), + audio_extension(Ext), + ( T=rdf(bldata:ID/FileID,mo:sampled_version_of,bldata:ID) + ; file_path_triple(bldata:ID/FileID,Dirs,Link,T) + ; member(element(Tag,_,Content),LocContent), + blapsi_triple(Tag,Content,bldata:ID/FileID,T) + ) + ). + +file_triple(mets:'Fcontent',_,_,_,_,_,_) :- !, fail. +file_triple(Tag,_,_,_,_,_,_) :- warning(unrecognised_tag(Tag,file)). + +file_path_triple(URI,Dirs,Link,rdf(URI,bldata:path,literal(Path))) :- + atomics_to_string(Parts,"/",Link), + atomics_to_string(Dirs,"/",Dir), + append(_,[Name],Parts), + directory_file_path(Dir,Name,Path). + +audio_mimetype('sound/wav'). +audio_mimetype('sound/wma'). +audio_mimetype('sound/mp3'). +audio_mimetype('sound/ogg'). + +audio_extension(wav). +audio_extension(mp3). +audio_extension(wma). + +% ---------------------------- BLAPSI INFO --------------------------------- + +blapsi_info(file_sample, X, mo:sample_rate, type(xsd:float,SampleRate)) :- atom_number(X,SampleRate). +blapsi_info(file_resolution, X, mo:bitsPerSample, type(xsd:int,Bits)) :- atom_number(X,Bits). +blapsi_info(resolution, X, mo:bitsPerSample, type(xsd:int,Bits)) :- atom_number(X,Bits). +blapsi_info(file_channels, X, mo:channels, type(xsd:int,Channels)) :- atom_number(X,Channels). +blapsi_info(file_duration, X, mo:duration, type(xsd:float,Millis)) :- parse_duration_millis(X,Millis). +blapsi_info(file_bitrate, X, blapsi:file_bitrate, X). % !!! FIXME should be attached to file, not to signal +blapsi_info(file_size, X, blapsi:file_size, type(xsd:int,Size)) :- atom_number(X,Size). +blapsi_info(file_length, X, blapsi:file_length, type(xsd:int,Size)) :- atom_number(X,Size). + +% --------------------------- SUPPORTING PREDICATES -------------------------- + +:- use_module(library(async)). +:- public scrape_all/2. +:- volatile_memo scrape_all(+options:list,-count:nonneg). +scrape_all(Opts,Count) :- + option(spacing(Sleep),Opts,1), + option(timeout(Timeout),Opts,10), + findall( R, rdf(R,dml:blpage,_), Rs), + with_progress_stack(map_with_progress(scrape_then_sleep(Sleep,Timeout),Rs,Ss)), + exclude(=(ok),Ss, Failures), + (Failures=[] -> length(Rs,Count); throw(scrape_errors(Failures))). + +scrape_then_sleep(D,T,R,Status) :- + ( audio_link(R,_) -> Status=ok + ; memo:reify(bl_p2r:slow(D,call_with_time_limit(T,scrape_audio_link(R,_))),Status), + (Status=ex(abort(Reason)) -> throw(abort(Reason)); true) + ). + +slow(Delay,Goal) :- call(Goal), sleep(Delay). + +%% has_available_audio(+R:uri) is semidet. +%% has_available_audio(-R:uri) is nondet. +% True when R is a recording in the BL collection whose audio is +% publicly available. +has_available_audio(R) :- + rdf(R,dml:blpage,_), + scrape_audio_link(R,_). + +:- public audio_link/2. +audio_link(URI,AudioURL) :- + browse(scrape_audio_link(URI,AudioURL)). + +:- public audio_file/3. +audio_file(URI,Path,just(mp3)) :- + setting(audio_root,just(Root)), + ( rdf(URI,bldata:path,literal(RelPath)), + rdf(URI,rdf:type,mo:'Signal') + ; rdf(URI2,mo:sampled_version_of,URI), + rdf(URI2,dml:mimetype,literal('sound/mp3')), + rdf(URI2,bldata:path,literal(RelPath)) + ), + atomic_list_concat([Root,RelPath],'/',Path). + +:- volatile_memo scrape_audio_link(+atom,-atom). + +scrape_audio_link(URI,AudioURL) :- + rdf(URI,dml:blpage,PageURL), + debug(bl_p2r,'Scraping audio link for ~w...',[URI]), + atom_concat('http://sounds.bl.uk/',_,PageURL), + http_get(PageURL,Doc,[]), + xpath(Doc,//li(@class=mainTrack)/a(@id),ID), + string_concat("MNT-",Key,ID), + string_concat('http://sounds.bl.uk/GT/',Key,AudioURL). + +sandbox:safe_primitive(bl_p2r:audio_link(_,_)). +sandbox:safe_primitive(bl_p2r:scrape_audio_link(_,_)). + +xpath(Prop,E,Path,Val) :- xpath(E,Path,I), xpath(I,/self(Prop),Val). + +warning(Term) :- nl, print_message(warning,Term), fail. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/charm_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/charm_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,245 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(charm_p2r, [ audio_link/3 ]). + +/** Access to beets database + */ + + +% :- use_module(library(odbc)). +:- use_module(library(csv)). +:- use_module(library(musicbrainz)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(termutils)). +:- use_module(library(rdfutils)). +:- use_module(library(stringutils)). +:- use_module(library(dcg/basics)). +% :- use_module(library(odbcutils)). +:- use_module(entailment(p2r)). +:- use_module(library(memo)). +% :- use_module(library(resolve)). + +:- set_prolog_flag(double_quotes,string). + +:- rdf_register_prefix(charm,'http://dml.org/charm/'). + +:- setting(csv_database,string,"~/lib/charm/charm-1.csv","Location of CHARM colon-separated-values"). +:- setting(audio_root,ground,nothing,"Location of CHARM audio files"). +% item(Id) :- +% odbc_query(charm,"select id from cmr",row(Id)). + +% item(Id,Prop,Val) :- +% odbc_table_column(charm,cmr,Prop), +% \+ignore_column(Prop), +% qsql(charm,"select ~w from cmr where id=~d and ~w is not null and ~w!=''",[Prop,Id,Prop,Prop], row(Val)). + +% ignore_column(id). +% ignore_column(digital_eq). +% ignore_column(eq_base). +% ignore_column(eq_mid). +% ignore_column(eq_top). +% ignore_column(old_id). + +map('TNo',tno). %? + +% work +map('Title',title,list(";",atom)). +map('Composer(s)',composer,list("/",composer)). + +% performance +map('Artist',performer,list("/",set(";",performer))). +map('Conductor',conductor,atom). + +map('Label',label,atom). +map('Series',series,atom). +map('Cat No.',cat_no,atom). +map('Size',size,number). +% map('Matrix No.',matrix_no,atom). +% map('Single Side No. (or other ref.)',single_side_no). +map('File Name',file_name,atom). +map('Notes',notes,atom). +map('Rec.Date (dd/mm/yyyy)', recording_date, date(old)). + +% transfer event (recording from vinyl to digital signal) +map('Speed', speed, number). + +% No need for this much detail really.. +% map('Stylus',stylus_size, number). +% map('Weight',stylus_weight, number). +% map('EQ bass',eq_bass). +% map('EQ mid',eq_mid). +% map('EQ top',eq_top). +% map('Digital EQ','digital_eq'). +% map('turnover',turnover). +map('tech notes', technical_notes, atom). +map('x-fer date', transfer_date, date(new)). +map('Transfer Engineer', transfer_engineer, atom). + +:- volatile_memo string_to_date(+atom,+string,-ground). +string_to_date(Era,X,Date) :- + string_codes(X,Codes), + once(phrase(charm_interval(Era,DD),Codes)), + charm_date_to_time(DD,Date). + +:- rdf_meta convert(+,+,o). +convert(string,X,literal(X)). +convert(atom,X,literal(Y)) :- atom_string(Y,X). +convert(number,X,literal(Y)) :- number_string(Y,X). +convert(date(E),X,literal(Date)) :- string_to_date(E,X,Date). +convert(set(Sep,Type),X,Y) :- + split_string(X,Sep,"\s",Xs), + member(Z,Xs), + convert(Type,Z,Y). +convert(list(Sep,Type),X,Y) :- + split_string(X,Sep,"\s",Xs), + member(Z,Xs), + convert(Type,Z,Y). + +convert(performer,X,Y) :- convert(atom,X,Y). +% convert(performer,X,literal(Y)) :- +% porter_stem:tokenize_atom(X,Tokens), +% phrase(charm_performer(Perf),Tokens), +% phrase(performer(Perf),Codes1), +% atom_codes(Y,Codes1). + + +convert(arranger,X,literal(Y)) :- atom_concat(X,' [arranger]',Y). +convert(writer,X,literal(Y)) :- atom_concat(X,' [writer]',Y). + +convert(composer,X,Y) :- + split_string_around(" arr. ",X,Composer,Arranger), !, + ( convert(composer,Composer,Y) + ; convert(arranger,Arranger,Y) + ). + +convert(composer,X,Y) :- + split_string_around(" - ",X,Composer,Writer), !, + ( convert(composer,Composer,Y) + ; convert(writer,Writer,Y) + ). + +convert(composer,X,literal(Y)) :- traditional(X,Z), !, format(atom(Y),'[traditional:~s]',[Z]). +convert(composer,X,literal(Y)) :- anonymous(X,Z), !, format(atom(Y),'[anonymous:~s]',[Z]). +convert(composer,X,literal(Y)) :- atom_string(Y,X). + +% charm_performer(agent(Tokens)) --> + +anonymous(X,Z) :- (string_concat("Anon",Y,X); string_concat("anon",Y,X)), strip_string(Y,Z). +traditional(X,Z) :- string_concat("Trad.",Y,X), strip_string(Y,Z). + + +pad_int(L,N,C1,C2) :- format(codes(C1,C2),'~`0t~d~*+',[N,L]). + +xsd_time(ymd(Y,M,D),xsd:date) --> pad_int(4,Y), "-", pad_int(2,M), "-", pad_int(2,D). +xsd_time(ym(Y,M),xsd:gYearMonth) --> pad_int(4,Y), "-", pad_int(2,M). +xsd_time(y(Y),xsd:gYear) --> pad_int(4,Y). +xsd_time(range(D1,_),Type) --> xsd_time(D1,Type). + +charm_date_to_time(Date,type(Type,Value)) :- + phrase(xsd_time(Date,Type1),Codes), + rdf_global_id(Type1,Type), + atom_codes(Value,Codes). + +year(old,Y) --> integer(YY), { YY>=100 -> Y=YY ; Y is YY+1900 }. +year(new,Y) --> integer(YY), { YY>=100 -> Y=YY ; Y is YY+2000 }. +month(M) --> integer(M), {between(1,12,M)}. +day(D) --> integer(D), {between(1,31,D)}. + +charm_date(E,ymd(Y,M,D)) --> year(E,Y), "-", month(M), "-", day(D). +charm_date(E,ymd(Y,M,D)) --> day(D), "-", month(M), "-", year(E,Y). +charm_date(E,ymd(Y,M,D)) --> day(D), "/", month(M), "/", year(E,Y). +charm_date(E,ymd(Y,M,D)) --> day(D), ".", month(M), ".", year(E,Y). +charm_date(E,ym(Y,M)) --> year(E,Y), "-", month(M). +charm_date(E,ym(Y,M)) --> month(M), "/", year(E,Y). +charm_date(E,y(Y)) --> year(E,Y). + +charm_interval(_,range(y(Y1),y(Y2))) --> + integer(Y1), {Y1>=100}, "-", + integer(YY), {YY>12}, + { YY<100 -> Y2=1900+YY; Y2=YY }. + +charm_interval(E,Int) --> + charm_date(E,D1), + ( "--", charm_date(E,D2), {Int=range(D1,D2)} + ; {Int=D1} + ). + + +rdf(charm:title, rdfs:subPropertyOf, dc:title) <== true. +rdf(charm:enc(Id), charm:enc(Prop), Obj) <== + setting(csv_database,Pattern), + expand_file_name(Pattern,[DBFile]), + csv_to_rdf(DBFile,Id,Prop,Obj). + +csv_to_rdf(DBFile,Id,Prop,Obj) :- + once(csv_read_file_row(DBFile,Header,[convert(false),line(1)])), + functor(Header,row,NumCols), + functor(Row,row,NumCols), + arg(N,Header,' I.D.'), + arg(N,Row,Id), + csv_read_file_row(DBFile,Row,[convert(false),line(L)]), L>1, + status("Importing charm: ~w",[Id]), + map_row(Header,Row,Prop,Obj). + +null_value(""). +null_value("na"). +null_value("n/a"). +null_value("#VALUE!"). + +map_row(Header,Row,Pred,Obj) :- + arg(I,Header,Col), arg(I,Row,Val1), + map(Col,Pred,Type), + strip_string(Val1,Val), \+null_value(Val), + ( convert(Type,Val,Obj) *-> true + ; print_message(warning,conversion_failed(Col,Type,Val)), + format(atom(Lit),'FAILED(~q)',[Val]), % fail + Obj=literal(Lit) + ). + +% Old MYSQL version +% rdf(charm:num(4,Id), charm:enc(Prop), literal(Val)) <== +% item(Id), +% status("Importing charm:~d",[Id]), +% item(Id,Prop,Val). + + +:- public import/0. +% import :- with_odbc(charm, assert_all(charm_p2r)). +import :- assert_all(charm_p2r). + +:- public audio_file/3. +audio_file(URI,Path,just(flac)) :- + rdf(URI,charm:file_name,literal(FileName)), + setting(audio_root,just(Root)), + atomic_list_concat([Root,'/',FileName,'.',flac],Path). + +audio_link(Type,URI,URL) :- + member(Type,[mp3,flac]), + rdf(URI,charm:file_name,literal(Filename)), + ( sub_atom(Filename,_,_,_,'£') + -> atom_codes(Filename,C1), + fix_url(C1,C2), + atom_codes(Filename2,C2) + ; Filename2=Filename + ), + format(atom(URL),'http://charm.cchcdn.net/audio/~w/~w.~w',[Type,Filename2,Type]). + +fix_url([],[]). +fix_url([0'£|C1],[0'%, 0'A, 0'3|C2]) :- !, fix_url(C1,C2). +fix_url([C|C1],[C|C2]) :- !, fix_url(C1,C2). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/code_cache.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/code_cache.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,35 @@ +:- module(code_cache, + [ clean_code_cache/1 + , cache_code/3 + , cache_code/2 + , call_cached/2 + ]). + +:- use_module(library(insist)). + +:- meta_predicate cache_code(0,-). +:- meta_predicate cache_code(+,0,-). + + +cache_code(Code,Code1) :- cache_code(false,Code,Code1). +cache_code(MultiUse,Code,code_cache:call_cached(ID,MultiUse)) :- + uuid(ID), + get_time(T), + recorda(ID,code_cache(T,Code)). + +call_cached(ID,Keep) :- + insist(recorded(ID,code_cache(_,Code),Ref),code_not_in_cache(ID)), + (Keep=false -> erase(Ref); true), + call(Code). + +clean_code_cache(MaxAge) :- + get_time(Now), + Oldest is Now-MaxAge, + forall( ( recorded(_,code_cache(T,Code),Ref), T Tools for applying compression programs to abitrary streams. + + This module provides a framework for applying a range of compression and + delta compression programs to arbitrary streams generated by Prolog code. + In particular, the predicates complexity/3 and conditional_complexity/4 + use compression programs to estimate Kolmogorov complexity and conditional + complexity. + + Compression programs are invoked by a collection of shell scripts included + with this software, in the scripts/compression subdirectory of the dml cpack. + The method to be used is determined by a term of type compression_method: + == + compression_method ---> id % no compression + ; compress(c_method) + ; diff(d_method,pred). + c_method ---> lzma ; gz ; bz. + + d_method ---> bsdiff + ; xdelta % using xdelta3 program + ; vcdiff % using open-vcdiff + ; vczip % using vczip tools from AT&T + ; xdiff % using binary to text encoding and diff + ; zzd(c_method, d_method) + ; zzcd(c_method, d_method) + ; dz(d_method, c_method). + == + + Currently we do not subtract an known overheads associated with redundant + information in compression program outputs, such as 'magic bytes' in a header + used to enable tools to recognise which program was used to compress a given file. +*/ + +:- use_module(library(settings)). +:- use_module(library(memo)). +:- use_module(library(process)). +:- use_module(library(fileutils)). +:- use_module(library(swipe)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_codes)). +:- use_module(library(zlib)). + +user:file_search_path(compression,dml(scripts/compression)). + +:- initialization time(memo_attach(memo(compression),[])). + +%% print_delimited_dcg(+P:phrase(list(code))) is det. +% +% Runs the DCG phrase to generate a list of character codes, and then +% print the textually encoded length of the resulting list, followed by +% a carriage return, followed by the characters themselves. Thus, the resulting +% sequence of bytes is self-delimiting. +print_delimited_dcg(Phrase) :- + phrase(Phrase,Codes), + length(Codes,Length), + format('~d\n~s',[Length,Codes]). + +:- meta_predicate + complexity(+,0,-), + min_complexity(-,0,-), + conditional_complexity(+,0,0,-), + min_conditional_complexity(-,0,0,-), + conditional_ncd(+,0,0,0,-), + ncd(+,0,0,-). + +:- meta_predicate with_zlib_stream(//). + +%% complexity(+Method:compression_method, +Writer:pred, -K:nonneg) is det. +%% complexity(-Method:compression_method, +Writer:pred, -K:nonneg) is nondet. +%% complexity(-Method:compression_method, -Writer:pred, -K:nonneg) is nondet. +% +% Estimates the Kolmogorov complexity in bits of the sequence of bytes written to the +% current output stream by the goal Writer. If Writer is unbound on entry, then +% browses the set of previously computed results, which are stored in a volatile memo. +% +% Method can be =|id|= for no compression, or =|compress(M)|= for compression using +% program M. If Method is a ground term of the form =|diff(M,RefWriter)|=, then +% complexity is estimated using a delta compression with respect to the bytes written +% by RefWriter. Methods are described in the module header. Conditional complexity +% can more conveniently be estimated using conditional_complexity/4. +complexity(Method,Mod:Writer,K) :- + ( nonvar(Writer), complexity_method(Method), ground(Method) + *->complexity1(Method,Mod:Writer,K) + ; browse(complexity1(Method,Mod:Writer,K)) + ). + +execable(A) :- var(A), !, fail. +execable((A,B)) :- !, execable(A), execable(B). +execable(_). + +:- volatile_memo min_complexity(-ground,+callable,-number). +min_complexity(Best,Writer,KMin) :- + aggregate(min(K,Meth),complexity(Meth,Writer,K),min(KMin,Best)). + +%% conditional_complexity(+M:cc_method, +RefWriter:pred, +Writer:pred, -K:nonneg) is det. +% +% Estimate conditional Kolmogorov complexity of byte sequence produced by Writer +% given bit sequence produced by RefWriter, using one of several methods: +% == +% cc_method ---> id % no compression, complexity is length of data from Writer +% ; compress(c_method) % ignore reference sequence and compress +% ; delta(d_method) % do delta compression using given method +% ; naive(c_method). % use naive estimate using concatentation method +% == +% The naive estimate of K(x|y) is C(yx) - C(y), where C(.) is compressed length and +% xy is simply x concatenated with y. It may give nonsensical zero results. +% It is not the length of any concrete message that can produce x given y. +conditional_complexity(Method,Ref,Writer,K) :- + ( Method=delta(Diff), M=diff(Diff,Ref) +% ; Method=compress(C), M=compress(C) +% ; Method=compress(zlib), M=zlib + ; Method=delta(zlib), M=zlib(Ref) + ; Method=delta(dlzma), M=dlzma(Ref) +% ; Method=id, M=id + ), + complexity(M,Writer,K). + +conditional_complexity(naive(C),Ref,Writer,K) :- + complexity(compress(C),Ref,KY), + complexity(compress(C),(Ref,Writer),KXY), + K is KXY - KY. + +ncd(naive(C),Writer1,Writer2,D) :- + complexity(compress(C),Writer1,K1), + complexity(compress(C),Writer2,K2), + complexity(compress(C),(Writer1,Writer2),K12), + D is (K12 - min(K1,K2))/max(K1,K2). + +ncd(CM-DM,Writer1,Writer2,D) :- + complexity(CM,Writer1,K1), + complexity(CM,Writer2,K2), + conditional_complexity(DM,Writer1,Writer2,K2g1), + conditional_complexity(DM,Writer2,Writer1,K1g2), + D is max(min(K1,K1g2)/K1, min(K2,K2g1)/K2). + +ncd(opt,Writer1,Writer2,D) :- + min_complexity(_,Writer1,K1), + min_complexity(_,Writer2,K2), + min_conditional_complexity(_,Writer1,Writer2,K2g1), + min_conditional_complexity(_,Writer2,Writer1,K1g2), + D is max(min(K1,K1g2)/K1, min(K2,K2g1)/K2). + +conditional_ncd(naive(Method),Ref,Writer1,Writer2,D) :- + conditional_complexity(Method,Ref,Writer1,K1), + conditional_complexity(Method,Ref,Writer2,K2), + conditional_complexity(Method,Ref,(Writer1,Writer2),K12), + D is (K12 - min(K1,K2))/max(K1,K2). + +conditional_ncd(DM,Ref,Writer1,Writer2,D) :- + conditional_complexity(DM,Ref,Writer1,K1), + conditional_complexity(DM,Ref,Writer2,K2), + conditional_complexity(DM,(Ref,Writer1),Writer2,K2g1), + conditional_complexity(DM,(Ref,Writer2),Writer1,K1g2), + D is max(min(K1,K1g2)/K1, min(K2,K2g1)/K2). + +:- volatile_memo min_conditional_complexity(-ground,+callable,+callable,-number). +min_conditional_complexity(Best,Ref,Writer,KMin) :- + aggregate(min(K,Meth),(conditional_complexity(Meth,Ref,Writer,K),Meth\=naive(_)), min(KMin,Best)). + +%% complexity_method(-M:compression_method) is nondet. +complexity_method(diff(Diff,_)) :- command(diff0(Diff,library('swipe.pl')),_,_). +complexity_method(compress(Comp)) :- command(compress(Comp),_,_). +complexity_method(id). +complexity_method(zlib). +complexity_method(zlibi). +complexity_method(zlib(_)). +complexity_method(dlzma(_)). + +:- persistent_memo complexity1(+ground,+callable,-number). +complexity1(id,Writer,K) :- with_transducer(cat,Writer,stream_length(K)). +complexity1(compress(Meth),Writer,K) :- with_transducer(compress(Meth), Writer, stream_length(K)). +complexity1(diff(Diff,RefWriter),Writer,K) :- + with_temp_files([F1], + ( with_output_to_file(F1,RefWriter), + with_transducer(diff0(Diff,F1), Writer, stream_length(K)))). +complexity1(zlib,Writer,K) :- + with_zlib_stream(call_zsync(Writer,K)). + +complexity1(zlibi,Writer,K) :- + with_zlib_stream((call_zsync(write_bytes([255]),_), call_zsync(Writer,K))). + +complexity1(zlib(Ref),Writer,K) :- + with_zlib_stream((call_zsync(Ref,_), call_zsync(Writer,K))). + +complexity1(dlzma(RefWriter),Writer,K) :- + with_temp_files([F1], + ( with_output_to_file(F1,RefWriter), + with_transducer(dlzma(F1,['-b0']), Writer, read_line_to_string(current_input,KString)))), + number_string(K,KString). + + +subs(_,_,T1,T2) :- var(T1), !, T1=T2. +subs(Old,New,T1,T2) :- T1==Old, !, T2=New. +subs(Old,New,T1,T2) :- + T1 =.. [F | Args1], + maplist(subs(Old,New),Args1,Args2), + T2 =.. [F | Args2]. + + +% this is hopeless... +length_prob(Meth,L,Prob) :- + length(X,L), + aggregate( sum(2**(-8*B)), + X^(maplist(between(0,255),X), + with_transducer(compress(Meth), write_bytes(X), stream_length(B)), + format(user_error, '\r~w : ~w', [X,B]) + ), + Prob). + +%% write_bytes(+Bytes:list(between(0,255))) is det. +% Writes a sequence of bytes to current_output. +write_bytes(Bytes) :- with_stream_encoding(current_output,octet,maplist(put_code,Bytes)). + + +% -------------------------------- Using ZLIB ------------------------------ + + +with_zlib_stream(Phrase) :- + setup_call_cleanup( + open_null_stream(Out), + setup_call_cleanup( + zopen(Out,ZOut,[level(9),close_parent(false)]), + with_output_to(ZOut,call_dcg(Phrase,Out-0,_)), + close(ZOut)), + close(Out)). + +zpos(Pos,Out-Pos,Out-Pos). +zsync(Bits,Out-Pos0,Out-Pos1) :- + flush_output, + byte_count(Out,Pos1), + ( Pos1=Pos0 -> Bits=0 % no data since last sync + ; Bits is 8*((Pos1-Pos0)-4)-(3+3) % subtract estimate of final type 0 block. + ). + +call_zsync(Goal,Delta) --> {call(Goal)}, zsync(Delta). + + +% ------ Method comparison ----- +evaluate_delta(KRel,Method) :- + call_with_mode(browse, setof(K-Meth,conditional_complexity(Meth,_:_,_:_,K),KMeths)), + memberchk(_-delta(_),KMeths), + exclude(eval_exclude,KMeths,KMeths1), + KMeths1 = [KBest-_|_], + member(K-Method,KMeths1), + KRel is K/KBest. + +:- public method_rankings/2. +method_rankings(Method,Scores) :- + setof( Method-KRels, + bagof(KRel, evaluate_delta(KRel,Method), KRels), + AllScores), + member(Method-Scores,AllScores). + +eval_exclude(_-Method) :- exclude_method(Method). +exclude_method(naive(_)). +exclude_method(delta(DMethod)) :- exclude_dmethod(DMethod). +exclude_dmethod(xdiff). +exclude_dmethod(dz(DM,_)) :- exclude_dmethod(DM). +exclude_dmethod(zzcd(_,DM)) :- exclude_dmethod(DM). +exclude_dmethod(zzd(_,DM)) :- exclude_dmethod(DM). + +delta_method(compress(C),compress(C)). +delta_method(delta(M),delta(M)). +delta_method(id,id). + + +% ----------------------- Compression framework -------------------------------------- + + +swipe:def(Pipe,Def) :- def(Pipe,Def). + +def( findcat(Dir), sh(0 >> $_, '~s ~s',[compression(findcat)+execute, file(Dir,[file_type(directory)])])). +def( humdump(Dir), findcat(Dir) >> sh($hum >> $hum,'rid -G')). +def( length, sh($_ >> $number, 'wc -c')). +def( prepend(File^T), sh($T >> $T,'cat ~s -',[File+read])). +def( prepend(_> $T,'cat ~s -',[T> $T, 'tail -c +$((1+~s))',[$(File^T :> length)])). +def( unprepend(T> $T, 'tail -c +$((1+~s))',[$(Pipe >> length)])). +def( compress(Method), sh( $X >> $z(Method,X), Cmd)) :- compressor(Method,Cmd,_). +def( decompress(Method), sh( $z(Method,X) >> $X, Cmd)) :- compressor(Method,_,Cmd). + +def( diff0(Diff,Ref), diff(Diff,Ref)). +% def( diff0(dz(Diff,Comp),Ref), diff(Diff,Ref) >> compress(Comp)). +def( diff(Diff,Ref), diff(Diff, encode, Ref+read)). +% def( diff(zzd(Comp,Diff),Ref), compress(Comp) >> buf(2,diff(Diff, encode, T<(Ref^T :> compress(Comp))))). +def( diff(zzcd(Comp,Diff),Ref), prepend(Ref^T) >> compress(Comp) >> buf(2,diff(Diff, encode, _<(Ref^T :> compress(Comp))))). + +def( patch(Method,Ref), diff(Method, decode, Ref+read)). +def( patch(zzd(Comp,Diff),Ref), buf(2,diff(Diff, decode, _<(Ref^_ :> compress(Comp)))) >> decompress(Comp)). +def( patch(zzcd(Comp,Diff),Ref), buf(2,diff(Diff, decode, _<(Ref^T :> compress(Comp)))) >> decompress(Comp) >> unprepend(Ref^T)). + +def( diff(Method,encode,RefSource), sh( $X >> $dz(Method,X), [compression(Script)+execute, encode, RefSource | Args])) :- differ(Method,Script,Args,_). +def( diff(Method,decode,RefSource), sh( $dz(Method,X) >> $X, [compression(Script)+execute, decode, RefSource | Args])) :- differ(Method,Script,_,Args), Method\=zvcz. +def( buf(N,Pipe), sh(Type,'~s ~d ~s',[compression(bufs)+execute, \N, \Cmd])) :- command(Pipe,Type,Cmd). + +def( diff1(Diff,Ref), diff2(Diff, Ref)). +def( diff1(zzd(Comp,Diff),Ref), compress(Comp) >> diff2(Diff, Ref >> compress(Comp))). +def( diff1(zzcd(Comp,Diff),Ref), prepend(_> compress(Comp) >> diff2(Diff, Ref >> compress(Comp))). +def( patch1(Diff,Ref), patch2(Diff, Ref)). +def( patch1(zzd(Comp,Diff),Ref), patch2(Diff, Ref >> compress(Comp)) >> decompress(Comp)). +def( patch1(zzcd(Comp,Diff),Ref), patch2(Diff, Ref >> compress(Comp)) >> decompress(Comp) >> unprepend(_> $dz(Method,X), [compression(encode)+execute, Script, X> $X, [compression(decode)+execute, Script, X> $dz(dlzma,X), [compression(dlzma)+execute | Args])) :- + append(Opts,[Ref],Args). + +% compressor(xz,xz,xzcat). +compressor(lzma,lzma,lzcat). +compressor(xzraw,'xz -q -F raw','xzcat -F raw'). +compressor(gz,gzip,zcat). +compressor(bz,bzip2,bzcat). + +contains(Diff,Diff). +contains(dz(D1,_),D2) :- contains(D1,D2). +contains(zzd(_,D1),D2) :- contains(D1,D2). +contains(zzcd(_,D1),D2) :- contains(D1,D2). + + +% :- setting(max_vczip_chain_length, nonneg, 2, 'Maximum length of vczip processing chain'). + +differ(Method,Exec,[],[]) :- differ(Method,Exec). +differ(Method-Opts, Exec, EncArgs, []) :- differ(Method,Exec), options_for(Method,Opts,EncArgs). +differ(vczip(vcdiff),zvcz,['-Vcdiff'],[]). +differ(vczip(delta),zvcz,['-mdelta'],[]). +differ(vczip(sieve),zvcz,['-msieve.delta'],[]). +% differ(vczip(Delta,Chain,Encode),zvcz,[\Codes],[]) :- +% setting(max_vczip_chain_length,N), +% between(1,N,L), +% length(Chain,L), +% vczip_chain(Delta,Chain,Encode,Codes,[]). + +% differ(bsdiff,zbs). +% differ(xdelta,zxd). +differ(vcdiff,zvcd). +% differ(vczip,zvcz). +% differ(xdiff,zdiff). + +options_for(Method,Opts,Args) :- + Opts=[_|_], + setof(opt(Opt,Gen,A1,A2),method_option(Method,Opt,Gen,A1,A2),Possible), + seqmap(maybe_option,Possible,Opts-Args,[]-[]). + +maybe_option(_) --> []. +maybe_option(opt(Opt,Gen,A1,A2),[Opt|Opts]-A1,Opts-A2) :- call(Gen). + +method_option(xdelta, secondary(A), member(A,[djw,fgk])) --> ['-S',A]. +method_option(vcdiff, target_matches, true) --> ['-target_matches']. + +% vczip_chain(Delta,Chain,Encode) --> +% "-m", +% vczip_delta(Delta), ",", +% seqmap_with_sep(",",vczip_transform,Chain), ",", +% vczip_encode(Encode). + +% vczip_delta(delta) --> "delta". +% vczip_delta(sieve) --> "sieve.delta". + +% vczip_transform(bwt) --> "bwt". +% vczip_transform(mtf) --> "mtf". +% vczip_transform(rle) --> "rle". +% vczip_transform(rle(N)) --> "rle.", {between(0,1,N)}, at(N). + +% vczip_encode(huffman) --> "huffman". +% vczip_encode(huffgroup) --> "huffgroup". +% vczip_encode(huffpart) --> "huffpart". + + +compressor_overhead(gz,18). % see http://www.onicos.com/staff/iz/formats/gzip.html, https://tools.ietf.org/html/rfc1952 +compressor_overhead(bz,4). % http://en.wikipedia.org/wiki/Bzip2 (need to know number of blocks for better estimate) +compressor_overhead(lzma,0). % http://svn.python.org/projects/external/xz-5.0.3/doc/lzma-file-format.txt + +% ------------------------- Pipe and file tools ---------------------------------- + +splice_in(Pipe) :- with_pipe_input(S,Pipe,copy_stream_data(current_input,S)). +splice_out(Pipe) :- + with_pipe_output(S,Pipe, + ( with_stream_encoding(S,octet, + with_stream_encoding(current_output,octet, + copy_stream_data(S,current_output))))). + +:- op(1050,xfy,&). + + +%% with_transducer(+P:pipe, +Writer:pred, +Reader:pred) is det. +% Runs a pipeline defined using the framework provided by library(swipe), +% while concurrently sending data written by Writer to the process +% on its standard input and making data from the standard output of the +% process available to Reader on current_input. +:- meta_predicate with_transducer(+,0,0). +with_transducer(Pipe,Writer,Reader) :- + with_pipe_io( To-From, Pipe, + ( call_cleanup(with_output_to(To,Writer), close(To)) + & call_cleanup(with_input_from(From,Reader), close(From)) + )). + + +A & B :- concurrent(2, [A,B], []). + +%% with_stream_encoding(+S:stream,+E:encoding,+G:pred) is det. +% Call goall G with encoding of stream S temporarily set to E. Encoding +% is restored afterwards. +:- meta_predicate with_stream_encoding(+,+,0). +with_stream_encoding(S,Enc,Goal) :- + stream_property(S,encoding(Old)), + setup_call_cleanup(set_stream(S,encoding(Enc)), Goal, set_stream(S,encoding(Old))). + +%% stream_length(-L:natural) is det. +% Reads all the data available on Prolog stream current_input and returns the +% number of bits consumed. +stream_length(S,Bits) :- with_input_from(S,stream_length(Bits)). +stream_length(Bits) :- + with_stream_encoding(current_input,octet,accum_length(0,Bytes)), + Bits is 8*Bytes. + +accum_length(L,L) :- at_end_of_stream, !. +accum_length(L1,L3) :- + read_pending_input(current_input, Codes, []), + length(Codes,L), + L2 is L1 + L, + accum_length(L2,L3). + +with_temp_files(Files,Goal) :- + must_be(list(var),Files), + setup_call_cleanup( + maplist(tmp_file_stream(binary),Files,Streams), + (maplist(close,Streams), call(Goal)), + maplist(delete_file,Files)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/computations.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/computations.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,537 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(computations, + [ computation/3 + , computation_memo/3 + , vamp/3 + , transform/2 + , transform_param/3 + , sparse_to_dense/4 + , fold_commutative/3 + , map_reduce/4 + , map_reduce/5 + , unzip/3 + , pair/3 + , add/3, mul/3, div_by/3 + , fst/3, snd/3 + , with_csv_rows/3 + , csv_op/3 + , (*)/4 + , array_list/2 + , microtone_map/4 + , rows_cols/3 + , tempo_curves_stats/3 + , map_edges/3 + , csv_pitch_count_prob/5 + , pitch_hist_prob/4 + , pitch_name_number/2 + , pitch_number_name/2 + , freq_note_number/2 + , histof/4 + , histof/3 + , weighted_histof/5 + , weighted_histof/4 + ]). + +:- use_module(library(rdfutils)). +:- use_module(library(dcg/basics)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_macros)). +:- use_module(library(csvutils)). +:- use_module(library(listutils)). +:- use_module(library(lambda)). +:- use_module(library(memo)). +:- use_module(library(mlserver)). +:- use_module(library(sandbox)). +:- use_module(library(backend_json)). +:- use_module(library(real)). + +:- volatile_memo pitch_name_number(+atom,-integer). + +:- initialization <-library(pracma). + +:- rdf_meta vamp(?,r,r). + +%% vamp(+T:transform_class, +R:uri, -X:uri) is nondet. +%% vamp(-T:transform_class, -R:uri, -X:uri) is nondet. +% +% See transform/2 for values transform_class type. +vamp(Class,In,Out) :- + transform(Class,F), + computation(F,In,Out). + +%% transform(+T:transform_class, -R:uri) is det. +%% transform(-T:transform_class, -R:uri) is nondet. +% +% Mapping between short transform descriptors and full VAMP transform URIs for +% transforms currently known to the system. Currently recognised transform classes are: +% == +% transform_class ---> transcription % equivalent to transcription(0) +% ; transcription({0,1}) % 0: semitone, 1:microtonal +% ; beats({beatroot,qm}) % beats using one of two plugins +% ; beats % beats using any plugin +% ; tempo +% ; chords +% ; chord_notes +% ; key +% ; tonic +% ; chromagram +% ; mfcc. +% == +transform(Class,Transform) :- + ground(Class), !, + transforms(Class,Transforms), + member(Transform,Transforms). +transform(Class,Transform) :- + transform1(Class,Transform). + +% memoised collection of all transforms +:- volatile_memo transforms(+ground,-list(atom)). +transforms(Class,Transforms) :- + findall(T,transform1(Class,T),Transforms). + +%% transform1(-Class:transform_class,-R:uri) is nondet. +% Searches the RDF database for resources of class vamp:Transform which +% match the various transform classes. See transform/2. +transform1(beats,Transform) :- transform1(beats(_),Transform). +transform1(transcription,Transform) :- transform1(transcription(0),Transform). +transform1(transcription(Fine),Transform) :- + transform1(notes,Transform), + transform_param(Transform,finetune,Lit), + literal_number(Lit,Fine). + +transform1(Class,Transform) :- + def_transform(Class,Plugin,Output), + rdf(Transform,vamp:plugin,Plugin), + rdf(Transform,vamp:output,Output). + +:- rdf_meta transform_param(r,r,-). +transform_param(Transform,ParamId,Value) :- + rdf(Transform,vamp:parameter_binding,Binding), + rdf(Binding,vamp:parameter,Param), + rdf(Param,vamp:identifier,literal(ParamId)), + rdf(Binding,vamp:value,literal(Value)). + + +:- rdf_meta def_transform(-,r,r). + +% transform class, plugin, output +def_transform(notes, vamp_plugins:'silvet#silvet', vamp_plugins:'silvet#silvet_output_notes'). +def_transform(pitch_activation, vamp_plugins:'silvet#silvet', vamp_plugins:'silvet#silvet_output_pitchactivation'). +def_transform(silvet_timefreq, vamp_plugins:'silvet#silvet', vamp_plugins:'silvet#silvet_output_timefreq'). +def_transform(beats(beatroot), vamp_plugins:'beatroot-vamp#beatroot', vamp_plugins:'beatroot-vamp#beatroot_output_beats'). +def_transform(beats(qm), vamp_plugins:'qm-vamp-plugins#qm-tempotracker', vamp_plugins:'qm-vamp-plugins#qm-tempotracker_output_beats'). +def_transform(tempo, vamp_plugins:'qm-vamp-plugins#qm-tempotracker', vamp_plugins:'qm-vamp-plugins#qm-tempotracker_output_tempo'). +def_transform(onset_dfn(tempo), vamp_plugins:'qm-vamp-plugins#qm-tempotracker', vamp_plugins:'qm-vamp-plugins#qm-tempotracker_output_detection_fn'). +def_transform(chords, vamp_plugins:'nnls-chroma#chordino', vamp_plugins:'nnls-chroma#chordino_output_simplechord'). +def_transform(chord_notes, vamp_plugins:'nnls-chroma#chordino', vamp_plugins:'nnls-chroma#chordino_output_chordnotes'). +def_transform(harmonic_change, vamp_plugins:'nnls-chroma#chordino', vamp_plugins:'nnls-chroma#chordino_output_harmonicchange'). +def_transform(key, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_key'). +def_transform(key_strength, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_keystrength'). +def_transform(tonic, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_tonic'). +def_transform(mode, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_mode'). +def_transform(mfcc, vamp_plugins:'qm-vamp-plugins#qm-mfcc', vamp_plugins:'qm-vamp-plugins#qm-mfcc_output_coefficients'). +def_transform(mfcc_means, vamp_plugins:'qm-vamp-plugins#qm-mfcc', vamp_plugins:'qm-vamp-plugins#qm-mfcc_output_means'). +def_transform(onsets, vamp_plugins:'qm-vamp-plugins#qm-onsetdetector',vamp_plugins:'qm-vamp-plugins#qm-onsetdetector_output_onsets'). +def_transform(onset_dfn, vamp_plugins:'qm-vamp-plugins#qm-onsetdetector',vamp_plugins:'qm-vamp-plugins#qm-onsetdetector_output_detection_fn'). +def_transform(onset_smoothed_dfn, vamp_plugins:'qm-vamp-plugins#qm-onsetdetector',vamp_plugins:'qm-vamp-plugins#qm-onsetdetector_output_smoothed_df'). +def_transform(chromagram, vamp_plugins:'qm-vamp-plugins#qm-chromagram', vamp_plugins:'qm-vamp-plugins#qm-chromagram_output_chromagram'). +def_transform(chromameans, vamp_plugins:'qm-vamp-plugins#qm-chromagram', vamp_plugins:'qm-vamp-plugins#qm-chromagram_output_chromameans'). +def_transform(chromagram(upper), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_chroma'). +def_transform(chromagram(bass), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_basschroma'). +def_transform(chromagram(both), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_bothchroma'). +def_transform(spectrogram(semitone), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_semitonespectrum'). +def_transform(spectrogram(log_freq), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_logfreqspec'). +def_transform(spectrogram(tuned), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_tunedlogfreqspec'). +def_transform(melody, vamp_plugins:'mtg-melodia#melodia', vamp_plugins:'mtg-melodai#melodia_output_melody'). +def_transform(spectrogram(const_q), vamp_plugins:'qm-vamp-plugins#qm-constantq', vamp_plugins:'qm-vamp-plugins#qm-constantq_output_constantq'). +def_transform(segments, vamp_plugins:'qm-vamp-plugins#qm-segmenter', vamp_plugins:'qm-vamp-plugins#qm-segmenter_output_segmentation'). +def_transform(speech_music, vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter', + vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter_output_segmentation'). +def_transform(speech_music_dfn, vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter', + vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter_output_skewness'). + + +%% computation_memo(+Transform:uri,+Input:uri,-Output:uri) is det. +% Memoised functional Relation between transforms, inputs and outputs. + +:- multifile do_computation/3. + +:- rdf_meta computation_memo(r,r,r). +computation_memo(Fn,Input,Output) :- + must_be(atom,Fn), + must_be(atom,Input), + must_be(var,Output), + ( computation(Fn,Input,Output) -> true + ; memo:timed(computations:do_computation(Fn,Input,Output),comp(_,Time,Dur)), + format_time(atom(Timestamp),'%FT%T%:z',Time), + memo:hostname(Host), + phrase( ( vamp:computation_triples(Comp,Input,Fn,Output), + vamp:rdf(Comp,dml:'comp/time',literal(type(xsd:dateTime,Timestamp))), + vamp:rdf(Comp,dml:'comp/duration',literal(type(xsd:float,Dur))), + vamp:rdf(Comp,dml:'comp/host',literal(Host)) + ), Triples,[]), + forall(member(rdf(S,P,O),Triples), rdf_assert(S,P,O,vamp_memo)) + ). + + +%% computation(-Transform:uri,-Input:uri,-Output:uri) is nondet. +% Relation between transforms, inputs and outputs using RDF database +% of existing computations. + +:- rdf_meta computation(r,r,r). +computation(Fn,Input,Output) :- nonvar(Output), !, + rdf(Comp,dml:'comp/output',Output), + rdf(Comp,dml:'comp/function',Fn), + rdf(Comp,dml:'comp/input',Input). + +computation(Fn,Input,Output) :- nonvar(Input), !, + rdf(Comp,dml:'comp/input',Input), + rdf(Comp,dml:'comp/function',Fn), + rdf(Comp,dml:'comp/output',Output). + +computation(Fn,Input,Output) :- + rdf(Comp,dml:'comp/input',Input), + rdf(Comp,dml:'comp/function',Fn), + rdf(Comp,dml:'comp/output',Output). + +% ------------ Framework for doing computations on CSV files ----------- +:- meta_predicate with_csv_rows(2,+,-). +with_csv_rows(Pred,CSV,Result) :- + insist(uri_to_csv(CSV,Rows)), + insist(call(Pred,Rows,Result), failed_on_csv(Pred,CSV)). + +csv_op(Op,CSV,Result) :- + ( memoise(Op) + -> csv_op_memo(Op,CSV,Result) % ,_-ok) + ; with_csv_rows(row_op(Op),CSV,Result) + ), + debug(computations(item),'Done csv_op(~q,~q).',[Op,CSV]). + +sandbox:safe_primitive(computations:csv_op(_,_,_)). + +:- persistent_memo csv_op_memo(+ground,+atom,-ground). +csv_op_memo(Op,CSV,Result) :- with_csv_rows(row_op(Op),CSV,Result). + +:- initialization time(memo_attach(memo(computations2),[])). + +memoise(pitch_hist(_)). +memoise(freq_hist(_,_)). +memoise(tempo_hist(_,_)). +memoise(uniform_tempo(_)). +memoise(uniform_tempo_r(_)). +memoise(normalised_tempo(_)). +memoise(normalised_tempo_r(_)). + +row_op(id,Rows,Rows) :- !. +row_op(column(N),Rows,Vals) :- !, maplist(arg(N),Rows,Vals). +row_op(array,Rows,Array) :- !, maplist(row_list(_),Rows,Array). +row_op(chord_hist,Rows,Hist) :- !, histof(Chord,T,member(row(T,Chord),Rows),Hist). +row_op(pitch_hist(none),Rows,Hist) :- !, histof(Pitch,t(T,Dur),note(Rows,T,Dur,Pitch),Hist). +row_op(pitch_hist(W),Rows,Hist) :- !, weighted_histof(Weight,Pitch,t(T,Dur),weighted_note(W,Rows,T,Dur,Pitch,Weight),Hist). +row_op(beat_times,Rows,Times) :- !, row_op(column(1),Rows,Times). +row_op(onset_times,Rows,Times) :- !, row_op(column(1),Rows,Times). +row_op(tempo,Rows,Tempo) :- !, maplist(row_pair(1,2),Rows,Tempo). +row_op(uniform_tempo(DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(ml,cubic,DT,Tempo,Samples). +row_op(uniform_tempo_r(DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(r,cubic,DT,Tempo,Samples). +row_op(uniform_tempo(Meth,DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(ml,Meth,DT,Tempo,Samples). +row_op(uniform_tempo_r(Meth,DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(r,Meth,DT,Tempo,Samples). +row_op(normalised_tempo(N),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), normalised_sample(ml,N,Tempo,Samples). +row_op(normalised_tempo_r(N),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), normalised_sample(r,N,Tempo,Samples). +row_op(tempo_hist(DT,Map),Rows,Edges-Counts) :- !, + row_op(uniform_tempo(DT),Rows,_-Tempo), + M===Map, + [arr(Counts), arr(Edges)] === + deal(accumhist(flatten(feval(M,Tempo)),1,cardr(M)), flatten(edges(M))). + +row_op(tempo_hist_r(DT,Map),Rows,Edges-Counts) :- !, + map_to_r_edges(Map,REdges), + row_op(uniform_tempo_r(DT),Rows,_-Tempo), + Counts <- table(cut(Tempo,breaks=REdges)), + Edges <- REdges. + % memberchk(counts=Counts,Hist), + % memberchk(breaks=Edges,Hist). + +row_op(freq_hist(Map1,W),Rows,Counts) :- + column(transcription,freq,J), + ( W=none + -> maplist(arg(J),Rows,Freqs), Weights=1 + ; column(transcription,W,I), + rows_cols([J,I],Rows,[Freqs,Weights]) + ), + Map===Map1, % evaluate map and keep in Matlab workspace + X=feval(Map,12*log2(Freqs)-(12*log2(440)-69)), + array_list(accumhist(flatten(X),flatten(Weights),cardr(Map)),Counts). + +row_op(freq_hist_r(Map1,W),Rows,Counts) :- + column(transcription,freq,J), + map_to_r_edges(Map1,REdges), + Pitches=12*log2(Freqs)-(12*log2(440)-69), + ( W=none + -> maplist(arg(J),Rows,Freqs), + Hist <- hist(Pitches,breaks=REdges,plot=0) + ; column(transcription,W,I), + rows_cols([J,I],Rows,[Freqs,Weights]), + Hist <- hist(Pitches,Weights,breaks=REdges,plot=0) + ), + memberchk(counts=Counts,Hist). + +map_edges(r,Map,Edges) :- + map_to_r_edges(Map,Expr), + Edges <- Expr. +map_edges(ml,Map,Edges) :- + array_list(edges(Map),Edges). + +map_to_r_edges(expmap(Min,Max,N),sapply(seq(log(Min),log(Max),len=N+1),exp)). +map_to_r_edges(binmap(Min,Max,N),seq(Min-HalfWidth,Max+HalfWidth,len=N+1)) :- HalfWidth=(Max-Min)/(2*(N-1)). + +column(Format, Name, Number) :- csv(Format,Row), arg(Number,Row,Name). +csv(transcription, row(time,dur,freq,vel,pitch)). + +gather(P,Rows,Xs) :- findall(X,(member(R,Rows),call(P,R,X)),Xs). + + +microtone_map(Min,Max,Res,binmap(Min,Max,N)) :- N is (Max-Min)*Res+1. + +% qfreq(Q,Rows,T,Dur,QFreq) :- member(row(T,Dur,Freq,_,_),Rows), qlogfreq(Q,Freq,QFreq). +% weighted_qfreq(dur,Q,Rows,T,Dur,QFreq,Dur) :- member(row(T,Dur,Freq,_,_),Rows), qlogfreq(Q,Freq,QFreq). +% weighted_qfreq(vel,Q,Rows,T,Dur,QFreq,Vel) :- member(row(T,Dur,Freq,Vel,_),Rows), qlogfreq(Q,Freq,QFreq). +% qlogfreq(Q,In,Out) :- B is 12/log(2), Out is 69+round(Q*B*(log(In)-log(440)))/Q. +% goal_expansion(qlogfreq(Q,In,Out), Out is 69+round(Q*B*(log(In)-A))/Q) :- B is 12/log(2), A=log(440). + +uniform_sample(DT,In,Out) :- uniform_sample(ml,linear,DT,In,Out). + +uniform_sample(_,_,_,[Time-Val],[Time]-[Val]) :- !. +uniform_sample(Lang,Meth,DT,Pairs,Times1-Vals1) :- + unzip(Pairs,Times,Vals), + aggregate(max(T), member(T,Times), MaxT), + interp1(Lang,Meth,0:DT:MaxT,Times,Vals,Times1,Vals1). + +normalised_sample(N,In,Out) :- normalised_sample(ml,N,In,Out). + +normalised_sample(_,N,[Time-Val],Times-Vals) :- !, + rep(N,Time,Times), + rep(N,Val,Vals). +normalised_sample(Lang,N,Pairs,Times1-Vals1) :- + unzip(Pairs,Times,Vals), + aggregate(max(T), member(T,Times), MaxT), + interp1(Lang,cubic,linspace(0,MaxT,N),Times,Vals,Times1,Vals1). + +interp1(ml,Meth,TSpec,Times,Vals,Times1,Vals1) :- + length(Times,N), + (N<4 -> Method=q(linear); Method=q(Meth)), + T1===flatten(TSpec), + [arr(Times1), arr(Vals1)]===deal(T1,interp1(Times,Vals,T1,Method)). +interp1(r,Meth,TSpec,Times,Vals,Times1,Vals1) :- + ml_r(TSpec,RTSpec), + length(Times,N), + (N<4 -> Method = +linear; Method = +Meth), + Times1 <- RTSpec, + Vals1 <- interp1(Times,Vals,Times1,Method). + +ml_r(X1:DX:X2, seq(X1,X2,DX)). +ml_r(linspace(X1,X2,N), seq(X1,X2,len=N)). + +array_list(Array,List) :- arr(List)===flatten(Array). + +:- meta_predicate '*'(2,2,+,-). +*(F1,F2,X,Y) :- call(F1,X,Z), call(F2,Z,Y). + +note(Rows,T,Dur,NN) :- member(row(T,Dur,_,_,Pitch),Rows), pitch_name_number(Pitch,NN). + +weighted_note(dur,Rows,T,Dur,NN,Dur) :- member(row(T,Dur,_,_,Pitch),Rows), pitch_name_number(Pitch,NN). +weighted_note(vel,Rows,T,Dur,NN,Vel) :- member(row(T,Dur,_,Vel,Pitch),Rows), pitch_name_number(Pitch,NN). +weighted_note(dur*vel,Rows,T,Dur,NN,Weight) :- + member(row(T,Dur,_,Vel,Pitch),Rows), pitch_name_number(Pitch,NN), + Weight is Dur*Vel. + + +tempo_curves_stats(ml,Curves, _{means:Means,std_devs:StdDevs}) :- + Data===arr(Curves), + array_list(mean(Data,2),Means), + array_list(std(Data,0,2),StdDevs). + +tempo_curves_stats(r,Curves, _{means:Means,std_devs:Stds}) :- + data <- Curves, + Means <- apply(data,2,mean), + Stds <- apply(data,2,sd). + +:- meta_predicate histof(-,0,-) + , histof(-,-,0,-) + , weighted_histof(-,-,0,-) + , weighted_histof(-,-,-,0,-) + . + +%% histof(@Dom:A,+Goal:callable,-Hist:list(pair(A,natural))) is nondet. +% Compile a histogram over values taken by the variable Dom while enumerating +% all solutions of Goal. Repeated solutions of Goal with the same values +% count as distinct observations. See also histof/4. +histof(Dom,Goal,Hist) :- + setof(Dom-N,aggregate(count,Goal,N),Hist). + +%% histof(@Dom:A,@Disc:_,+Goal:callable,-Hist:list(pair(A,natural))) is nondet. +% Compile a histogram over values taken by the variable Dom while enumerating +% all solutions of Goal. The value of Disc is used to discriminate between +% solutions of Goal with the same value of Dom. See also histof/3 and aggregate/4 +% for more information about discriminator variables. +histof(Dom,Disc,Goal,Hist) :- + setof(Dom-N,aggregate(count,Disc,Goal,N),Hist). + +weighted_histof(W,Dom,Goal,Hist) :- + setof(Dom-N,aggregate(sum(W),Goal,N),Hist). + +weighted_histof(W,Dom,Disc,Goal,Hist) :- + setof(Dom-N,aggregate(sum(W),Disc,Goal,N),Hist). + +sparse_to_dense(Min,Max,Hist,Counts) :- + s_to_d(Min,Max,Hist,Counts). + +s_to_d(I,Max,[],[]) :- I>Max, !. +s_to_d(I,Max,[],[0|Counts]) :- !, succ(I,J), s_to_d(J,Max,[],Counts). +s_to_d(I,Max,[I-C|Hist],[C|Counts]) :- !, succ(I,J), s_to_d(J,Max,Hist,Counts). +s_to_d(I,Max,Hist,[0|Counts]) :- succ(I,J), s_to_d(J,Max,Hist,Counts). + + +add(X,Y,Z) :- Z is X+Y. + +:- meta_predicate + map_reduce(1,2,3,-), + map_reduce(1,2,3,-,-), + fold_commutative(3,+,-). + +%% map_reduce(+Generator:pred(-R), +Mapper:pred(+R,-A), +Reducer:pred(+A,+A,-A), -Result:A, -Errors:list(error_report(R))) is det. +%% map_reduce(+Generator:pred(-R), +Mapper:pred(+R,-A), +Reducer:pred(+A,+A,-A), -Result:A) is semidet. +% +% Simple implementation of map-reduce: Mapper is applied to each item produced by Generator +% and the results all combined using Reducer. Mapper should be a deterministic predicate. +% Failures and exceptions encountered in the mapping phase are reported in Errors. +% However, if the items are successfully mapped, this predicate fails. +% Any choice points left by mapper after its first solution are cut. +% +% == +% error_report(R) ---> failed(R); error(R,exception). +% == +map_reduce(Finder,Mapper,Reducer,Result) :- + map_reduce(Finder,Mapper,Reducer,Result,_). + +map_reduce(Finder,Mapper,Reducer,Result,Errors-Failures) :- + setof(X,call(Finder,X),Xs), + maplist(safe_call(Mapper),Xs,Ys), + partition_ok(Ys,Ok,Errors,Failures), + insist(fold_commutative(Reducer,Ok,Result)). + +%% safe_call(+P:pred(+A,-B), +X:A, -Y:result(A,B)) is det. +% +% Call binary predicate P with arguments of type A and B. The result +% term Y is of type +% == +% result(A,B) ---> ok(B); failed(A); error(A,exception). +% == +% and encodes the result of the call, including the input value that +% caused any failure or exception. +safe_call(Mapper,X,Z) :- + ( catch((call(Mapper,X,Y), Z=ok(Y)), Ex, + (Ex=abort_map -> throw(map_aborted); Z=error(X,Ex))), ! + ; Z=failed(X) + ). + +partition_ok([],[],[],[]). +partition_ok([In|Ins],Goods,Bads,Uglies) :- + ( In=ok(X) + -> Goods=[X|Goods1], partition_ok(Ins,Goods1,Bads,Uglies) + ; In=error(_,_) + -> Bads=[In|Bads1], partition_ok(Ins,Goods,Bads1,Uglies) + ; In=failed(X) + -> Uglies=[X|Uglies1], partition_ok(Ins,Goods,Bads,Uglies1) + ). + +fold_commutative(Op,Items,Result) :- + Items=[I1|Rest], + seqmap(Op,Rest,I1,Result), !. + +freq_note_number(F,N) :- N is 69+round(12*log(F/440)/log(2)). + +pitch_name_number(Name,Number) :- + atom_codes(Name,Chars), + phrase(note(Number),Chars). + +pitch_number_name(Number,Name) :- + phrase(note(Number),Chars), + atom_codes(Name,Chars). + +:- use_module(library(clpfd)). +note(Num) --> + [Nom], ({Mod=0}; [0'#],{Mod=1}), + { PC in 0..11, + Num #= 12*(Oct+1)+PC+Mod, + nom_semis(Nom,PC) + }, + integer(Oct). + +nom_semis(0'C,0). +nom_semis(0'D,2). +nom_semis(0'E,4). +nom_semis(0'F,5). +nom_semis(0'G,7). +nom_semis(0'A,9). +nom_semis(0'B,11). + +unzip(Pairs,Xs,Ys) :- maplist(pair,Xs,Ys,Pairs). +pair(X,Y,X-Y). + +row_pair(I,J,Row,X-Y) :- arg(I,Row,X), arg(J,Row,Y). +row_list(N,Row,List) :- functor(Row,_,N), Row=..[_|List]. +rows_cols(Is,[],Cols) :- !, maplist(nil,Is,Cols). +rows_cols(Is,[R|Rs],Cols) :- + ( maplist(arg_cons(R),Is,Tails,Cols) + -> rows_cols(Is,Rs,Tails) + ; fail % rows_cols(Is,Rs,Cols) + ). + +arg_cons(Row,I,T,[X|T]) :- arg(I,Row,X). +nil(_,[]). + +fst(F,K1-V,K2-V) :- call(F,K1,K2). +snd(F,K-V1,K-V2) :- call(F,V1,V2). +div_by(K,X,Y) :- Y is X/K. + +mul(X,Y,Z) :- Z is round(X*Y). + +:- dynamic pitch_hist_table/5, pitch_hist_tabled/1. + +csv_pitch_count_prob(W,CSV,Pitch,Count,Prob) :- + must_be(ground,W), + ( pitch_hist_tabled(W) -> true + ; table_pitch_hist(W) + ), + pitch_hist_table(W,CSV,Pitch,Count,Prob). + +table_pitch_hist(W) :- + retractall(pitch_hist_table_cached(W)), + forall( browse(csv_op_memo(pitch_hist(W),CSV,Hist)), + ( retractall(pitch_hist_table(W,CSV,_,_,_)), + forall( pitch_hist_prob(Hist,Pitch,Count,Prob), + assert(pitch_hist_table(W,CSV,Pitch,Count,Prob))))), + assert(pitch_hist_tabled(W)). + +pitch_hist_prob(Hist,Pitch,Count,Prob) :- + unzip(Hist,_,Counts), + sumlist(Counts,Total), + member(Pitch-Count,Hist), + Prob is Count/Total. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/crawler.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/crawler.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,223 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(crawler, + [ crawl_loaded/2 + , crawl_ui//2 + , crawl/2 + , crawl/1 + , crawl_reload_graph/1 + ]). + +:- multifile authority/3. +:- multifile source/3. + +:- use_module(library(settings)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_parameters)). +:- use_module(library(http/http_wrapper)). +:- use_module(library(http/html_write)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(prov_schema)). +:- use_module(library(httpfiles)). +:- use_module(library(htmlutils), [element//2]). +:- use_module(library(dcg_core)). +:- use_module(library(insist)). +:- use_module(components(basics)). +:- use_module(components(messages)). +:- use_module(user(user_db)). + +:- setting(enable_auto_crawl, boolean, true, "Enables automatic semantic web searches for recognised URIs"). + +:- http_handler(root(crawl), crawl_handler, []). + +no_cache --> + html_post(head,meta(['http-equiv'='Cache-Control', content='no-cache, no-store, must-revalidate, max-age=0'],[])), + html_post(head,meta(['http-equiv'='Pragma', content='no-cache'],[])), + html_post(head,meta(['http-equiv'='Expires', content=0],[])). + +refresh(URL,Delay) --> + no_cache, + html_post(head,meta(['http-equiv'=refresh, content="~d;~w"-[Delay,URL]],[])). + +%% crawl_handler(+Request) is det. +% web service to query given authority about given URI +crawl_handler(Request) :- + authorized(write(default, load(lod))), + http_parameters(Request, + [ uri(URI, [optional(false), description("URI to search for")]) + , src(Src, [optional(false), description("Source ID")]) + , return_to(Return, [ optional(true), description('URI to return to') ]) + , return_after(Delay, [ default(2) ]) + , messages(Msgs, [boolean, default(true)]) + ]), + debug(crawler,"Got request to consult ~w on ~w",[Src,URI]), + return_options(Return, Delay, Options), + ( Msgs=true + -> call_showing_messages(insist(crawl(URI,Src)),Options) + ; call_without_messages(insist(crawl(URI,Src)),Options) + ). + +call_without_messages(Goal,Options) :- + catch( (Goal, Msg='Success'), Ex, (Msg='Error', print_message(error,Ex))), + ( option(return_to(Return),Options) + -> option(return_after(Delay),Options,2), + reply_html_page(cliopatria(default),[], [ h2(Msg), \refresh(Return,Delay) ], [unstable]) + ; reply_html_page(cliopatria(default),[], [ h2(Msg) ], [unstable]) + ). + +return_options(Return, _, []) :- var(Return), !. +return_options(Return, Delay, [ return_to(Return), return_after(Delay) ]). + + +%% crawl_ui(+URI:resource,+NT:natural) is det. +% Component to allow user to trigger a crawl on a given URI, depending on +% NT, the number of triples which currently have it has subject. +crawl_ui(URI,NT) --> + ( {setof(S-Auto, uri_authority(URI,S,Auto),Sources)} + -> ( {setof(S-A, (member(S-A,Sources), \+crawl_loaded(URI,S)), Untapped)} + % !!! should check permissions here + -> { http_current_request(Request), + memberchk(request_uri(Here), Request) + }, + {debug(crawler,'Untapped sources: ~q',[Untapped])}, + no_cache, + ( {setting(enable_auto_crawl,true)}, + {setof(S, member(S-true,Untapped), AutoSources)} + -> html([ 'The following sources have been consulted automatically: ', + \seqmap_with_sep(html(', '),element(code),AutoSources), '.', br([]) + ]), + { debug(crawler,'consulting in parallel: ~w...',[AutoSources]), + concurrent_maplist(consult_source(URI),AutoSources,Statuses), + debug(crawler,'finished consulting on ~w.',[URI]) + }, + ( {member(ok,Statuses)} + -> refresh(Here,0), + html([b('At least one consultation succeeded; refreshing automatically.'),br([])]) + ; html([b('All consultations failed.'),br([])]) + ) + ; html(p([ 'Click to consult one of the following sources for more information.' + , br([]), \seqmap(consult_form(URI,Here),Untapped) + ])) + ) + ; [] + ) + ; {NT>0} -> [] + ; html(p('No triples and no authorities known for this URI.')) + ). + +consult_source(URI,Source,Status) :- + catch( (crawl(URI,Source), Status=ok), Ex, + (print_message(error,Ex), Status=error(Ex))). + +consult_form(URI,Here,Source-_) --> + {http_link_to_id(crawl_handler, [], FetchURL)}, + {source_name(Source,Name)}, + {source(Source,_,Opts), option(messages(Msgs),Opts,true)}, + html(form([style="display:inline-block", action(FetchURL)], + [ \hidden(uri, URI), + \hidden(src, Source), + \hidden(return_to, Here), + \hidden(messages, Msgs), + input([ type(submit), value(Name) ]) + ])). + +%% crawl_loaded(+URI:resource,+Source:atom) is semidet. +% True when URI has already been crawled and added to the RDF database. +crawl_loaded(URI,Source) :- + source_uri_graph(Source,URI,Graph), + debug(crawler,'Checking if loaded: ~w in graph ~w from ~w',[URI,Graph,Source]), + rdf(Graph,prov:wasDerivedFrom,URI,Graph). + + +%% crawl_reload_graph(+Graph:atom) is det. +% Attempts to delete the named graph and reload it from all the URIs +% that it was derived from. +crawl_reload_graph(Graph) :- + findall(URI,rdf(Graph,prov:wasDerivedFrom,URI,Graph),URIs), + length(URIs,NURIs), + print_message(information,crawl_reload(Graph,NURIs)), + rdf_transaction(( + rdf_unload_graph(Graph), + maplist(reload_into(Graph),URIs) + )). + +reload_into(Graph,URI) :- + uri_authority(URI,Source,_), + source_uri_graph(Source,URI,Graph), + load_into(Graph,Source,URI). + +%% crawl(+URI:resource) is det. +% Looks for information about URI on all authorities claiming authority on it. +% Queries are made in parallel using concurrent_maplist/2. +crawl(URI) :- + findall(S,uri_authority(URI,S,_),Sources), + concurrent_maplist(consult_source(URI),Sources,_). + + +%% crawl(+URI:resource,+Auth:atom) is det. +% Looks for information about URI on specified authority. +crawl(URI,Source) :- + debug(crawler,"Consulting source ~w on ~w...",[Source,URI]), + source_uri_graph(Source, URI, Graph), + rdf_transaction(load_into(Graph,Source,URI)). + +load_into(Graph,Source,URI) :- + source(Source, Handler, _), + ( call(Handler,crawl(URI,Graph)) + -> print_message(information,crawler_crawled(Source,URI,Graph)) + ; setof(T, call(Handler,describe(URI,T)), Triples), + length(Triples, NumTriples), + forall(member(rdf(S,P,O),Triples), rdf_assert(S,P,O,Graph)) + -> print_message(information,crawler_described(Source,URI,Graph,NumTriples)) + ; print_message(information,crawler_failed(Source,URI)) + ), + debug(crawler,'Asserting successful load of ~w into graph ~w from ~w',[URI,Graph,Source]), + rdf_assert(Graph, prov:wasDerivedFrom, URI, Graph). + +%% uri_authority(+URI:resource, -Auth:atom, -Auto:boolean) is nondet. +% True when Auth is declared as an authority on URI. If Auto=true, +% then, this authority should be queried automatically when URI is the +% subject of a 'list_resource' page. +uri_authority(URI,Src,Auto) :- + authority(Cond,Src,Opts), + once(matches(Cond,URI)), + option(auto(Auto),Opts,false). + +matches(begins(Prefix),URI) :- sub_atom(URI,0,_,_,Prefix). +matches(\+Cond,URI) :- \+matches(Cond,URI). +matches((C1,C2),URI) :- matches(C1,URI), matches(C2,URI). +matches((C1;C2),URI) :- matches(C1,URI); matches(C2,URI). + + +%% source_uri_graph(+Auth:atom,+URI:resource,-Graph:atom) is det. +% Derive the RDF graph name for a given authority. +source_uri_graph(Source,URI,Graph) :- + source(Source,Handler,_), + call(Handler,uri_graph(URI,Graph)). + +source_name(Source,Name) :- source(Source,Handler,_), call(Handler,name(Name)), !. +source_name(Source,Source). + +prolog:message(crawler_crawled(Src,URI,Graph)) --> + ["Triples from ~w about ~w loaded into ~w via crawl method"-[Src,URI,Graph]]. +prolog:message(crawler_described(Src,URI,Graph,N)) --> + ["Triples from ~w about ~w loaded into ~w via describe method: ~d."-[Src,URI,Graph,N]]. +prolog:message(crawler_failed(Src,URI)) --> + ["Failed to load anything from ~w about ~w."-[Src,URI]]. + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/csvutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/csvutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,35 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(csvutils, [uri_to_csv/2]). + +:- use_module(library(insist)). +:- use_module(api(archive)). + +:- set_prolog_flag(double_quotes,string). + +%% uri_to_csv(+URI:uri, -Rows:list(row)) is det. +% +% Read contents of CSV and return a list of terms with functor row/N, where +% N is the number of columns in the CSV. +uri_to_csv(URI,Rows) :- with_input_from_uri(URI,load_csv_from_stream(Rows)). + +load_csv_from_stream(Rows,Stream) :- + read_stream_to_codes(Stream,Codes), + insist(phrase(csv(Rows,[match_arity(false),convert(true)]),Codes), + csv_parse_failed). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dataset.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dataset.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,105 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dataset, + [ dataset/5 + , dataset_size/2 + , dataset_query/2 + , dataset_query_dv/3 + , dataset_item/2 + , dataset_items/2 + , dataset_query_id/3 + , random_subset/4 + ]). + +/** Definition and memoising of datasets */ + +:- use_module(library(memo)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(sandbox)). +:- use_module(library(typedef)). + +:- type natural == nonneg. +:- persistent_memo dataset(+class:ground,+dbv:ground,-id:ground,-size:natural, -items:list). +:- persistent_memo term_hash_id(+object:any, +hash:atom, -id:atom). +:- persistent_memo random_subset( +domain:nonneg, +size:nonneg, +index:nonneg, -set:list(nonneg)). + +random_subset(N,K,_,Indices) :- randset(K,N,Indices). + + +:- initialization memo_attach(memo(datasets),[]). + +:- meta_predicate dataset(1,+,-,-,-), dataset_query_id(1,+,-). + +sandbox:safe_meta(dataset(G,_,_,_,_),[G]). +sandbox:safe_meta(dataset_query_id(G,_,_),[G]). + +%% dataset( +Generator:pred(A), +DBVersion, -ID:atom, -Size:natural, -Items:list(A)) is det. +% +% Note: Generator must be ground. +dataset(Generator,_,ID,Size,Items) :- + setof(X, call(Generator,X), Items), + length(Items,Size), + variant_sha1(Items,Hash), + term_hash_id(Items,Hash,ID). + +term_hash_id(X,Hash,ID) :- + ( browse(term_hash_id(X,Hash,ID)) -> true % makes it safe to call in compute mode + ; (ID=Hash; between(1,100,I), variant_sha1(Hash-I,ID)), + \+browse(term_hash_id(_,_,ID)) + ; throw(unable_to_unique_id(X)) + ). + + + +%% dataset_query_id(+Query:class,+DBVersion:ground,-ID:ground) is det. +% Get ID for given query and database version. If this query has been +% requested before, the previously generated ID will be unified with ID. +% Otherwise, a new ID will be created and the list of items stored in +% the persistent Prolog database. An empty dataset results in an +% exception. +dataset_query_id(Q,V,ID) :- + dif(Status,fail), + memo(dataset(Q,V,ID,_,_),_-Status). + +%% dataset_size(-ID:ground,-Size:natural) is nondet. +%% dataset_size(+ID:ground,-Size:natural) is semidet. +% True when Size is the number of items in existing dataset with id ID. +dataset_size(ID,Size) :- distinct(current_dataset(ID,Size,_)). + +%% dataset_items(-ID,-Items:list) is nondet. +%% dataset_items(+ID,-Items:list) is semidet. +% True when Items is the list of items in existing dataset with id ID. +dataset_items(ID,Items) :- distinct(current_dataset(ID,_,Items)). + +%% dataset_item(-ID,-Item) is nondet. +%% dataset_item(+ID,-Item) is nondet. +% True when dataset ID contains Item. +dataset_item(ID,Item) :- dataset_items(ID,Items), member(Item,Items). + +%% dataset_query(-ID,-Query) is nondet. +%% dataset_query(+ID,-Query) is nondet. +% True when dataset ID contains Item. +dataset_query(ID,Q) :- browse(dataset(Q,_,ID,_,_)). + +%% dataset_query_dv(-ID,-Query,-DV) is nondet. +%% dataset_query_dv(+ID,-Query,-DV) is nondet. +% True when dataset ID contains Item. +dataset_query_dv(ID,Q,DV) :- browse(dataset(Q,DV,ID,_,_)). + +current_dataset(ID,Size,Items) :- browse(dataset(_,_,ID,Size,Items)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/decoration.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/decoration.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,110 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(decoration, []). +/** Hook for customised RDF links with extra HTML +*/ + + +:- use_module(cliopatria(hooks)). +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(semweb/rdfs)). +:- use_module(library(dcg_core)). +:- use_module(library(rdfutils)). +:- use_module(components(label)). +:- use_module(components(icons)). + + +:- multifile resource_decoration//2, resource_view//2. + +%% resource_decoration(URI)// is nondet. +% This DCG rule succeeds when the resource specified by URI should be +% preceeded by arbitrary HTML elements. It should produce a list of HTML +% tokens as produced by html//1. + +cliopatria:display_link(R,_) --> + { rdf_equal(R,rdf:nil) }, !, html(span(title('rdf:nil'),b('[]'))). + +cliopatria:display_link(R,Opts) --> + { rdf_has(R,rdf:first,_), !, + option(max_length(Max),Opts,5), + cp_label:resource_link(R,ListLink), + rdf_list_take(Max,R,Items,Tail), + rdf_list_length(Tail,Rem), + ( Rem=0 -> length(Items,ListLength) + ; ListLength is Max+Rem + ), + format(string(ListTitle), 'RDF collection with ~D members', ListLength) + }, + html([ a([href(ListLink),title(ListTitle)],b('[')) + , \seqmap_with_sep(comma, display_item(Opts), Items) + , \display_tail(Rem,Tail) + , a([href(ListLink),title(ListTitle)],b(']')) + ]). + +cliopatria:display_link(R,Opts) --> + { rdf(R,rdf:type,owl:'Restriction'), + rdf(R,owl:onProperty,Prop), + restriction_condition(R,Cond) + }, !, + html(span(title(R),['(', \html(Cond),')',&(nbsp),\rdf_link(Prop,Opts)])). + +restriction_condition(R,['=',Num]) :- rdf_number(R,owl:cardinality,Num), !. +restriction_condition(R,[&(ge),Num]) :- rdf_number(R,owl:minCardinality,Num), !. +restriction_condition(R,[&(le),Num]) :- rdf_number(R,owl:maxCardinality,Num), !. + +cliopatria:display_link(URI,Opts) --> + { atom(URI), \+rdf_graph(URI), !, + cp_label:resource_link(URI, Target), + (rdf(URI,_,_) -> Class=r_def; Class=r_undef), + Link = a( [class(Class), href(Target), title(URI)], + \(cp_label:resource_label(URI, Opts))) + }, + ( {option(decoration(true),Opts,true)}, + resource_decoration(URI,decoration:html(Link)) -> [] + ; html(Link) + ). + +decoration:resource_decoration(URI,Link) --> + { rdf_has(_,foaf:page,URI) + ; rdf_has(_,foaf:isPrimaryTopicOf,URI) + % ; rdfs_individual_of(URI,foaf:'Document') + }, !, + html_requires(font_awesome), + html( span( [ \Link, &(nbsp), a([href(URI),target('_blank')],\icon('external-link')) ])). + + +display_item(Opts,Item) --> rdf_link(Item,Opts). +display_tail(0,_) --> !. +display_tail(N,Tail) --> + { cp_label:resource_link(Tail,Link), + format(string(Title),'Remaining ~D items',[N]) + }, + html([' | ',a([href(Link),title(Title)],&(hellip))]). + +comma --> html(', '). + +cliopatria:list_resource(URI,Opts) --> + {debug(decoration,'Checking for views for ~q...',[URI])}, + {findall(Head-Tail,resource_view(URI,Opts,Head,Tail),Views), Views\=[]}, !, + {length(Views,N), debug(decoration,'Found ~d views.',[N])}, + seqmap(dlist,Views), + cpa_browse:list_resource(URI,[raw(true)|Opts]). + +dlist(Head-Tail,Head,Tail). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dictutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dictutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,37 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dictutils, + [ print_dict/1 + , print_dict/2 + , print_dict/3 + , tag/2 + ]). + +:- use_module(library(lambda)). + +print_dict(Dict) :- print_dict(Dict,[]). +print_dict(Dict,Opts) :- print_dict(current_output,Dict,Opts). +print_dict(Str,Dict,Opts) :- + option(exclude(Exc),Opts,\_^fail), + option(include(Inc),Opts,\_^true), + findall(F:V, (get_dict(F,Dict,V),call(Inc,F:V), \+call(Exc,F:V)), Pairs), + aggregate_all(max(FL),(member(F:_,Pairs),atom_length(F,FL)),Max), + forall( member(F:V,Pairs), format(Str,"~t~2+~t~w~*+: ~p\n",[F,Max,V])). + +tag(Tag,Dict) :- is_dict(Dict,Tag). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dlogic.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dlogic.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,61 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module( dlogic, [ ext/2, lambda/3, unary/2 ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdfs)). +:- use_module(library(sandbox)). +:- use_module(library(rdfutils)). + +% :- meta_predicate unary(:,-). +:- meta_predicate lambda(-,0,-). +:- rdf_meta ext(t,o). + +:- op(400,xfx,~). + +ext((C1,C2),X) :- !, ext(C1,X), ext(C2,X). +ext(C1;C2, X) :- !, ext(C1,X); ext(C2,X). +ext(inv(P) is Q, X) :- !, rdf_has(V,P,X), call(Q,V). +ext(P is Q, X) :- !, rdf_has(X,P,V), call(Q,V). +ext(q(P,Q), X) :- !, rdf(X,P,literal(Q,_)). +ext(NS:Class,X) :- !, rdf_global_id(NS:Class,C), rdfs_individual_of(X,C). +ext(Class,X) :- atomic(Class), rdfs_individual_of(X,Class). + +lambda(X,Goal,Y) :- + copy_term(X-Goal,Y-Goal1), + call(Goal1). + + +unary((Binary -> Unary), X) :- !, binary(Binary,X,Y), unary(Unary,Y). +unary(\Pred,X) :- !, call(Pred,X). +unary((U1,U2),X) :- !, unary(U1,X), unary(U2,X). +unary((U1;U2),X) :- !, unary(U1,X); unary(U2,X). +unary(a(Class),X) :- !, rdf_global_id(Class,C), rdfs_individual_of(X,C). +unary(P~Q,X) :- !, rdf(X,P,literal(Q,_)). + +binary(p(P),X,Y) :- !, rdf_global_id(P,P1), rdf(X,P1,Y). +binary(ip(P),X,Y) :- !, rdf_global_id(P,P1), rdf(Y,P1,X). +binary(P~Q,X,Y) :- !, rdf_global_id(P,P1), rdf(X,P1,literal(Q,Y)). +binary(\Pred,X,Y) :- !, call(Pred,X,Y). +binary(text,X,Y) :- !, literal_text(X,Y). +binary(num,X,Y) :- !, literal_number(X,Y). + + +sandbox:safe_meta(dlogic:lambda(_,Goal,_),[Goal]). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_c3.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_c3.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,152 @@ +:- module(dml_c3, + [ csv_op_chart/3 + , cla_op_chart/3 + , cla_label_lang/3 + , c3_bar/3, c3_bar/2 + , c3_plot/3 + , c3_steps/3 + , c3_csteps/3 + , c3_hist/5 + ]). + +:- use_module(library(computations)). +:- use_module(library(mlserver)). +:- use_rendering(c3). + +csv_op_chart(Op,Result,Chart) :- op_chart(Op,Result,Chart), !. +csv_op_chart(Op,X,unrecognised(Op,X)). + +op_chart(pitch_hist(_Weighting),Pairs,Ch) :- + unzip(Pairs,NoteNums,Counts), + maplist(computations:pitch_number_name,NoteNums,Pitches), + c3_bar(pitch-Pitches,counts-Counts,Ch1), + Ch=Ch1.put(axis/x/type,categorical). + +op_chart(freq_hist(Map,_),Counts,Ch) :- c3_hist(bars,pitch,Map,Counts,Ch). +op_chart(freq_hist_r(Map,_),Counts,Ch) :- c3_hist(bars,pitch,Map,Counts,Ch). +op_chart(tempo,Pairs,Ch) :- unzip(Pairs,T,X), c3_plot(time-T,tempo-X,Ch). +op_chart(uniform_tempo(_),T-X,Ch) :- c3_plot(time-T,tempo-X,Ch). +op_chart(uniform_tempo_r(_),T-X,Ch) :- c3_plot(time-T,tempo-X,Ch). +op_chart(uniform_tempo(_,_),T-X,Ch) :- c3_plot(time-T,tempo-X,Ch). +op_chart(uniform_tempo_r(_,_),T-X,Ch) :- c3_plot(time-T,tempo-X,Ch). +op_chart(tempo_hist_r(_DT,Map),_-Counts,Ch) :- c3_hist(steps,tempo,Map,Counts,Ch). +op_chart(tempo_hist(_DT,Map),_-Counts,Ch) :- c3_hist(steps,tempo,Map,Counts,Ch). +op_chart(normalised_tempo(N),_T-X,Ch) :- tempo_curve(N,X,Ch). +op_chart(normalised_tempo_r(N),_T-X,Ch) :- tempo_curve(N,X,Ch). + +cla_op_chart(Op,X,Chart) :- cla_chart(Op,X,Chart), !. +cla_op_chart(Op,X,unrecognised(Op,X)). + +cla_chart(Op,X,Chart) :- + is_dict(X), _{result:R} :< X, !, + cla_chart(Op,R,Chart). + +cla_chart(collection_pitch_histogram(_),X,Chart) :- + c3_bar(notenum-X.values,counts-X.counts,Chart). + +cla_chart(collection_freq_histogram(Min,Max,Quant,_),X,Chart) :- % matlab + c3_hist(bars,pitch,binmap(Min,Max,(Max-Min)*Quant+1),X.counts,Chart). + +cla_chart(collection_freq_histogram(_Lang,Min,Max,Quant,_),X,Chart) :- + c3_hist(bars,pitch,binmap(Min,Max,(Max-Min)*Quant+1),X.counts,Chart). + +cla_chart(collection_tempo_histogram(_,Min,Max,N),X,Chart) :- % matlab + c3_hist(steps,tempo,expmap(Min,Max,N),X.counts,Chart). + +cla_chart(collection_tempo_histogram(_Lang,_,Min,Max,N),X,Chart) :- + c3_hist(steps,tempo,expmap(Min,Max,N),X.counts,Chart). + +cla_chart(collection_tempo_curve(N),X,Chart) :- % matlab + tempo_curve(N,X.means,Chart). + +cla_chart(collection_tempo_curve(_Lang,N),X,Chart) :- + tempo_curve(N,X.means,Chart). + +cla_chart(py_hist(tagged(tonic), key_tonic_hist:aggregate, []),X,Chart) :- + c3_bar(key-X.values,counts-X.counts,Chart1), + Chart=Chart1.put(axis/x/type,categorical). + +cla_chart(py_hist(tagged(transcription), semitone_hist:aggregate, []),X,Chart) :- + c3_bar('pitch class'-X.values,counts-X.counts,Chart1), + Chart=Chart1.put(axis/x/type,categorical). + +cla_chart(tuning_stats, X, Chart) :- + Hist=X.stats.hist, + c3_hist(steps,frequency,edgemap(Hist.edges),Hist.counts,Chart). + +cla_chart(py_cla(tagged(transcription(1)), tuning_stats:per_file, []),X, Chart) :- + cla_chart(tuning_stats, X, Chart). + + +tempo_curve(N,X,Chart) :- + numlist(1,N,T), + c3_csteps(time-T,tempo-X,Chart). + +c3_hist(bars,XLabel,Map,Counts,Chart) :- + array_list(centres(Map),Centres1), + maplist(fix(2),Centres1,Centres), + c3_bar(XLabel-Centres,counts-Counts,Chart). + +c3_hist(steps,XLabel,Map,Counts,Chart) :- + array_list(edges(Map),Edges1), + maplist(fix(2),Edges1,Edges), + append(Counts,[0],C), + c3_steps(XLabel-Edges,counts-C,Chart). + + +fix(N,X,Y) :- Q is 10^N, Y is round(X*Q)/Q. + +:- public c3:put//2 + , c3:axis//2 + , c3:bar//2 + , c3:area//2 + , c3:zoom//1 + , c3:legend//1 + , c3:subchart//1 + , c3:put//2 + , c3:scat//2 + . + +c3:put(Path,Val,D1,D1.put(Path,Val)). +c3:axis(Name,Label,D1,D2) :- axis_pos(Name,Pos), D2=D1.put(axis/Name/label,_{text:Label,position:Pos}). +c3:axes(Lab1,Lab2) --> c3:axis(x,Lab1), c3:axis(y,Lab2). +c3:legend(F) --> c3:put(legend/show,F). +c3:subchart(F) --> c3:put(subchart/show,F). +c3:zoom(F) --> c3:put(zoom/enabled,F). + +c3:scat(XLabel,YLabel) --> c3:init(scatter,XLabel,YLabel). +c3:bar(XLabel,YLabel) --> c3:init(bar,XLabel,YLabel). +c3:area(XLabel,YLabel) --> c3:init(area,XLabel,YLabel). + +c3:init(Type,XLabel,YLabel) --> + c3:axes(XLabel,YLabel), + c3:put(data,_{columns:[],type:Type}), + c3:put(axis/x/tick/fit,false). + +axis_pos(x,'outer-center'). +axis_pos(y,'outer-middle'). + +c3_plot(XL-XV,YL-YV, c3{data:_{x:XL,columns:[[XL|XV],[YL|YV]]}}.axes(XL,YL).legend(false)). +c3_steps(XL-XV,YL-YV, c3{ line:_{step:_{type:'step-after'}}, + data:_{type:'area-step',x:XL, columns:[[XL|XV],[YL|YV]]} + }.axes(XL,YL).legend(false)). +c3_csteps(XL-XV,YL-YV, c3{data:_{type:step,x:XL,columns:[[XL|XV],[YL|YV]]}}.axes(XL,YL).legend(false)). +c3_bar(Label-Vals,c3{data:_{type:bar, columns:[[Label|Vals]]}}.axis(y,Label)). +c3_bar(XL-XV,YL-YV,c3{data:_{type:bar, x:XL, columns:[[XL|XV],[YL|YV]]}}.axes(XL,YL).legend(false)). + + +cla_label_lang(collection_pitch_histogram(_),pitch_histogram,pl). +cla_label_lang(collection_freq_histogram(_,_,_,_),freq_histogram,ml). +cla_label_lang(collection_freq_histogram(Lang,_,_,_,_),freq_histogram,Lang). +cla_label_lang(collection_tempo_histogram(_,_,_,_),tempo_histogram,ml). % matlab +cla_label_lang(collection_tempo_histogram(Lang,_,_,_,_),tempo_histogram,Lang). +cla_label_lang(collection_tempo_curve(_),tempo_curve,ml). % matlab +cla_label_lang(collection_tempo_curve(Lang,_),tempo_curve,Lang). +cla_label_lang(py_hist(tagged(tonic), key_tonic_hist:aggregate, []),tonic_histogram,py). +cla_label_lang(py_hist(tagged(transcription), semitone_hist:aggregate, _),pc_histogram,py). +cla_label_lang(tuning_stats, tuning_stats, py). +cla_label_lang(py_cla(tagged(transcription(1)), tuning_stats:per_file, _),tuning_stats, py). +cla_label_lang(py_cla(keys_chords,chord_seq_key_relative:aggregate,_),key_relative_chord_seq,py). +cla_label_lang(py_cla(similarity_bundle,similarity:per_file,_), similarity, py). + + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_crawler.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_crawler.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,445 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_crawler, []). + +:- use_module(library(http/html_write)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdfs)). +:- use_module(library(semweb/rdf_label)). +:- use_module(library(sparkle)). +:- use_module(library(crawler)). +:- use_module(library(musicbrainz)). +:- use_module(library(memo)). +:- use_module(applications(browse)). +:- use_module(api(lod_crawler)). +:- use_module(cliopatria(hooks)). + +:- sparql_endpoint(mb, 'http://dbtune.org/musicbrainz/sparql'). +:- sparql_endpoint(lb, 'http://linkedbrainz.org/sparql/'). +:- sparql_endpoint(dbp, 'http://dbpedia.org/sparql/'). +:- sparql_endpoint(self, 'http://localhost:3020/sparql/'). + +% :- sparql_endpoint(bbc, 'http://dbtune.org/bbc/programmes/sparql/'). +% :- sparql_endpoint(peel,'http://dbtune.org/bbc/peel/sparql/'), +% :- sparql_endpoint(classical,'http://dbtune.org/classical/sparql/'), +% :- sparql_endpoint(jamendo,'http://dbtune.org/jamendo/sparql/'), +% :- sparql_endpoint(magnatune,'http://dbtune.org/magnatune/sparql/'), +% :- sparql_endpoint(henry,'http://dbtune.org/henry/sparql/'), + + +crawler:source(dbp, dml_crawler:sparql_crawler(dbp), []). +crawler:source(lbz, dml_crawler:sparql_crawler(lb), []). +crawler:source(mbz, dml_crawler:mbz_crawler, []). +crawler:source(lod, dml_crawler:lod_crawler, []). + +crawler:authority( begins('http://dbpedia.org'), dbp, [auto(true)]). +crawler:authority( begins('http://musicbrainz.org'), lbz, [auto(true)]). +crawler:authority( begins('http://musicbrainz.org'), mbz, [auto(true)]). +crawler:authority( begins('http://id.loc.gov/vocabulary'), lod, [auto(true)]). +crawler:authority( begins('http://yago-knowledge.org'), lod, [auto(true)]). +crawler:authority( ( (begins('http://'); begins('https://')), + \+begins('http://dbpedia.org/'), + \+begins('http://musicbrainz.org/'), + \+begins('http://dml.org/'), + \+begins('http://sounds.bl.uk/') + ), lod, [auto(false)]). + +:- volatile_memo instrument(+label:atom,-uri:atom). + +instrument(Label,Instr) :- + rdf(Instr,skos:prefLabel,literal(exact(Label),_)). + +:- rdf_meta censor(+,t). +censor(lb, rdf(_,'http://purl.org/muto/core#taggedResource',_)). +censor(lb, rdf(_,mo:musicbrainz_guid,_)). +censor(lb, rdf(_,foaf:made,_)). + +% not needed after all: it was me giving the recordings type 'Signal', not lb. +% sparql_crawler:modify(lb,Tin,Tout) :- +% debug(sparql_crawler,"checking ~q",[Tin]), +% once(relink_brainz(Tin,Tout)). + +% :- rdf_meta relink_brainz(t,t). +% relink_brainz(rdf(MBZRecording,rdf:type,mo:'Track'),rdf(MBZRecording,rdf:type,mo:'Signal')):- +% mb_id_uri(recording,_,MBZRecording). + +% connects patched ClioPatria resource viewer to sparql_crawler module +cliopatria:resource_crawler(URI,NT) --> html(div(class(crawler),\crawl_ui(URI,NT))). + +% --------- SPARQL crawler using sparkle --------------- + +sparql_crawler(dbp,name('DBPedia')). +sparql_crawler(lb,name('LinkedBrainz')). + +sparql_crawler(EP,uri_graph(_,Graph)) :- + current_sparql_endpoint(EP,Host,Port,Path,_), + parse_url(Graph,[protocol(http),host(Host),port(Port),path(Path)]). + +sparql_crawler(EP,describe(URI,Triple)) :- + describe(EP,URI,Triple), + \+censor(EP,Triple). + + +describe(EP,URI,rdf(Subj,Pred,URI)) :- EP ?? rdf(Subj,Pred,URI). +describe(EP,URI,rdf(URI,Pred,Obj)) :- EP ?? rdf(URI,Pred,Obj). +% !!! FIXME This was to slow for URIs with many linked resources +% Need to get asynchronous crawling working first.. +% describe(EP,URI,rdf(Subj,Pred,Obj)) :- +% (EP ?? rdf(URI,P1,O1)), +% ( Subj=URI, Pred=P1, Obj=O1 +% ; Subj=O1, Pred=P2, Obj=O2, +% O1\=literal(_), +% (EP ?? rdf(O1,P2,O2)) +% ). + +% ----------- LOD crawler --------------------------- +lod_crawler(name('LOD Cloud')). +lod_crawler(uri_graph(URI,Graph)) :- + uri_components(URI, uri_components(Sch,Auth,_,_,_)), + uri_components(Graph, uri_components(Sch,Auth,_,_,_)). + +lod_crawler(crawl(URI,Graph)) :- + lod_uri_graph(URI,URL), + rdf_load(URL,[graph(Graph)]). + +% ----------- MusicBrainz crawler ------------------- +mbz_crawler(uri_graph(_,'http://musicbrainz.org/ws/2')). +mbz_crawler(name('MusicBrainz')). +mbz_crawler(describe(URI,Triple)) :- + debug(crawler,'Doing ~q.',[mbz_crawler(describe(URI,Triple))]), + ( mb_id_uri(Type,_,URI) -> Context=Type + ; event_uri(URI,EvType,BaseURI,Extra), + mb_id_uri(BaseType,_,BaseURI) + -> Context=event(BaseType,BaseURI,EvType,Extra) + ; debug(crawler,'Unrecognised URI: ~w',[URI]), + fail + ), + mbz_triple(Context,URI,Triple1), + rdf_global_term(Triple1,Triple). + + +mbz_triple(artist,URI,rdf(URI,rdf:type,mo:'MusicArtist')). +mbz_triple(artist,URI,Triple) :- + mb_lookup(URI,[inc([aliases]), rels([recording,work,artist])],Artist), + subject_triple(Artist-URI,artist,Triple). + +mbz_triple(recording,URI,rdf(URI,rdf:type,mo:'Signal')). +mbz_triple(recording,URI,rdf(Event,rdf:type,mo:'Recording')) :- + event_uri(Event,production,URI). + +mbz_triple(recording,URI,Triple) :- + mb_lookup(URI,[inc([artists,'artist-credits']),rels([artist,work])],Recording), + event_uri(Event,production,URI), + subject_triple(Recording-URI, recording(Event), Triple). + +mbz_triple(work,URI,rdf(URI,rdf:type,mo:'MusicalWork')). +mbz_triple(work,URI,Triple) :- + mb_lookup(URI,[inc([aliases]),rels([recording,artist,work])],Work), + subject_triple(Work-URI, work, Triple). + +mbz_triple(event(work,_,composition,''),Event,rdf(Event,rdf:type:mo:'Composition')). +mbz_triple(event(work,W,composition,''),Event,Triple) :- + mb_lookup(W,[rels([artist,work])],Work), % need work rels here? + event_uri(Event,composition,WorkURI), + subject_triple(Work-WorkURI, work, Triple). + +mbz_triple(event(recording,Signal,production,''),Event,Triple) :- + production_triple(Signal,Event,Triple). + +production_triple(_, Ev, rdf(Ev,rdf:type,mo:'Performance')). +production_triple(_, Ev, rdf(Ev,rdf:type,mo:'Recording')). +production_triple(S, Ev, rdf(Ev,mo:produced_signal,S)). +production_triple(S, Ev, T) :- + mb_lookup(S,[inc([artists,'artist-credits']),rels([work,artist])],Recording), + mb_uri(Recording,Signal), + subject_triple(Recording-Signal,recording(Ev),T). + +%% subject_triple( +Subj:pair(element,resource), +Content:ground, -T:triple) is nondet. +% Produce triples relating to this subject without doing any more musicbrainz queries. + +% first deal with the non-relation facets +subject_triple(E-URI, Context, T) :- + dif(Facet,relation(_,_)), + mb_facet(E,Facet), + facet_triple(URI, Context, Facet, T). + +% then deal with relations +subject_triple(E1-URI1, _Context, T) :- + mb_relation(E1, E2, Name, Dir, Opts), + mb_uri(E2,URI2), + ( mb_class(E2,C2), + subject_triple(E2-URI2, C2, T) % do all facets of related object + ; normalise_direction(Dir,URI1,URI2,URI_A,URI_B), + relation_triple(Name,URI_A,URI_B,Opts,T) + ). + +normalise_direction(fwd,E1,E2,E1,E2). +normalise_direction(bwd,E1,E2,E2,E1). + + +facet_triple(_, _, credit(A), T) :- mb_uri(A,Agent), subject_triple(A-Agent,artist,T). +facet_triple(URI, _, title(T), rdf(URI,dc:title,literal(T))). +facet_triple(URI, artist, name(N), rdf(URI,foaf:name,literal(N))). +facet_triple(URI, artist, alias(A), rdf(URI,dml:alias,literal(A))). +facet_triple(URI, artist, gender(G), rdf(URI,foaf:gender,literal(GG))) :- downcase_atom(G,GG). +facet_triple(URI, artist, type(Type), rdf(URI,rdf:type,foaf:Type)) :- member(Type,['Person','Group']). +facet_triple(URI, artist, born(X), T) :- life_event_triple(URI,birth,time(X),T). +facet_triple(URI, artist, died(X), T) :- life_event_triple(URI,death,time(X),T). +facet_triple(URI, artist, birth_place(X), T) :- life_event_triple(URI,birth,area(X),T). +facet_triple(URI, artist, death_place(X), T) :- life_event_triple(URI,death,area(X),T). + +facet_triple(_, recording(E), credit(A), rdf(E,event:agent,Agent)) :- mb_uri(A,Agent). +facet_triple(URI, recording(_), length(L), rdf(URI,mo:duration,literal(type(xsd:float,LenA)))) :- + atom_number(LenA,L). + +life_event_triple(Agent,Type,Property,T) :- + event_uri(Event,Type,Agent), + ( T=rdf(Event,rdf:type,event:'Event') + ; T=rdf(Event,event:agent,Agent) + ; life_event_property_triple(Event,Property,T) + ). + + +life_event_property_triple(Event,area(A),rdf(Event,event:place,URI)) :- mb_uri(A,URI). +life_event_property_triple(Event,time(T),Triple) :- + prefix_uri('/time',Event,Time), + ( Triple=rdf(Event,event:time,Time) + ; time_instant_triple(Time-T,Triple) + ). + +% ----------------------------------------------------------------------------- +% relation_triple + +relation_triple(parts, Whole, Part, _, rdf(Part,dml:part_of,Whole)). +relation_triple(composer, Agent, Work, _, rdf(Work,dml:composer,Agent)). +relation_triple('is person', Agent, Person, _, rdf(Agent,dml:persona_of,Person)). +relation_triple('performing orchestra', _, Group, _, rdf(Group,rdf:type,mo:'Orchestra')). +relation_triple(Name, _, Group, _, rdf(Group,rdf:type,mo:'MusicGroup')) :- membership_role(Name). +relation_triple(Name, Agent, Group, _, rdf(Group,mo:member,Agent)) :- membership_role(Name). + +relation_triple(Role, Agent, _, _, rdf(Agent,rdf:type,mo:'MusicArtist')) :- + musical_role(Role). +relation_triple(Name, R1, R2, Opts, T) :- + relation_event(Name, R1, R2, Opts, Event, Relation), + relation_event_triple(Relation, Event, T). + +relation_event( based_on, Orig, Deriv, _, Ev, based_on(Orig)) :- event_uri(Ev,composition,Deriv). +relation_event( composer, A, W, O, Ev, composition(composer,A,W,O)) :- event_uri(Ev,composition,W). +relation_event( lyricist, A, W, _, Ev, composition(lyricist,A,W,[])) :- event_uri(Ev,composition,W). +relation_event( writer, A, W, _, Ev, composition(writer,A,W,[])) :- event_uri(Ev,composition,W). +relation_event( arrangement, W1, W2, O, Ev, arrangement(W1,W2,O)) :- event_uri(Ev,arrangement,W2). +relation_event( performance, Sig, W, O, Ev, performance(W,O)) :- event_uri(Ev,production,Sig). +relation_event( performance, Sig, _, _, Ev, recording(Sig)) :- event_uri(Ev,production,Sig). +relation_event( performer, _, Sig, _, Ev, recording(Sig)) :- event_uri(Ev,production,Sig). +relation_event( 'performing orchestra', _, Sig, _, Ev, recording(Sig)) :- event_uri(Ev,production,Sig). +relation_event( vocal, Ag, Sig, O, Ev, ED) :- relation_event( instrument, Ag, Sig, [attribute(voice)|O], Ev, ED). +relation_event( 'instrument arranger', Ag, Sig, O, Ev, ED) :- relation_event(instrument,Ag,Sig,O,Ev,ED). +relation_event( 'instrument arranger', Ag, Sig, O, Ev, ED) :- relation_event(arranger,Ag,Sig,O,Ev,ED). +relation_event( instrument, _, Sig, _, Ev, recording(Sig)) :- event_uri(Ev,production,Sig). +relation_event( instrument, Ag, Sig, O, Ev, instrument(Prod,Ag,O)) :- + mb_id_uri(_,PerformerID,Ag), + event_uri(Prod,production,Sig), + event_uri(Ev,performance,Sig,PerformerID). +relation_event( Name, Agent, Sig, _, Ev, role(Pred,Agent)) :- + production_role(Name,Pred), + mb_id_uri(recording,_,Sig), + event_uri(Ev,production,Sig). + +relation_event( Name, Agent, Group, Opts, Ev, membership(Agent,Group,[role(Role)|Opts])) :- + membership_role(Name,Role), + mb_id_uri(_,AID,Agent), + term_hash(t(AID,Role,Opts),Hash), + number_string(Hash,HashString), + event_uri(Ev,membership,Group,HashString). + +production_role(producer,mo:producer). +production_role(arranger,mo:arranger). +production_role(conductor,mo:conductor). +production_role(performer,mo:performer). +production_role('performing orchestra',mo:performer). +production_role(vocal,mo:performer). + +membership_role(Name) :- membership_role(Name,_). +membership_role('member of band',member). +membership_role('conductor position',conductor). +membership_role('vocal supporting musician',vocal_support). + +musical_role(composer). +musical_role(arranger). +musical_role(lyricist). +musical_role(instrument). +musical_role(performer). +musical_role('performing orchestra'). +musical_role('vocal supporting musician'). +musical_role(Name) :- membership_role(Name). + +relation_event_triple( based_on(_), Ev, rdf(Ev,rdf:type,mo:'Composition')). +relation_event_triple( based_on(Orig), Ev, rdf(Ev,event:factor,Orig)). + +relation_event_triple( membership(_,_,_), Ev, rdf(Ev,rdf:type,mo:'Membership')). +relation_event_triple( membership(A,_,_), Ev, rdf(Ev,mo:artist,A)). +relation_event_triple( membership(_,G,_), Ev, rdf(Ev,mo:group,G)). +relation_event_triple( membership(_,_,O), Ev, T) :- membership_triple(Ev,O,T). +relation_event_triple( membership(_,_,O), Ev, T) :- event_time_triple(Ev,O,T). + +relation_event_triple( composition(_,_,_,_), Ev, rdf(Ev,rdf:type,mo:'Composition')). +relation_event_triple( composition(_,_,W,_), Ev, rdf(Ev,mo:produced_work,W)). +relation_event_triple( composition(R,A,_,_), Ev, rdf(Ev,mo:R,A)). +relation_event_triple( composition(_,_,_,O), Ev, T) :- event_time_triple(Ev,O,T). + +relation_event_triple( arrangement(_,_,_), Ev, rdf(Ev,rdf:type,mo:'Arrangement')). +relation_event_triple( arrangement(W,_,_), Ev, rdf(Ev,mo:arrangement_of,W)). +relation_event_triple( arrangement(_,W,_), Ev, rdf(Ev,mo:produced_work,W)). +relation_event_triple( arrangement(_,_,O), Ev, T) :- event_time_triple(Ev,O,T). + +relation_event_triple( performance(_,_), Ev, rdf(Ev,rdf:type,mo:'Performance')). +relation_event_triple( performance(_,O), Ev, T) :- event_time_triple(Ev,O,T). +relation_event_triple( performance(W,O), Ev, rdf(Ev,Pred,W)) :- + ( member(attribute(partial),O) + -> Pred=mo:partial_performance_of + ; Pred=mo:performance_of + ). + +relation_event_triple( recording(_), Ev, rdf(Ev,rdf:type,mo:'Recording')). +relation_event_triple( recording(S), Ev, rdf(Ev,mo:produced_signal,S)). + +relation_event_triple( instrument(_,_,_), Ev, rdf(Ev,rdf:type,mo:'Performance')). +relation_event_triple( instrument(_,A,_), Ev, rdf(Ev,mo:performer,A)). +relation_event_triple( instrument(P,_,_), Ev, rdf(P,event:sub_event,Ev)). +relation_event_triple( instrument(_,_,O), Ev, T) :- event_time_triple(Ev,O,T). +% relation_event_triple( instrument(_,_,O), Ev, rdf(Ev,mo:instrument,literal(Instr))) :- +% member(attribute(Instr),O). +relation_event_triple( instrument(_,_,O), Ev, rdf(Ev,mo:instrument,Instr)) :- + member(attribute(Label),O), + ( instrument(Label,Instr) -> true + ; Instr=literal(Label) + ). + +membership_triple(E, O, rdf(E,dml:role,literal(R))) :- member(role(R),O), R\=member. +membership_triple(E, O, rdf(E,dml:modifier,literal(A))) :- member(attribute(A),O). + +event_time_triple(Event,Opts,T) :- + (memberchk(begin(_),Opts); memberchk(end(_),Opts); memberchk(in(_),Opts)), + prefix_uri('/time',Event,Time), + ( T=rdf(Event,event:time,Time) + ; ( member(in(DT),Opts) + -> time_instant_triple(Time-DT,T) + ; ( member(begin(DT),Opts), prefix_uri('/begin',Time,Pt), Pred=time:hasBeginning + ; member(end(DT),Opts), prefix_uri('/end',Time,Pt), Pred=time:hasEnd + ), + time_interval_triple(Time,Pred,Pt-DT,T) + ) + ). + +time_instant_triple(Time-_, rdf(Time,rdf:type,time:'Instant')). +time_instant_triple(Time-DT, rdf(Time,time:inXSDDateTime,literal(type(xsd:dateTime,DT)))). + +time_interval_triple(T, _, _, rdf(T,rdf:type, time:'Interval')). +time_interval_triple(T, Pred, Pt-_, rdf(T,Pred,Pt)). +time_interval_triple(_, _, PtDT, T) :- time_instant_triple(PtDT,T). + + +%% event_uri(-EventURI,+Type,+BaseURI) is det. +%% event_uri(-EventURI,+Type,+BaseURI) is det. +event_uri(EventURI,Type,BaseURI) :- event_uri(EventURI,Type,BaseURI,''). + +%% event_uri(+EventURI,-Type,-BaseURI,-Extra) is det. +%% event_uri(-EventURI,+Type,+BaseURI,+Extra) is det. +event_uri(EventURI,Type,BaseURI,Extra) :- + ( var(EventURI) + -> uri_components(BaseURI,uri_components(Sc,Ho,Pa,Extra,'_')), + uri_components(EventURI,uri_components(Sc,Ho,Pa,Extra,Type)), Type\='_' + ; uri_components(EventURI,uri_components(Sc,Ho,Pa,Extra,Type)), Type\='_', + uri_components(BaseURI,uri_components(Sc,Ho,Pa,Extra,'_')) + ). + +% prefix_uri(_,_,N) :- rdf_bnode(N), !. +prefix_uri(Prefix,URI,PURI) :- + uri_components(URI,uri_components(Sc,Ho,Pa,Extra,Type)), atom_concat(Prefix,Pa,TPa), + uri_components(PURI,uri_components(Sc,Ho,TPa,Extra,Type)). + +% -------------- display hooks --------------- +:- rdf_meta label(r,r,-). +label(time:'Instant',URI, Label) :- + ( rdf_has(URI,time:inXSDDateTime,literal(type(xsd:dateTime,DT))) + -> format(string(Label),'~w',[DT]) + ; Label='' + ). + +label(time:'Interval',URI, Label) :- + (rdf_has(URI,time:hasBeginning,Begin) -> rdf_display_label(Begin,L1); L1=''), + (rdf_has(URI,time:hasEnd,End) -> rdf_display_label(End,L2); L2=''), + ( L1=L2 + -> format(string(Label),'~s',[L1]) + ; format(string(Label),'~s to ~s',[L1,L2]) + ). + +label(mo:'Recording',Ev, Label) :- + rdf_has(Ev,mo:produced_signal,Sig), !, + rdf_display_label(Sig,Title), + ( rdf_has(Ev,event:agent,Agent) + -> rdf_display_label(Agent,Name), + format(string(Label),'Recording of ~w by ~w',[Title,Name]) + ; format(string(Label),'Recording of ~w',[Title]) + ). + +label(mo:'Membership',Ev, Label) :- + rdf_has(Ev,mo:artist,A), + rdf_has(Ev,mo:group,G), !, + rdf_display_label(A,AL), + rdf_display_label(G,GL), + format(string(Label),'Membership of ~w in ~w',[AL,GL]). + +label(mo:'Performance',Ev, Label) :- + ( rdf_has(Ev,mo:produced_signal,Sig) + ; rdf_has(SEv,event:sub_event,Ev), + rdf_has(SEv,mo:produced_signal,Sig) + ), !, + rdf_display_label(Sig,Title), + rdf_has(Ev,mo:performer,Performer), rdf_display_label(Performer,Name), + rdf_has(Ev,mo:instrument,Instr), rdf_display_label(Instr,IName), + format(string(Label),'~w playing ~w on ~w',[Name,IName,Title]). + + +label(mo:'Composition',E,Label) :- + rdf_has(E,mo:produced_work,Work), + rdfs_individual_of(Work,mo:'MusicalWork'), !, + rdf_display_label(Work,Title), + format(string(Label),'Composition of ~w',[Title]). + +rdf_label:display_label_hook(URI, _, Label) :- + rdf(URI,rdf:type,Class), + label(Class,URI,Label). + +rdf_label:display_label_hook(URI, _, Label) :- + atom(URI), + sub_atom(URI,0,_,_,'http://musicbrainz.org'), + event_uri(URI,EvType,Base), + event_label(EvType,URI,Base,Label). + +event_label(birth,_,Person,Label) :- + rdfs_individual_of(Person,foaf:'Person'), !, + rdf_display_label(Person,Name), + format(string(Label),'Birth of ~w',[Name]). +event_label(death,_,Person,Label) :- + rdfs_individual_of(Person,foaf:'Person'), !, + rdf_display_label(Person,Name), + format(string(Label),'Death of ~w',[Name]). + + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_data.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_data.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,92 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_data, + [ p2r_import/1 + , humdrum_import/1 + , load_everything/0 + , hum_uri_path/2 + , not_functional/3 + , rdf_pair/4 + ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_zlib_plugin)). +:- use_module(library(mo_schema)). +:- use_module(library(dbpedia)). +:- use_module(library(humdrum_p2r)). +:- use_module(library(beets_p2r)). +:- use_module(library(memo_p2r)). +:- use_module(library(bl_p2r)). +:- use_module(library(ilm_p2r)). +:- use_module(library(charm_p2r)). +:- use_module(library(mazurka_p2r)). +:- use_module(library(vamp)). +:- use_module(library(termutils)). +:- use_module(library(p2r)). +:- use_module(entailment(p2r)). + + +load_everything :- + maplist(p2r_import,[humdrum_p2r,memo_p2r,beets_p2r,bl_p2r,charm_p2r,vamp]). + +:- meta_predicate not_functional(2,-,-). + +not_functional(G,X,Ys) :- + writeln('Compiling...'), + setof(X-Y,call(G,X,Y),Pairs), + writeln('Grouping...'), + group_pairs_by_key(Pairs,Grouped), + writeln('Checking...'), + Ys=[_,_|_], member(X-Ys,Grouped). + +:- rdf_meta rdf_pair(r,r,o,o). +rdf_pair(P1,P2,X1,X2) :- + rdf(Y,P1,X1), + rdf(Y,P2,X2). + +:- rdf_meta assert_subproperty(r,r). + +%% assert_subproperty(P1,P2) is det. +% Asserts that P1 is a sub-property of P2. +assert_subproperty(P1,P2) :- rdf_assert(P1,rdfs:subPropertyOf,P2). + +rdf_assertions :- + rdf_assert(event:sub_event,rdf:type,owl:'TransitiveProperty'), + assert_subproperty(charm:composer,dml:composer), + assert_subproperty(hum:'refcode/COM',dml:composer), + assert_subproperty(charm:title,dml:title), + assert_subproperty(charm:performer,dml:performer), + assert_subproperty(marcrel:cmp,dml:composer), + assert_subproperty(marcrel:prf,dml:performer), + assert_subproperty(beets:title,dml:title), + assert_subproperty(beets:composer,dml:composer), + assert_subproperty(dc:title,dml:title). + +rdf_loads :- + rdf_load(rdf('silvet.n3')), +% rdf_load('http://id.loc.gov/vocabulary/relators'), +% rdf_load(['http://id.loc.gov/vocabulary/countries.rdf','http://id.loc.gov/vocabulary/languages.rdf'], [register_namespaces(true)]). + rdf_load('http://purl.org/ontology/vamp/',[register_namespaces(true)]), + rdf_load('http://vamp-plugins.org/rdf/plugins/qm-vamp-plugins'), + rdf_load('http://vamp-plugins.org/rdf/plugins/nnls-chroma'), + rdf_load('http://vamp-plugins.org/rdf/plugins/beatroot-vamp'). + +:- initialization rdf_assertions. +%:- initialization rdf_loads. + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_misc.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_misc.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,73 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_misc, [ periodically/2, current_periodical/3, remove_periodical/1 ]). +/** Miscellaneous hooks and initialisations + + This module implements some hooks for managing the context graphs + which appear at the bottom of individual resource pages. + + It also loads some miscellanous RDF graphs. + +*/ +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdfs)). +:- use_module(library(memo)). +:- use_module(cliopatria(hooks)). + +:- rdf_meta context_graph_class(r). + +:- meta_predicate periodically(+,0). +:- meta_predicate current_periodical(-,0,-). + +cliopatria:context_graph(URI, Triples, _) :- + context_graphable(URI), !, + maplist(rdf_global_id,[rdf:type, prov:wasDerivedFrom],Excludes), + findall(T, context_triple(Excludes,URI,[],T), T1), + sort(T1,Triples). + +context_triple(Excludes,URI,Visited,T) :- + edge(URI,Pred,URI1,Triple), + \+member(Pred,Excludes), + ( T=Triple + ; \+member(URI1,Visited), + %context_graphable(URI1), % this follows a lot of link + rdfs_individual_of(URI1,event:'Event'), + context_triple(Excludes,URI1,[URI|Visited],T) + ). + +edge(URI,Pred,URI1,rdf(URI,Pred,URI1)) :- rdf(URI,Pred,URI1), URI1\=literal(_). +edge(URI,Pred,URI1,rdf(URI1,Pred,URI)) :- rdf(URI1,Pred,URI). + +context_graphable(URI) :- + context_graph_class(Class), + rdfs_individual_of(URI,Class). + +context_graph_class(event:'Event'). +context_graph_class(mo:'Signal'). +context_graph_class(mo:'MusicalWork'). +context_graph_class(mo:'MusicGroup'). + +current_periodical(Interval,Goal,Id) :- current_alarm(_,periodically(Interval,Goal),Id,_). +remove_periodical(Id) :- remove_alarm(Id). + +periodically(Interval,Goal) :- + memo:reify(Goal,Status), + (Status=ok -> true; debug(cron,'Periodic goal ~q failed with ~q',[Goal,Status])), + alarm(Interval,periodically(Interval,Goal),_,[remove(true)]). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_musicbrainz.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_musicbrainz.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,23 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_musicbrainz, [ dump_facets/1]). +:- reexport(library(musicbrainz)). + +dump_facets(E) :- + forall(mb_facet(E,F), (tab(3),print(F),nl)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_spotify.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_spotify.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,30 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_spotify, []). + +:- reexport(library(spotify/spotify)). +:- reexport(library(spotify/spotools)). + +:- spotify_app( digifest, + [ id("fb7509e0220c4c02ba81801bb232f9c7") + , secret("a2704c4dd0f54acd8fa42f399e388d49") + , redirect("http://localhost:8888/callback") + , scope('user-read-private playlist-read-private playlist-modify-public') + ]). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dml_swish.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dml_swish.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,47 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dml_swish, []). + +:- use_module(library(sandbox)). +:- use_module(library(humdrum)). + +:- use_module(swish:library(http/html_write)). +:- use_module(swish:library(pengines)). +:- use_module(swish:library(memo)). +:- use_module(swish:library(rdfutils)). +:- use_module(swish:library(dataset)). +:- use_module(swish:library(dlogic)). +:- use_module(swish:library(pengutils)). + +user:file_search_path(example,dml(examples)). + +sandbox:safe_meta(settings:setting(_,_),[]). +sandbox:safe_primitive(error:has_type(_,_)). +sandbox:safe_primitive(rdf_label:literal_text(_,_)). +sandbox:safe_primitive(humdrum:hum_read(_,_,_)). % could check path here.. +sandbox:safe_primitive(musicbrainz:mb_query(_,_,_,_)). +sandbox:safe_primitive(humdrum_p2r:hum_uri_path(_,_)). + +sandbox:safe_meta('$dicts':eval_dict_function(Func,_,Dict,Out),Goals) :- !, + ( safe_func(Func), Goals=[] + ; is_dict(Dict,Tag), nonvar(Tag), Goals=[call(Tag:Func,Dict,Out)] + ). +safe_func(get(_)). +safe_func(put(_)). +safe_func(put(_,_)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dovamp.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dovamp.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,96 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dovamp, []). + + +:- use_module(library(persistency)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_turtle_write)). +:- use_module(library(fileutils)). +:- use_module(library(computations)). +:- use_module(library(swipe)). +:- use_module(library(async)). +:- use_module(components(audio)). +:- use_module(api(archive)). + +computations:do_computation(Transform,Input,Output) :- + rdf(Transform,rdf:type,vamp:'Transform'), !, + debug(dovamp,'Doing on demand Vamp ~q on ~q',[Transform,Input]), + with_temp_dir(Dir, with_progress_stack(sonic_annotator(Dir,Transform,Input,Output))). + +sonic_annotator(Dir,Transform,Input,CSVFile) :- + directory_file_path(Dir,'transform.n3',TFile), + directory_file_path(Dir,'*.csv',CSVPattern), + ( cp_audio:audio_file(Input,AudioFile,_) -> true + ; % !!! HACK + (rdf(Input,dml:blpage,_) -> ignore(bl_p2r:scrape_audio_link(Input,_)); true), + cp_audio:audio_link(Input,AudioLink,_), + directory_file_path(Dir,audio,AudioFile), + format(string(Desc),"Downloading audio for ~w to ~w",[Input,AudioFile]), + simple_task(Desc,run(curl(AudioLink)>:AudioFile^_)) + ), + write_transform(Transform,TFile), + run_with_progress(sonic_annotator(csv(Dir),TFile,AudioFile)), + expand_file_name(CSVPattern,[LocalCSV]), + archive_file('.csv',LocalCSV,CSVFile). + +run_with_progress(Pipeline) :- + command(Pipeline,Cmd), + debug(dovamp,'Running shell: ~s',[Cmd]), + setup_call_cleanup( + process_create(path(bash),['-c',Cmd],[stdin(null),stdout(null),stderr(pipe(Msgs)),process(PID)]), + % !!! not sure why I need once(_) here, but it doesn't work without it + call_cleanup( once(updatable_status_task('Initialising...',Update,read_messages(Msgs,Update))), + exception(_), process_kill(PID)), + (close(Msgs), process_wait(PID,Status)) + ), + check_status(Cmd,Status). + +read_messages(Stream,Update) :- + set_stream(Stream,buffer(false)), + repeat, % argh.. it's a failure driven loop + read_string(Stream, "\n\r", "",End, String), + ( string_concat(_,"%",String) -> call(Update,String) + ; string_concat("ERROR: ",Err,String) -> throw(sonic_annotator(Err)) + ; String\="" -> debug(sonic_annotator,'SA: >~w<',[String]) + ; true + ), + End = -1, !. + +prolog:message(sonic_annotator(Err)) --> ['Sonic annotator error: ~s'-[Err]]. +prolog:message(shell_error(Cmd,RC)) --> ['Shell command exit code ~w: ~s'-[RC,Cmd]]. + +check_status(_,exit(0)) :- !. +check_status(Cmd,exit(RC)) :- RC\=0, throw(shell_error(Cmd,RC)). +check_status(Cmd,killed(S)) :- throw(shell_killed(Cmd,S)). + +write_transform(Transform,File) :- rdf_save_turtle(File,[expand(transform_triple(Transform))]). + +:- rdf_meta transform_triple(r,r,r,o,-). +transform_triple(T, T, P, O, _) :- rdf(T, P, O). +transform_triple(T, S, P, O, _) :- rdf(T, vamp:parameter_binding, Param), describe(Param,rdf(S,P,O)). + +describe(S,rdf(S,P,O)) :- rdf(S,P,O). +describe(S,Triple) :- rdf(S,_,O), atom(O), describe(O,Triple). + + +swipe:def( curl(URL), sh(0>>_, "curl -L ~s 2>/dev/null", [@URL])). +swipe:def( sonic_annotator(csv(Dir),T,In), + sh(0>>0, "sonic-annotator -t ~s -w csv --csv-basedir ~s ~s", + [T+read,@Dir,In+read])). % Dir+write fails for directories diff -r 000000000000 -r 718306e29690 cpack/dml/lib/dsp.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/dsp.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,65 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(dsp, + [ spectrogram/2 + , spectrogram/3 + , spectrum/2 + , sum/2 + ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(sandbox)). +:- use_module(library(rdfutils)). +:- use_module(library(memo)). +:- use_module(library(mlserver)). + +:- set_prolog_flag(double_quotes,string). + +:- setting(specgram_dynamic_range,number,90,"Dynamic range in dB for spectrograms"). + +spectrogram(URI,X) :- + rdf_text(URI,beets:path,P), + X===specgrm( monofile(P), hanning(2048),512). + +:- volatile_memo spectrum(+atom,-ground). +spectrum(URI,X) :- + spectrogram(URI,Y), + X1===sum(Y,2), + persist_item(X1,X). + +spectrogram(URI,Offset,Length) :- + setting(specgram_dynamic_range,DBs), + ( cp_audio:audio_file(URI,P,Fmt), + ( Fmt=just(aac) + -> MSignal=sndfile(q(P),q(enc),q(aac)) + ; MSignal=sndfile(q(P)) + ) + ; cp_audio:audio_link(URI,P,just(mp3)), + MSignal=mp3file(q(P)) + ), !, + ?? (specgrm( taket(Length,dropt(Offset,mixdown(MSignal))), + hanning(2048),512,"range",DBs,"offset",Offset); + ylim([0,15])). + +sum(Items,Sum) :- + once(member(X,Items)), + D===numdims(X)+1, + Sum===sum(cellcat(D,cell(Items)),D). + +sandbox:safe_primitive(dsp:spectrogram(_,_,_)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/grammars.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/grammars.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,425 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(grammars, + [ model_name/2 + , model_module_prep/3 + , build_options/2 + , build_subset_options/2 + , learn/6 + , learn_bpe/6 + , learn_model/7 + , model_sequence_parses/4 + , nnums_ivals/2 + , restart_prism/0 + , best_first/6 + , method_model_dataset_results/4 + , dataset_num_events/2 + ]). + +:- multifile dataset_sequences/2. + +:- use_module(library(memo)). +:- use_module(library(typedef)). +:- use_module(library(lambda)). +:- use_module(library(plml)). +:- use_module(library(prism/prism)). +:- use_module(library(argutils)). +:- use_module(library(snobol)). + +:- type pmodule == ground. +:- type natural == nonneg. +:- type prep == callable. +:- type options == ordset. +:- type model ---> model(atom, list, prep, list(pair(ground,list(number)))). +:- type method ---> vb(ground) ; map(ground). +:- type matlab_method ---> vb ; map. + +% % hmmmn.. maybe module issues here... +% error:has_type(\Checker,Term) :- call(Checker,Term). +error:has_type(ordset,Term) :- is_ordset(Term). + +:- persistent_memo + learn( +method, +pmodule, +prep, +dataset:ground, +options, -scores:list), + learn_model( +method, +pmodule, +prep, +dataset:ground, +options, -scores:list, -model), + dataset_num_events( +dataset:ground, -num_events:nonneg). + +dataset_num_events(Dataset,NumEvents) :- + dataset_sequences(Dataset,Seqs), + maplist(length,Seqs,Lens), + sumlist(Lens,NumEvents). + % aggregate_all(sum(L),(member(S,Seqs),length(S,L)),NumEvents). + +:- initialization memo_attach(memo(learned),[]). +:- setting(timeout, number, 900, 'Time limit for learning in seconds'). + +user:file_search_path(prism,'psm'). +user:matlab_path(grammars,['stats/hmm']). + +partition_options([],[],[],[]). +partition_options([O|OX],[O|MO],IO,LO) :- option_class(O,model), partition_options(OX,MO,IO,LO). +partition_options([O|OX],MO,[O|IO],LO) :- option_class(O,init), partition_options(OX,MO,IO,LO). +partition_options([O|OX],MO,IO,[O|LO]) :- option_class(O,learn), partition_options(OX,MO,IO,LO). + +option_class(switch_mode(_),model). +option_class(prior_weight(_),model). +option_class(gamut(_),model). +option_class(leap_range(_),model). +option_class(log_scale(_),learn). +option_class(O,init) :- \+option_class(O,model), \+option_class(O,learn). + +option_mlopt(gamut(X-Y),gamut:[X,Y]) :- !. +option_mlopt(init(none),perturb:0) :- !. +option_mlopt(init(perturb(U)),perturb:U) :- !. +option_mlopt(F,N:V) :- F=..[N,V]. + +learn(vb(InitMeth),matlab(Function),Prepare,DataSet,Opts,[free_energy(FE)]) :- !, + dataset_sequences(DataSet, D1), + maplist(Prepare,D1,D), + maplist(option_mlopt,[init(InitMeth)|Opts],Opts1), + compileoptions(Opts1,Opts2), + [float(FE)]===feval(@Function,cell(D),Opts2). + + % method dependent options + +learn(Method,Module,Prepare,DataSet,Opts,Scores) :- + member(Method,[vb(_),map(_)]), + % prepare data + dataset_sequences(DataSet, D1), + maplist(Prepare,D1,D), + % method dependent options + method_switch_mode(Method,Mode), + option(log_scale(LS), Opts, on), + % load up prism and initialise + restart_prism, load_prism(prism(Module)), + #init_model([switch_mode(Mode)|Opts]), + #init_switches(Opts), + set_prism_flag(log_scale,LS), + % allow 15 minutes for learning + setting(timeout, TimeLimit), + get_time(Time), + debug(learn,'Calling PRISM with time limit ~w at ~@...', + [TimeLimit, format_time(current_output,'%T',Time)]), + call_with_time_limit(TimeLimit, prism_learn(Method, D, [], Scores)). + +method_switch_mode(vb(_),a). +method_switch_mode(map(_),d). + +learn_model(Method,Module,Prepare,DataSet,Opts,Scores,model(Module,ModelOpts,Prepare,Counts)) :- + % must re-compute to get final state + compute(learn(Method,Module,Prepare,DataSet,Opts,Scores)), + partition_options(Opts,ModelOpts,_,_), + get_prism_state(ps(_,_,Counts1,_,_,_)), + map_filter(unfixed_count,Counts1,Counts). + +unfixed_count(sw(SW,a,set(unfixed,Counts)), SW-Counts). + +model_initial_state(model(Module,MO,_,_),State) :- + restart_prism, + load_prism(prism(Module)), + #init_model([switch_mode(a)|MO]), + get_prism_state(State). + +with_model_data(model(Module,MO,Prepare,Counts),Data,Goal) :- + restart_prism, load_prism(prism(Module)), + #init_model([switch_mode(a)|MO]), + #maplist(SW-C,set_sw_a(SW,C),Counts), + call(Prepare,Data,D), + call(Goal,D). + +learn_bpe(Method,Module,Prepare,DataSet,Opts,BPE) :- + browse(learn(Method,Module,Prepare,DataSet,Opts,Scores)), + catch( bits_per_event(Method,DataSet,Scores,BPE), _, fail). + +bits_per_event(Method,DS,Scores,BPE) :- + dataset_num_events(DS,NumEvents), + score(Method,NumEvents,Scores,BPE). + +score(map(_),NumEvents,Scores,BitsPerEvent) :- + member(log_lik(LL), Scores), + BitsPerEvent is -(LL/NumEvents)/log(2). + +score(vb(_),NumEvents,Scores,BitsPerEvent) :- + member(free_energy(LL), Scores), + BitsPerEvent is -(LL/NumEvents)/log(2). + +score(vb_pm(_),NumEvents,Scores,BitsPerEvent) :- + member(free_energy(LL), Scores), + BitsPerEvent is -(LL/NumEvents)/log(2). + +%% tree_syntax(+Mod:module,+Tree:prism_tree,-Syntax:tree) is det. +% +% Create a parse tree from a PRISM Viterbi tree. +% Works for models gilbert1, gilbert2, gilbert2a, gilbert3 and gilbert2m. +tree_syntax(Mod,[s(_),TT],T2) :- tree_parse_tree(Mod,TT,T2). + +tree_parse_tree(_,msw(i(I),terminal),node(t(I),[])). +tree_parse_tree(Mod,[pp(s,_,_)|Children],Term) :- member(Mod,[gilbert2,gilbert2a,gilbert3,gilbert2m]), !, + member(msw(s,Rule),Children), + map_filter(tree_parse_tree(Mod),Children,CN), + ( Rule=grow -> CN=[Child1,T1], T1=node(s,Tail), Term=node(s,[Child1|Tail]) + ; Rule=last -> CN=[Child], Term=node(s,[Child]) + ). +tree_parse_tree(Mod,[pp(s,_,_)|Children],Term) :- Mod=gilbert1, !, + member(msw(s,Rule),Children), + map_filter(tree_parse_tree(Mod),Children,CN), + ( Rule=grow -> CN=[Child1,T1], T1=node(s,Tail), Term=node(s,[Child1|Tail]) + ; Rule=first -> CN=[], Term=node(s,[]) + ). +tree_parse_tree(Mod,[pp(H,_,_)|Children],Term) :- !, + map_filter(tree_parse_tree(Mod),Children,CN), + member(msw(H,Rule1),Children), + ( Rule1=terminal -> Rule=t; Rule=Rule1), + Term = node(H-Rule,CN). + +:- volatile_memo model_sequence_parses(+ground,+list(ground),+natural,-ground). + +model_sequence_parses(Model,Seq,N,Parses) :- + Model=model(Mod,_,_,_), + with_model_data(Model,Seq,parses(Mod,N,Parses)). + +parses(Mod,N,Parses,Goal) :- + succ(N,M), + findall(P-T,viterbi_tree(M,Goal,P,[],T),ProbsTrees), + append(NProbsTrees,[P0-_],ProbsTrees), + maplist(tree_parse(Mod,P0),NProbsTrees,Parses). + +tree_parse(Mod,P0,P-T,RP-S) :- tree_syntax(Mod,T,S), RP is P/P0. + + +% model declarations +decl_model(markov(nnum,0), p1gram, markovp, with_nnums(s0)). +decl_model(markov(nnum,1), p2gram, markovp, with_nnums(s1)). +decl_model(markov(ival,0), i1gram, markovi, with_ivals(s0)). +decl_model(markov(ival,1), i2gram, markovi, with_ivals(s1)). +decl_model(gilbert(1), gilbert1, gilbert1, with_pre_ivals(s)). +decl_model(gilbert(2), gilbert2, gilbert2, with_ivals(s)). +decl_model(gilbert(3), gilbert3, gilbert3, with_ivals(s)). +decl_model(gilbert(2-a), gilbert2a, gilbert2a, with_ivals(s)). +decl_model(gilbert(2-m), gilbert2m, gilbert2m, with_ivals(s)). +% decl_model(gilbert(4), gilbert1, gilbert1a, with_pre_ivals(s)). +% decl_model(gilbert(5), gilbert2, gilbert2a, with_ivals(s)). +% decl_model(gilbert(6), gilbert3, gilbert3a, with_ivals(s)). +decl_model(hmm(nnum), phmm, phmm, with_nnums(s)). +decl_model(hmm(nnum,NS), Name, phmm, with_nnums(s)) :- atom_concat(phmm,NS,Name). +%decl_model(hmm(ival), ihmm, ihmm, with_ivals(s)). +decl_model(matlab(p1gram), 'ml-p1gram', matlab(p1gram), (=)). +decl_model(matlab(p2gram), 'ml-p2gram', matlab(p2gram), (=)). +decl_model(matlab(phmm), 'ml-phmm', matlab(phmm), (=)). + +model_name(Model,Name) :- decl_model(Model,Name,_,_). +model_module_prep(Model,Module,Prepare) :- decl_model(Model,_,Module,Prepare). + +with_nnums(Head, Seq, Head1) :- + addargs(Head,[Seq],Head1). + +with_ivals(Head, Seq, Head1) :- + nnums_ivals(Seq,Seq1), + addargs(Head,[Seq1],Head1). + +with_pre_ivals(Head, Seq, Head1) :- + nnums_pre_ivals(Seq,Seq1), + addargs(Head,[Seq1],Head1). + +nnums_ivals(NNums,Ivals) :- nnums_post_ivals(NNums,Ivals). +nnums_post_ivals(NNums,Ivals) :- phrase((ivals(NNums),[end]),Ivals,[]). +nnums_pre_ivals(NNums,Ivals) :- phrase(([start],ivals(NNums)),Ivals,[]). + +ivals([X0,X1|Xs]) --> {I1 is X1-X0}, [I1], ivals([X1|Xs]). +ivals([_]) --> []. + +% NB option defaults here must match those in PRISM source files. +model_options(markov(nnum,_)) --> + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + optopt(gamut,[40-100]). + +model_options(markov(ival,_)) --> + optopt(prior_shape, [uniform, binomial+uniform, binomial+0.1*uniform]). + +model_options(gilbert(_)) --> + [leap_range((-20)-(20))], + optopt(leap_shape, [uniform, binomial+uniform, binomial+0.1*uniform]), + optopt(pass_shape, [binomial, binomial+uniform, binomial+0.1*uniform]). + +model_options(hmm(nnum)) --> + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + anyopt(num_states, [1,2,3,5,7,12,18]), + optopt(trans_self, [1]), + % optopt(gamut,[40-100]). + % anyopt(trans_self, [1]), + anyopt(gamut,[40-100]). + +model_options(hmm(nnum,NS)) --> + [num_states(NS)], + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + optopt(trans_self, [1]), + % optopt(gamut,[40-100]). + % anyopt(trans_self, [1]), + anyopt(gamut,[40-100]). + +model_options(hmm(ival)) --> + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + anyopt(num_states, [5,7,12,24]), + [leap_range((-20)-(20))]. + +model_options(matlab(p1gram)) --> + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + optopt(gamut,[40-100]). + +model_options(matlab(p2gram)) --> + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + optopt(gamut,[40-100]). + +model_options(matlab(phmm)) --> + optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), + anyopt(num_states, [1,2,3,5,7,12,18]), + optopt(gamut,[40-100]). + +model_subset_options(markov(nnum,_)) --> [prior_shape(binomial+0.1*uniform)]. +model_subset_options(markov(ival,_)) --> [prior_shape(binomial+0.1*uniform)]. +model_subset_options(gilbert(_)) --> []. +model_subset_options(hmm(nnum)) --> + [prior_shape(binomial+0.1*uniform)], + anyopt(num_states,[2,5,7,12,18]). +model_subset_options(hmm(ival)) --> + [prior_shape(binomial+0.1*uniform), leap_range((-20)-(20))], + anyopt(num_states,[2,5,7,12]). + +build_options(Model,Opts) :- + build_options(Model,Opts1,[]), + sort(Opts1,Opts). + +build_options(Model) --> + optopt(prior_weight,[0.3,3,10]), % NB have removed 0.1 and 30 + model_options(Model). + +build_subset_options(Model,Opts) :- + build_subset_options(Model,Opts1,[]), + sort(Opts1,Opts). + +build_subset_options(Model) --> + optopt(prior_weight,[0.1,0.3,3,10,30]), + model_subset_options(Model). + +anyopt(Name,Vals) --> {maplist(\X^Y^(Y=..[Name,X]),Vals,Opts)}, any(Opts). +optopt(Name,Vals) --> []; anyopt(Name,Vals). + +best_first(Meth,Mod,Prepare,DS,Opts,learn(Meth,Mod,Prepare,DS,Opts,F)) :- + order_by([asc(F)], learn_bpe(Meth,Mod,Prepare,DS,Opts,F)). + +/* TODO: + Sort out HMM init options. They are all wrong: + init_shape : shape of prior over initial state {uniform} + trans_shape : shape of prior over transition distribution {uniform} + trans_persistence : add self transtion counts {0,1,3} + init_noise : perturbation of initial obs counts {0,0.1} + restarts: {3} + + + + compare p2gram with hmm(1) + */ + + +%% map_filter(+P:pred(A,B),+Xs:list(A),-Ys:list(B)) is det. +% +% map_filter(P,Xs,Ys) is similar to maplist(P,Xs,Ys), except that P is allowed to +% fail and the resulting list Ys contains only those elements Y for which call(P,X,Y). +% P is used as if it was semi-deterministic: only the first solution is accepted. +map_filter(_,[],[]). +map_filter(P,[X|XX],[Y|YY]) :- call(P,X,Y), !, map_filter(P,XX,YY). +map_filter(P,[_|XX],YY) :- map_filter(P,XX,YY). + +user:file_search_path(home,X) :- expand_file_name('~',[X]). +user:file_search_path(prism,home('src/probprog/prism/psm')). +restart_prism :- prism_start('prism.log'). + +retry_on_error(G,M) :- + catch((restart_prism,G,Status=ok), Ex, Status=error(Ex)), + ( Status=ok -> true + ; format('*** terminated with ~w.\n',[Ex]), + shell('say ALERT: THERE WAS AN ERROR!'), + ( succ(N,M) -> retry_on_error(G,N) + ; writeln('failing after too many retries.'), + shell('say ALERT: I AM GIVING UP!'), + shell('say ALERT: I AM GIVING UP!'), + fail + ) + ). + +%% summary_array(+Meth:method,+Models:list(model),+Datasets:list(dataset),-Summary) is det. +summary_array(Meth,Models,Datasets,arr(Summary)) :- + maplist( \Model^RR^maplist(\DS^{arr(R)}^method_model_dataset_results(Meth,Model,DS,R),Datasets,RR), Models,Summary). + +%% method_model_dataset_results(+Method,+Model,+Dataset,Results:list(list(number))) is det. +method_model_dataset_results(Meth,Model,DS,Results) :- bagof( Row, datum(Meth,Model,DS,Row), Results). + +%% datum(+Method:method,+Model:model,+Dataset,-Datum:list(number)) is nondet. +% +% Maps trained models to a numerical tuple consisting of +% the free energy (in bits per event), the prior weight parameter, and one or two +% shape parameters, depending on the model. The shape parameter is 0 for a uniform +% prior, 1 for a binomial prior, and between 0 and 1 for linear interpolation between +% the two. +% +% Grammar models have leap_shape and pass_shape parameters, while the others +% have a single prior_shape parameter. +datum(Meth,gilbert(I),DS,[FE,W,K1,K2]) :- + model_module_prep(gilbert(I),Mod,Prep), + learn_bpe(Meth,Mod,Prep,DS,Opts,FE), + option(prior_weight(W),Opts,1), + option(leap_shape(Sh1),Opts,binomial), + option(pass_shape(Sh2),Opts,uniform), + shape_param(Sh1,K1), + shape_param(Sh2,K2). + +datum(Meth,markov(Rep,Ord),DS,[FE,W,K]) :- + model_module_prep(markov(Rep,Ord),Mod,Prep), + learn_bpe(Meth,Mod,Prep,DS,Opts,FE), + option(prior_weight(W),Opts,1), + option(prior_shape(Sh),Opts,binomial), + shape_param(Sh,K). + +datum(Meth,hmm(Rep),DS,[FE,W,K]) :- + model_module_prep(hmm(Rep),Mod,Prep), + learn_bpe(Meth,Mod,Prep,DS,Opts,FE), + option(prior_weight(W),Opts,1), + option(prior_shape(Sh),Opts,binomial), + shape_param(Sh,K). + +datum(Meth,hmm(Rep,NS),DS,[FE,W,K]) :- + model_module_prep(hmm(Rep),Mod,Prep), + learn_bpe(Meth,Mod,Prep,DS,Opts,FE), + option(num_states(NS),Opts), + option(prior_weight(W),Opts,1), + option(prior_shape(Sh),Opts,binomial), + shape_param(Sh,K). + +datum(Meth,matlab(F),DS,[FE,W,K]) :- + model_module_prep(matlab(F),Mod,Prep), + learn_bpe(Meth,Mod,Prep,DS,Opts,FE), + option(prior_weight(W),Opts,1), + option(prior_shape(Sh),Opts,binomial), + shape_param(Sh,K). + +shape_param(uniform,0). +shape_param(binomial,1). +shape_param(binomial+uniform,0.5). +shape_param(uniform+binomial,0.5). +shape_param(binomial+K*uniform,Lam) :- Lam = 1/(1+K). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/htmlutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/htmlutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,88 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(htmlutils, + [ link//2 + , style//1 + , script//1 + , use_font//2 + , use_font//3 + , paginator//3 + , element//2 + ]). + +:- use_module(library(http/html_write)). +:- use_module(library(http/html_head)). +:- use_module(library(http/http_path)). +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/http_server_files)). + +:- multifile user:body//1, user:body//2. +:- multifile user:head//1, user:head//2. +% :- multifile user:style/2. + +:- set_prolog_flag(double_quotes,string). + +% :- setting(appname, string, "anApp", "Application name"). + +:- meta_predicate element(+,:,?,?). +element(Element,Content) --> { Item=..[Element, Content] }, html(Item). + +link(Id,Text) --> html(a(href(location_by_id(Id)),Text)). +style(Loc) --> {http_absolute_location(Loc,Ref,[])}, html(link([rel(stylesheet), href(Ref)],[])). +script(Loc) --> {http_absolute_location(Loc,Ref,[])}, html(script(src(Ref),[])). + +http:location(googlefonts,"//fonts.googleapis.com",[]). + +user:term_expansion((:- googlefont(Name,Family)), Decls) :- + Decls = [ (:- html_resource(Name,[virtual(true),requires(googlefonts(Query))])) + , (:- html_resource(googlefonts(Query),[mime_type(text/css)])) + ], + string_concat("css?family=",Family,Query). + + +use_font(Family,Resource) --> + html_requires(Resource), + html_post(head, style(type="text/css","html,body,h1,h2,h3,h4,h5,h6,select,input,.btn {font-family: '~s';}"-[Family])). + +use_font(Elements,Family,Resource) --> + html_requires(Resource), + html_post(head, style(type="text/css","~w {font-family: '~s';}"-[Elements,Family])). + +paginator(_,_,1) --> []. +paginator(Handler,Page,Pages) --> + html(div(class('text-centered'), + ul(class(pagination), + [ li(\prev(Page,Pages,Handler)) + , li(\page_link(Handler,1,1)) + , li(span("~d of ~d"-[Page,Pages])) + , li(\page_link(Handler,Pages,Pages)) + , li(\next(Page,Pages,Handler)) + ]))). + +prev(1,_,_) --> !,html(span(class(inactive),&(larr))). +prev(N,_,Handler) --> { succ(M,N) }, page_link(Handler,M,&(larr)). + +next(N,N,_) --> !,html(span(class(inactive),&(rarr))). +next(N,_,Handler) --> { succ(N,M) }, page_link(Handler,M,&(rarr)). + +page_link(ID-Params,N,Content) --> + { http_link_to_id(ID,[page(N)|Params],Link) }, + html(a(href(Link),Content)). + + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/httpfiles.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/httpfiles.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,129 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(httpfiles, + [ reply_file/2 + , reply_file/3 + , reply_stream/2 + , reply_stream/3 + , reply_html_page/4 + , write_headers/1 + , mime_type/2 + ]). + +:- use_module(library(http/html_write)). + +:- meta_predicate reply_html_page(+,:,:,+). + +write_headers(Headers) :- maplist(write_header,Headers), nl. + +write_header(length(L)) :- write_header('Content-Length'-L). +write_header(no_ranges) :- write_header('Accept-Ranges'-none). +write_header(stable) :- write_header('Cache-Control'-'max-age=31536000, public'). +write_header(unstable) :- write_header('Cache-Control'-'max-age=0, public'). +write_header(error) :- write_header('Cache-Control'-'max-age=0, private, must-revalidate'). +write_header(html) :- + html_current_option(content_type(ContentType)), + write_header('Content-Type'-ContentType). +write_header(type(Type)) :- + mime_type(Type,MimeType), + write_header('Content-Type'-MimeType). +write_header(cookie(Name,Value,Expires)) :- + format(atom(Cookie),'~w=~w; path=/; Expires=~w',[Name,Value,Expires]), + write_header('Set-Cookie'-Cookie). +write_header(no_cache) :- + maplist( write_header, + [ 'Cache-Control'-'no-cache, no-store, must-revalidate' + , 'Pragma'-'no-cache' + , 'Expires'-'0' + ]). + +write_header(Name-Value) :- + format('~w: ~w~n',[Name,Value]). + +reply_html_page(Style,Head,Body,Headers) :- + phrase(page(Style,Head,Body),Tokens), + write_headers([html|Headers]), + print_html(Tokens). + +reply_file(File,Type) :- reply_file(File,Type,[stable]). +reply_file(File,Type,Headers) :- + write_headers([type(Type)|Headers]), + debug(httpfiles,"Sending ~w with type ~w...",[File,Type]), + setup_call_cleanup( + open(File, read, In, [type(binary)]), + copy_stream_data(In, current_output), + close(In)), + debug(httpfiles,"Finished sending.",[]). + +with_tmp_stream(Enc,File,Str,Goal) :- + setup_call_cleanup( + tmp_file_stream(Enc,File,Str), Goal, + (close(Str,[force(true)]), delete_file(File))). + +reply_stream(In,Type) :- reply_stream(In,Type,[stable]). +reply_stream(In,Type,Headers) :- + ( memberchk(length(Length),Headers), var(Length) + -> debug(httpfiles,"Stream length unknown - buffering to file...",[]), + with_tmp_stream( octet, TmpFile, ToTmp, + ( copy_stream_data(In,ToTmp), close(ToTmp), + size_file(TmpFile,Length), + debug(httpfiles,"Stream length was ~d bytes",[Length]), + reply_file(TmpFile,Type,Headers) + )) + ; write_headers([type(Type)|Headers]), + copy_stream_data(In, current_output) + ), + debug(httpfiles,"Finished sending stream.",[]). + +% debug_stream(S,Label,Prop) :- stream_property(S,Prop), debug(httpfiles,"Stream property (~w): ~w",[Label,Prop]). + +% copy_stream_length(In,Out,Len) :- + % copy_stream_data(In,Out). + % copy_stream_length(In,Out,0,Len). + +% copy_stream_length(In,_,Len,Len) :- at_end_of_stream(In), !. +% copy_stream_length(In,Out,L1,L3) :- +% debug(httpfiles,"Reading...",[]), +% read_pending_input(In,Codes,[]), +% length(Codes,N), L2 is L1+N, +% debug(httpfiles,"Transferring ~d bytes...",[N]), +% format(Out,'~s',[Codes]), +% flush_output(Out), +% copy_stream_length(In,Out,L2,L3). + +mime_type(csv , "text/csv"). +mime_type(ogg , "audio/ogg"). +mime_type(mp3 , "audio/mp3"). +mime_type(aac , "audio/aac"). +mime_type(svg, "image/svg+xml; charset=UTF-8"). +mime_type(pdf, "application/pdf"). +mime_type(eps, "application/postscript"). +mime_type(ps, "application/postscript"). +mime_type(kern, "text/plain; charset=UTF-8"). +mime_type(abc, "text/plain; charset=UTF-8"). % vnd.abc +mime_type(mxml, "text/xml; charset=UTF-8"). +mime_type(lily, "text/plain; charset=UTF-8"). +mime_type(midi, "audio/midi"). +mime_type(png, "image/png"). +mime_type(mp4, "video/mp4"). +mime_type(json, "application/json; charset=UTF-8"). +mime_type(jsonp,"application/javascript; charset=UTF-8"). + +% httpfiles:mime_type(mxml, "application/vnd.recordare.musicxml+xml; charset=UTF-8"). +% httpfiles:mime_type(lily, "text/x-lilypond; charset=UTF-8"). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/humdrum_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/humdrum_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,286 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(humdrum_p2r, [ humdrum_import/1, hum_uri_path/2 ]). + +/** Manages a database of Humdrum files and mappings to RDF. + */ + +:- use_module(library(memo)). +:- use_module(library(humdrum)). +:- use_module(library(humdrum/humdrum_world), [with_kern_module/4]). +:- use_module(library(fileutils)). +:- use_module(library(termutils)). +:- use_module(library(typedef)). +:- use_module(library(dcg_core)). +:- use_module(library(musiclab)). +:- use_module(library(settings)). +:- use_module(entailment(p2r)). + +:- set_prolog_flag(double_quotes,string). + +:- rdf_register_prefix(humdb,'http://dml.org/humdrum/data/'). +:- rdf_register_prefix(hum,'http://dml.org/humdrum/schema/'). +:- rdf_register_prefix(kern,'kern:'). + +:- setting(kern_root,string,"~/lib/kern","Root of kern lib tree"). +:- setting(kern_subdirs,list(atom),[classical,lorraine,jrp,ragtime,ireland,pentatonic,idyom],"Kern library directories to import"). + +uripattern:def( work(Opus), humdb:work/enc(Opus)). +uripattern:def( trefcode(C), hum:refcode/trans/enc(C)). +uripattern:def( refcode(C), hum:refcode/enc(C)). +uripattern:def( kernfile(F), kern:tail(F)). + +% Humdrum schema +rdf(hum:refcode('OTL'), rdfs:subPropertyOf, dc:title), +rdf(hum:composer, rdfs:subPropertyOf, foaf:maker), +rdf(hum:opus, rdfs:subPropertyOf, mo:opus), +rdf(hum:'Work', rdfs:subClassOf, mo:'MusicalWork'), +rdf(hum:'File', rdfs:subClassOf, mo:'Score'), +rdf(hum:encodedBy, rdfs:type, rdf:'ObjectProperty'), +% rdf(hum:encodedBy, owl:inverseOf, hum:encodes) <== true. + +rdf(\refcode(C), rdfs:subPropertyOf, \trefcode(C)) <== + setof(C, translated_refcode(C), Codes), + member(C, Codes). + +rdf(\trefcode(C), rdf:comment, Desc1) <== + setof(C, translated_refcode(C), Codes), + member(C, Codes), + hum_prop_desc(C,Desc), + atom_concat(Desc,' (translated)',Desc1). + +translated_refcode(Code) :- + browse(file_props(_,Props)), + member(Code-((sec-_)-_),Props). + +hum_prop_desc(C,_) ==> + rdf(\refcode(C), rdf:type, rdf:'ObjectProperty'), + rdf(\refcode(C), rdf:domain, hum:'File'). + +hum_prop_desc(C,Desc) ==> + rdf(\refcode(C), rdf:comment, literal(Desc)). + +% -- mappings that use file_opus/2 --------------- + +%% file(-File) is nondet. +% True when File is a Humdrum file that has been imported into +% the current database. +:- dynamic file/1. + +%% file_opus(-File,-Opus) is nondet. +% True when Humdrum file File contains an SCT refcode +% (scholarly catalog number) Opus. +file_opus(F,O) :- file(F), file_prop(F,'SCT',_,O). + +rdf(\kernfile(F), \trefcode(C), literal(Value)) <== + call_with_mode(browse,file_prop(F,C,sec,Value)). + +rdf(\kernfile(F), \refcode(C), literal(Value)) <== + call_with_mode(browse,file_prop(F,C,pri,Value)). + +rdf(\kernfile(F), hum:directory, literal(Dir1)) <== + file(F), + file_directory_name(F,Dir), + atom_concat('/',Dir1,Dir). + +file(F) ==> + % rdf(\kernfile(F), hum:language, hum:language/humdrum), + rdf(\kernfile(F), rdf:type, hum:'File'). + +file_opus(_,O) ==> + rdf(\work(O), rdf:type, hum:'Work'), + rdf(\work(O), hum:opus, literal(O)). + +% file_opus(F,O) ==> +% rdf(\kernfile(F), hum:encodes, \work(O)). + + +% rdf(\work(O), dc:title, literal(Title)) <== +% file_opus(F,O), +% (file_has(F,'OTL',Title); file_has(F,'OTP',Title)). + +% rdf(\work(O), dc:title, literal(lang(Lang,Title))) <== +% file_opus(F,O), +% file_has(F,'OTL',Title), +% file_has(F,'TXO',Lang). + +% rdf(\work(O), hum:partOf, humdb:parent_work/enc(P)) <== +% file_opus(F,O), +% (file_has(F,'OPT',P); file_has(F,'OPR',P)). + +% rdf(\work(O), hum:composer, humdb:agent/enc(C)) <== +% file_opus(F,O), file_has(F,'COM',C). + +% rdf(\work(O), hum:number, literal(Num)) <== +% file_opus(F,O), file_has(F,'ONM',Num). + +% ----- mappings using composers/1 -------- + +% rdf(humdb:agent/enc(C), foaf:name, literal(C)), +% rdf(humdb:agent/enc(C), rdf:type, mo:'MusicArtist') <== +% composers(Composers), +% member(C,Composers). + +% ----- mappings using parent_works/1 -------- + +% rdf(humdb:parent_work/enc(P), rdf:type, hum:'Work'), +% rdf(humdb:parent_work/enc(P), dc:title, literal(P)) <== +% parent_works(Works), +% member(P,Works). + + +has_stripped(Recs,Prop,Status,Literal) :- + member(ref(Prop,Lang,RawValue),Recs), + split_string(RawValue,""," ",[String]), + String\="", atom_string(Value,String), + refcode_literal(Lang,Value,Status,Literal). + +refcode_literal(def, Val, pri, Val). +refcode_literal(P-Lang, Val, P, lang(L,Val)) :- lang(Lang,L). + +:- type prop ---> prop(atom,atom,ground). +:- volatile_memo file_props(+file:atomic,-props:list(prop)). + +file_props(File,Props) :- + setting(kern_root,Root0), + expand_file_name(Root0,[Root]), + string_concat(Root,File,Abs), + % !!! FIXME: will barf if Root contains funny characters + format(string(Cmd),"grep '^!!!' \"~w\"",[Abs]), + hum_read(pipe(Cmd),utf8,Recs), + setof(prop(Prop,Status,Lit),has_stripped(Recs,Prop,Status,Lit),Props). + + +:- volatile_memo parent_works(-works:list(ground)). +parent_works(Works) :- + writeln('% Compiling list of parent works...'), + setof(P, F^O^(file_opus(F,O),file_prop(F,'OPR',_,P)), Works). + +:- volatile_memo composers(-composers:list(atom)). + +%% composers(-Composers:list(atom)) is det. +% Compiles a list of composer names referenced in the current +% Humdrum file property database file_props/2. +composers(Composers) :- + writeln('% Compiling list of composers...'), + findall(C, call_with_mode(browse,file_prop(_,'COM',_,C)), CList), + sort(CList,Composers). + +% rdf(URI,rdf:type,mo:'MusicArtist') <== +% composers(Comps), +% member(C,Comps), +% agent_uri(composer,C,URI). + +% rdf(URI,hum:name,literal(Name)) <== +% agent_uri(composer,Name,URI). + +% rdf(\kernfile(F), hum:composer, literal(Name)) <== +% call_with_mode(browse,file_prop(F,'COM',pri,Name)), + % agent_uri(composer,Name,URI). + + +file_work_terms(File) --> + if(file_prop(File,'OTL',_,Title), [Title]), + if(file_prop(File,'OPR',_,Parent), [Parent]), + if(file_prop(File,'OPN',_,Opus), [Opus]), + if(file_prop(File,'SCT',_,Cat), [Cat]). + + +file_prop(File,Prop,Status,Lit) :- + file_props(File,Props), + member(prop(Prop,Status,Lit),Props). + + +hum_uri_path(URI,Path) :- + atom_concat('kern:',Rel,URI), + setting(kern_root,Root), + expand_file_name(Root,[Root1]), + string_concat(Root1,Rel,Path). + + +%% humdrum_import(+Path:atom) is det. +% +% Searches for files in the directory tree beneath +% =|/Path|=, where =| Status=ok + ; Status=fail), + Ex, Status=ex(Ex)). + + +humdrum_check :- + with_status_line( + forall( (rdf_db:rdf(X,rdf:type,hum:'File'), hum_uri_path(X,Path)), + ( humfile_status(Path,Status), + ( Status=ok -> true + ; Status=fail -> format('\nFailed on: ~w\n',[Path]) + ; Status=ex(Ex) -> format('\nException on: ~w\n',[Path]), + print_message(error,Ex) + ) + ))). + +kern_file(Findspec,File) :- + find_files(Findspec,File), + extension_in(File,[krn,kern,'KRN','KERN']). + +id_assert(Fact) :- call(Fact) -> true; assert(Fact). + +lang('ENG',en). +lang('EN',en). +lang('FRA',fr). +lang('FRE',fr). +lang('FR',fr). +lang('DE',de). +lang('DEU',de). +lang('GER',de). +lang('ITA',it). +lang('IT',it). +lang('NO',no). +lang('NOR',no). +lang('LAT',la). +lang('LA',la). +lang('RU',ru). +lang('RUS',ru). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/ilm_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/ilm_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,168 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(ilm_p2r, []). + +/** Access to ILM database + */ + + +:- use_module(library(odbc)). +:- use_module(library(musicbrainz)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(termutils)). +:- use_module(library(odbcutils)). +:- use_module(library(rdfutils)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg/basics)). +:- use_module(entailment(p2r)). +:- use_module(cliopatria(hooks)). + +:- set_prolog_flag(double_quotes,string). + +:- rdf_register_prefix(ilm,'http://dml.org/ilm/'). + +:- setting( ilm_genres,list(atom), + ['Classical','Jazz','Latin','Blues','Folk','Electronic','Reggae','Rock & Roll'], + "List of ILM genre names to import"). + +:- public import/0. +import :- with_odbc(ilm, assert_all(ilm_p2r)). + +:- rdf_meta map(+,r,+,o). + +% ---------------------------- utilities ----------------------------- + +%% genre_list_member(-Genre:uri, +GenreList:atom) is nondet. +genre_list_member(Genre,Atom) :- + parse_list_member(';',Atom,GenreName), + number_string(GenreId,GenreName), + uripattern:pattern_uri(ilm:genre/num(5,GenreId),Genre). + +%% parse_list_member(+Sep:text,+Text:text,-Item:string) is nondet. +parse_list_member(Sep,Atom,Item) :- + split_string(Atom,Sep,'',Items), + member(Item,Items). +% ---------------------- getting stuff out of database --------------------- + +genre_album(Genre,AlbumId) :- + qsql(ilm,"select distinct album_id from assets where genre_id=~d and track_no!=0",[Genre],row(AlbumId)). + +album_facet(AlbumId,Prop-Val) :- entity_facet(album,AlbumId,Prop,Val). + +genre_track(Genre,AlbumId-TrackNo) :- + qsql(ilm,"select album_id, track_no from assets where genre_id=~d and track_no!=0",[Genre],row(AlbumId,TrackNo)). + +track_facet(AlbumId-TrackNo,Prop-Val) :- entity_facet(track,AlbumId-TrackNo,Prop,Val). + +query_columns(album, + [ album_title, product_artist, product_classifications, product_genre, + product_release_year, product_label, product_upc ]). +query_columns(track, + [ assets_online, artist_name, comment, genre_id, release_year, song_title, + track_classifications, track_duration, track_isrc]). + +entity_facet(Type,Id,Prop,Val) :- + query_columns(Type,Cols), + pairs_keys_values(Pairs,Cols,Vals), + Row =.. [row|Vals], + phrase(entity_query(Type,Id,Cols),Codes,[]), + qsql(ilm,'~s',[Codes],Row), + member(Prop-Val,Pairs), + Val\='$null$', + Val\=''. + +entity_query(album,AlbumId,Cols) --> + "select ", + seqmap_with_sep(",",atom,Cols), + " from assets where album_id=", number(AlbumId). + +entity_query(track,AlbumId-TrackNo,Cols) --> + "select ", + seqmap_with_sep(",",atom,Cols), + " from assets where album_id=", number(AlbumId), + " and track_no=", number(TrackNo). + +include_genre(GenreId,Genre) :- + setting(ilm_genres,Genres), + member(Genre,Genres), + qsql(ilm,"select ID from classifications where name='~s'",[Genre],row(GenreId)). + + +% -------------------- mapping to rdf ---------------------------------- + + +rdf(ilm:genre/num(5,GenreID),rdf:type,mo:'Genre'), +rdf(ilm:genre/num(5,GenreID),rdfs:label,literal(GenreName)) <== + odbc_query(ilm,"select ID, name from classifications",row(GenreID,GenreName)). + +rdf(ilm:album/num(AlbumId), Pred, Obj) <== + include_genre(GenreId,GenreName), + status("Querying albums of genre ~w...",[GenreName]), + genre_album(GenreId,AlbumId), + status("Importing ILM albums, genre ~w: ~d",[GenreName, AlbumId]), + album_facet(AlbumId,Facet), + map(Facet,Pred,Obj). + +rdf(ilm:track/num(AlbumId)/num(TrackNo), Pred, Obj) <== + include_genre(GenreId,GenreName), + status("Querying tracks of genre ~w...",[GenreName]), + genre_track(GenreId,AlbumId-TrackNo), + status("Importing ILM tracks, genre ~w: ~d/~d",[GenreName, AlbumId, TrackNo]), + ( Facet=track_no-TrackNo + ; Facet=album_id-AlbumId + ; track_facet(AlbumId-TrackNo,Facet) + ), + map(Facet,Pred,Obj). + +map(Prop-Val,Pred,Obj) :- + ( map(Prop,Pred,Val,Obj) *-> true + ; print_message(warning,ilm_p2r:unrecognized_column(Prop,Val)), fail + ). + + +% album level +map(album_title , dc:title, X, literal(X)). +map(product_label , mo:label, X, literal(X)). +map(product_artist , ilm:artist, X, literal(X)). +map(product_upc , ilm:upc, X, literal(X)). +map(product_release_year, ilm:release_date, Y, literal(type(xsd:date,YA))) :- atom_number(YA,Y). +map(product_classifications, mo:genre, Atom, Genre) :- genre_list_member(Genre,Atom). +map(product_genre, ilm:genre, Id, Obj) :- uripattern:pattern_uri(ilm:genre/num(5,Id),Obj). + +% track level +map(genre_id, ilm:genre, Id, Obj) :- uripattern:pattern_uri(ilm:genre/num(5,Id),Obj). +map(album_id, ilm:album, X, Album) :- uripattern:pattern_uri(ilm:album/num(X),Album). +map(track_no, mo:track_number, X, literal(type(xsd:nonNegativeInteger,X))). +map(track_isrc, mo:isrc, X, literal(type(xsd:string,X))). +map(song_title, dc:title, X, literal(X)). +map(comment, ilm:comment, X, literal(X)). +map(artist_name, ilm:artist, X, literal(X)). +map(track_classifications, mo:genre, X, Genre) :- genre_list_member(Genre,X). +map(track_duration, mo:duration, X, literal(type(xsd:float,Millis))) :- + parse_duration_millis(X,Millis). + +map(release_year, ilm:release_date, Y, literal(type(xsd:date,YA))) :- atom_number(YA,Y). +map(assets_online, ilm:asset_online, Atom, literal(Type)) :- + parse_list_member(',',Atom,TypeS), + atom_string(Type,TypeS). + +% map(P,ilm:P,date(Y,M,D),literal(type(xsd:date,Date))) :- +% format_time(atom(Date),'%F',date(Y,M,D)). +% map(P,ilm:P,timestamp(YY,MM,DD,H,M,S,_),literal(type(xsd:dateTime, DateTime))) :- !, +% format_time(atom(DateTime),'%FT%T',date(YY,MM,DD,H,M,S,0,-,-)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/insist.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/insist.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,30 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(insist, [insist/1,insist/2, insist/3]). +:- meta_predicate insist(0,:), insist(0), insist(+,0,:). + +insist(G) :- insist(G,failed(G)). +insist(G,Ex) :- call(G) -> true; throw(Ex). +insist(det,G,Ex) :- insist(G,Ex). +insist(multi,G,Ex) :- call(G) *-> true; throw(Ex). + +user:goal_expansion(insist(G),X) :- user:goal_expansion(insist(G,failed(G)),X). +user:goal_expansion(insist(G,Ex),(G->true;throw(Ex))). +user:goal_expansion(insist(det,G,Ex),X) :- user:goal_expansion(insist(G,Ex),X). +user:goal_expansion(insist(multi,G,Ex),(G*->true;throw(Ex))). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/jpath.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/jpath.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,85 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(jpath, [ jpath/2, op(600,xfy,#) ]). +:- use_module(library(dcg_core)). +:- use_module(library(insist)). + +% :- op(600,fx,#). +:- op(600,xfy,#). + +% harvest(M,Tree) :- harvest(M,just(Tree),nothing). +% harvest(\X,just(X),nothing). +% harvest(@F,just(X),just(Y)) :- Y=X.F. +% harvest(#N,just(X),just(Y)) :- nth1(N,X,Y). +% harvest(F*G) --> harvest(F), harvest(G). +% harvest((F//G)) --> harvest(F) // harvest(G). + +% dec(id,X,X). +% dec([],_,[]). +% dec([D|Ds],X,[Y|Ys]) :- dec(D,X,Y), dec(Ds,X,Ys). +% dec(@F,X,Y) :- Y=X.F. +% dec(F*G,X,Z) :- dec(F,X,Y), dec(G,Y,Z). +% dec(swap,(X,Y),(Y,X)). +% dec(dup,X,(X,X)). +% dec(fst(F),(X,Y),(Z,Y)) :- dec(F,X,Z). +% dec((F,G),X,(Y,Z)) :- dec(F,X,Y), dec(G,X,Z). +% dec(item,X,Y) :- member(Y,X). + +% decode(F, R, X) :- atomic(F), X=R.F. +% decode(item(D), R, X) :- decode(D,R,Y), member(X,Y). +% decode(F/G, R, X) :- decode(F,R,Y), decode(G,Y,X). + +jpath(Y,X) :- + (complex(X) -> (match(Y,X); Y=(_,_), multi_match(Y,[],X)) ; Y=X). + +complex(X) :- is_list(X). +complex(X) :- is_dict(X). + +match(\X,X). +match(Y,X) :- var(Y), !, + ( is_dict(X) -> match_dict(Y,X) + ; is_list(X) -> match_list(Y,X) + ). +match(dict(X),X) :- must_be(dict,X). +match(list(X),X) :- must_be(list,X). +match(N#Y,X) :- must_be(list,X), match_member(N,Y,X). +match(F:Y,X) :- must_be(dict,X), match_field(F,Y,X). + +match_dict(dict(X),X). +match_dict(F:V,X) :- match_field(F,V,X). + +match_list(list(X),X). +match_list(N#Y,X) :- match_member(N,Y,X). + +match_field(F,Y,X) :- + ( var(F) -> get_dict(F,X,Z) + ; insist(get_dict(F,X,Z),field_not_present(F,X)) + ), + jpath(Y,Z). + +match_member(N,Y,X) :- + ( var(N) -> nth1(N,X,Z) + ; nth1(N,X,Z) % insist(...),index_out_of_range(N,X)) + ), + jpath(Y,Z). + +% multi_match([],_,_). +% multi_match([S|Ss],Prev,X) :- match1(S,X), \+member(S,Prev), multi_match(Ss,[S|Prev],X). +multi_match(S,Prev,X) :- match(S,X), \+member(S,Prev). +multi_match((S,Ss),Prev,X) :- match(S,X), \+member(S,Prev), multi_match(Ss,[S|Prev],X). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/kern_analysis.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/kern_analysis.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,267 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(kern_analysis, []). + +:- use_module(library(kerndata)). +:- use_module(library(grammars)). +:- use_module(library(compression)). +:- use_module(library(swipe)). + +grammars:dataset_sequences(DS,Seqs) :- + kerndata:dataset_sequences(DS,Seqs). + + + +write_dataset_sequences(DS) :- + dataset_sequences(DS,SS), + with_stream_encoding(current_output,octet, + maplist(write_seq(notenums),SS)). + +write_dataset(Prep,DS) :- + dataset_sequences(DS,SS), + with_stream_encoding(current_output,octet, + maplist(write_seq(Prep),SS)). + +write_item(Prep,Item) :- + item_sequence(Item,Sequence), + write_seq(Prep,Sequence). + +write_seq(notenums,NS) :- + write_bytes(NS), + write_bytes([255]). + +write_seq(intervals,NS) :- + nth1(1,NS,N1), + nnums_ivals(NS,IS), + append(IS2,[end],IS), + maplist(plus(127),IS2,CS), + write_bytes([N1|CS]), + write_bytes([255]). + +ds_complexity(Method,Prep,DS,K) :- + complexity(Method, + write_dataset(Prep,DS), + K). + +ds_conditional_complexity(Method,Prep,Ref,DS,K) :- + conditional_complexity(Method, + write_dataset(Prep,Ref), + write_dataset(Prep,DS), + K). + +% ds_mutual_information(Method,Prep,DS1,DS2,I) :- +% mutual_information(Method, +% write_dataset(Prep,DS1), +% write_dataset(Prep,DS2), +% I). + +arg_min(K-Meth,Goal,KMin-Best) :- + aggregate_all(min(K,Meth),(Goal,Meth\=naive(_,_)),min(KMin,Best)). + +:- use_module(library(lambda)). +:- use_module(library(mlserver)). +:- use_module(library(uri)). + +exp(conditioning_scat(DS,Prep,Ref)) :- + dataset_items(DS,Items), + findall([KMin,CKMin], + ( member(I,Items), + min_complexity(_,write_item(Prep,I),KMin), + min_conditional_complexity(_,write_dataset(Prep,Ref), + write_item(Prep,I),CKMin) + ), XX), + ??scat(transpose(arr(XX))), + ??xlabel(q(complexity)), + ??ylabel(q('conditional complexity')). + +exp(relative_erasure(DS,Prep)) :- + dataset_items(DS,Items), + findall(CKRel, + ( select(I,Items,Rest), + min_complexity(_,write_item(Prep,I),KMin), + min_conditional_complexity(_,maplist(write_item(Prep),Rest), + write_item(Prep,I),CKMin), + CKRel is 1- CKMin/KMin + ), XX), + ??barh(XX), + ??xlabel(q('1 - relative erasure complexity')), + item_yticks(Items). + +exp(odd_one_out(Prep,DS,DS2,N)) :- + dataset_items(DS,Items), + dataset_items(DS2,Items2), + nth1(N,Items2,OddBall), + AllItems=[OddBall|Items], + findall(CKRel, + ( select(I,AllItems,Rest), + min_complexity(_,write_item(Prep,I),KMin), + min_conditional_complexity(_,maplist(write_item(Prep),Rest), + write_item(Prep,I),CKMin), + CKRel is 1 - CKMin/KMin + ), XX), + ??barh(XX), + ??xlabel(q('1 - relative erasure complexity')), + item_yticks(AllItems). + +exp(erasure(DS,Prep)) :- + dataset_items(DS,Items), + findall([KMin,CKMin], + ( select(I,Items,Rest), + min_complexity(_,write_item(Prep,I),KMin), + min_conditional_complexity(_,maplist(write_item(Prep),Rest), + write_item(Prep,I),CKMin) + ), XX), + ??barh(transpose(arr(XX))), + ??legend(cell([q(isolated),q(erasure)])), + ??xlabel(q(bits)), + item_yticks(Items). + +exp(compressibility(DS,Prep,Ref)) :- + dataset_items(DS,Items), + findall([CKMin,KMin], + ( member(I,Items), + % complexity(id,write_item(Prep,I),L), + min_complexity(_,write_item(Prep,I),KMin), + min_conditional_complexity(_,write_dataset(Prep,Ref), + write_item(Prep,I),CKMin) + % arg_min(K-C, conditional_complexity(naive(C),write_dataset(Prep,Ref), + % write_item(Prep,I),K), NCK-_) + ), XX), + ??barh(transpose(arr(XX))), + item_yticks(Items), + ??xlabel(q(bits)), + ??legend(cell([q('delta compressed'),q(compressed)])). + +exp(info_density(DS,Prep,Ref)) :- + dataset_items(DS,Items), + findall([H,HRef], + ( member(I,Items), + item_sequence(I,Pitches), + length(Pitches,L), + min_complexity(_,write_item(Prep,I),KMin), + min_conditional_complexity(_,write_dataset(Prep,Ref), + write_item(Prep,I),CKMin), + H is KMin/L, + HRef is CKMin/L + ), XX), + ??barh(transpose(arr(XX))), + ??legend(cell([q(isolated),q(conditional)])), + ??xlabel(q('bits per note')), + item_yticks(Items). + +exp(ds_similarity_matrix(Prep,Meth,Datasets)) :- + ncd_matrix(ncd(Meth), write_dataset(Prep), Datasets, Matrix), + ncd_image(Matrix), + yticks(Datasets). + +exp(similarity_matrix(Prep,Meth,DS)) :- + dataset_items(DS,Items), + ncd_matrix(ncd(Meth), write_item(Prep), Items, Matrix), + ncd_image(Matrix), + item_yticks(Items). + +exp(conditional_similarity_matrix(Prep,Method,DS,Ref)) :- + dataset_items(DS,Items), + ncd_matrix(conditional_ncd(Method,write_dataset(Prep,Ref)), write_item(Prep), Items, Matrix), + ncd_image(Matrix), + item_yticks(Items). + +exp(ds_conditional_similarity_matrix(Prep,Method,Datasets,Ref)) :- + ncd_matrix(conditional_ncd(Method,write_dataset(Prep,Ref)), write_dataset(Prep), Datasets, Matrix), + ncd_image(Matrix), + yticks(Datasets). + +ncd_image(Matrix) :- ??imagesc(1-arr(Matrix)), ??colorbar. + +ncd_matrix(Sim,Writer,Items,Matrix) :- + length(Items,N), + numlist(1,N,IX), + maplist(ncd_matrix_column(Sim,Writer,Items,IX),IX,Matrix). + +ncd_matrix_column(Sim,Writer,Items,JX,I,Column) :- + maplist(ncd_matrix_entry(Sim,Writer,Items,I),JX,Column). + +ncd_matrix_entry(Sim,Writer,Items,I,J,D) :- + ( I=J -> D=nan + ; nth1(I,Items,XI), + nth1(J,Items,XJ), + call(Sim, call(Writer,XI), call(Writer,XJ), D) + ). + +item_yticks(Items) :- + length(Items,NumItems), + maplist(item_label,Items,Labels), + ??yticks(1:NumItems,cell(Labels)). + +item_label(Item,q(Name)) :- + item_uri(Item,URI), + uri_components(URI,Components), + uri_data(path,Components,Path), + directory_file_path(_,File,Path), + file_name_extension(Name,_,File). + +printfig(W,H,Name) :- + format(atom(Path),'/Users/samer/pubs/asymmus/workshop/figs/~w.eps',[Name]), + format(atom(Cmd),'epstopdf ~w',[Path]), + ??fsetup(W,H,q(centimeters)), + ??print(q('-depsc2'),q(Path)), + shell(Cmd). + +plot_method_rankings :- + setof( r(MeanRank,Method,Ranks), + ( compression:method_rankings(Method,Ranks), + mean_list(Ranks,MeanRank)), + Results), + ??newplot, + ??hold(q(on)), + forall( nth1(I,Results,r(_,_,Ranks)), + ??plot(Ranks,I+0.7*(rand(size(Ranks))-0.5),q('.'))), + ??hold(q(off)), + maplist(result_method,Results,Methods), + yticks(Methods). + +result_method(r(_,Method,_),Method). + +yticks(Terms) :- + length(Terms,N), + maplist(term_label,Terms,Labels), + ??yticks(1:N,cell(Labels)). + +term_label(Term,q(Label)) :- format(atom(Label),'~w',[Term]). + + +mean_list(L,Mean) :- + length(L,N), + sumlist(L,Sum), + Mean is Sum/N. + + +% pairwise(DS,Matrix) :- +% dataset_items(DS,Items), +% maplist(\I1^maplist(\I2^conditional_complexity( + + +% rnd_state(T) :- get_rnd_state(S), rnd_state_term(S,T). + +% with_sample(T,RV,Pred) :- +% rnd_state_term(S1,T), +% sample(RV,X,S1,S2), +% set_rnd_state(S2), +% call(Pred,X). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/kerndata.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/kerndata.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,442 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(kerndata, + [ uri_spine_pitches/3 + , uri_spine_events/4 + , uri_opus/2 + , events_nth_phrase/3 + , dataset_size/2 + , dataset_items/2 + , dataset_sequences/2 + , dataset_random_subsets/4 + , item_sequence/2 + , item_opus/2 + , item_uri/2 + , metpos/4 + , with_kern_module/3 + , fileset/1 + ]). + +/** Managings sets of Kern scores + + This module provides tools for defining and working with sets of musical + fragments extracted from Humdrum/Kern scores. Sets of files are defined by + searches in the RDF database. Then, a small language of operations can be + used to extract given spines and/or break melodic sequences into phrases. + + A named fileset is a term (the name) associated with a file set specification. + A fileset specification is a nondeterministic binary predicate which yields + both a Humdrum file URI and a spine number. An alternative way to refer to a + file set is anonymously, as a term \Spec. A fileset, then is either a named + fileset or an anonymous fileset: + == + anonymous_filset ---> \fileset_spec. + fileset_spec == pred(-uri, -spine_spec). + named_fileset == term. + fileset == named_fileset | anonymous_fileset. + spine == natural. % {1,2,...} + + spine_spec ---> extract(spine) + ; trace(spine) + ; merge + ; all. + == + Named filesets are defined using the multifile predicate fileset/2. + + Some predicates are available for convenient construction of fileset_specs: + == + with_spine( +S:spine, +Finder:pred(-uri), -URI:uri, -S:spine_spec) is nondet. + trace_spine( +S:spine, +Finder:pred(-uri), -URI:uri, -S:spine_spec) is nondet. + merge_spines( +Finder:pred(-uri), -URI:uri, -S:spine_spec) is nondet. + all_spines( +Finder:pred(-uri), -URI:uri, -S:spine_spec) is nondet. + + kern_uri( +FS:find_spec, -URI:uri) is nondet. + + find_spec ---> (find_spec ; find_spec) % set union + ; (find_spec , find_spec) % set intersection + ; under(path) % recursive directory search + ; in(path) % single directory search + ; uri=object. % match on RDF property + + path == atom. % a path relative to root of Humdrum file library. + object == uri | literal | literal_search_spec. + + literal == { lang(atom,atom), type(uri,atom) } | atom. + literal_search_spec ---> literal(literal_query,atom). + literal_query ---> plain(atom) + ; exact(atom) + ; substring(atom) + ; word(atom) + ; prefix(atom) + ; ge(atom) + ; le(atom) + ; between(atom,atom) + ; like(atom). + == + Thus, as a fileset_spec, the term =|with_spine(S,Finder)|= yields the Sth spine + of each URI produced by Finder. =|all_spines(Finder)|= yields all spines of each file + produced by Finder. See rdf/3 for more information about literal query terms. + + Datasets are defined in terms of filesets: + == + fileset :< dataset. % any fileset is also a dataset: each member yields one sequence + phrases(fileset) :< dataset. % denotes the set of phrases segmented from fileset. + extract(DS:dataset, Size:nonneg, Offset:nonneg) :: dataset. + subset(DS:dataset, Size:nonneg, Indices:list(nonneg)) :: dataset. + subset_ref(DS:dataset, Size:nonneg, SubsetRef:atom) :: dataset. + null :: dataset. + == + + Each item in a dataset is represented by a term of the following type: + == + dataset_item ---> whole(uri,spine) % Humdrum URI and spine number + ; phrase(uri,spine,natural). % URI, spine and phrase number + ; merged(uri). % all spines, highest note of chords + == + Items can be obtained using dataset_items/2. + Each item corresponds to a list of note numbers, which can be obtained using + item_sequence/2, or dataset_sequences/2. + +*/ + +:- meta_predicate with_kern_module(+,-,0). + +:- use_module(library(memo)). +:- use_module(library(dcg_core)). +:- use_module(library(snobol)). +:- use_module(library(listutils)). +:- use_module(library(fileutils)). +:- use_module(library(termutils)). +:- use_module(library(insist)). +:- use_module(library(humdrum)). +:- use_module(library(humdrum/kern)). +:- use_module(library(humdrum/dynam)). +:- use_module(library(humdrum/humdrum_world)). +:- use_module(library(humdrum/kernutils)). +:- use_module(library(lambda)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(humdrum_p2r), [hum_uri_path/2]). +:- use_module(library(dataset), [random_subset/4]). + +:- set_prolog_flag(double_quotes, codes). +:- initialization memo_attach(memo(kerndata),[]). + +:- dynamic item_sequence/2. +:- multifile fileset/2. + +%% fileset(-FS:named_fileset) is nondet. +% True when FS identifies an explicitly declared Kern file-set. +fileset(FS) :- fileset(FS,Spec), FS \= \Spec. + +%% fileset(+FS:named_fileset, -Spec:fileset_spec) is semidet. +%% fileset(-FS:named_fileset, -Spec:fileset_spec) is nondet. +% +% Database of named filesets and their fileset specifiers. +fileset(lorraine, with_spine(1,kern_uri(in('lorraine')))). +fileset(nova_scotia, with_spine(1,kern_uri(in('classical/songs/unaccompanied/nova-scotia/kern')))). +fileset(ireland, with_spine(1,kern_uri(in('ireland')))). +fileset(chorales, with_spine(1,kern_uri(in('classical/bach/chorales')))). +fileset(chorales371, with_spine(4,kern_uri(in('classical/bach/371chorales')))). +fileset(bach_cello, with_spec(merge,kern_uri(in('classical/bach/cello')))). +fileset(bach_violin, with_spec(merge,kern_uri(in('classical/bach/violin')))). +fileset(beethoven_quartets, all_spines(kern_uri(in('classical/beethoven/quartet')))). +fileset(essen, with_spine(1,kern_uri(under('essen/europe')))). +fileset(essen(china),with_spine(1,kern_uri(under('essen/china')))). +fileset(essen(Rgn), with_spine(1,kern_uri(under(Dir)))) :- + member(Rgn,[germany,rossiya,magyar,elsass,lothring,nederlan,schweiz,oesterrh,jugoslav]), + atom_concat('essen/europe/',Rgn,Dir). +fileset(essen(germany,Sub), with_spine(1,kern_uri(under(Dir)))) :- + member(Sub,[dva,allerkbd,kinder,altdeu1,altdeu2,fink,zuccal,ballad,boehme,erk]), + atom_concat('essen/europe/germany/',Sub,Dir). + + +%% uri_opus(+URI:uri,-Opus:atom) is semidet. +%% uri_opus(-URI:uri,-Opus:atom) is nondet. +% Relation between Humdrum file URIs and their Humdrum SCT property. +uri_opus(URI,Opus) :- rdf(URI,hum:'refcode/SCT',literal(Opus)). + +% :- volatile_memo file_opus( +file:atom, -opus:atom). +% file_opus(File,Opus) :- +% with_kern_module(File, utf8, Mod, (Mod:ref('SCT',_,Opus) -> true; Opus=unknown(_))). + +%% item_opus(+Item:dataset_item, -Opus:atom) is semidet. +% Relation between a dataset item and the opus of its associated Humdrum file. +item_opus(Item,Opus) :- item_uri(Item,URI), uri_opus(URI,Opus). + +%% item_uri(+Item:dataset_item, -URI:uri) is semidet. +% Relation between a dataset item and the URI of its associated Humdrum file. +item_uri(phrase(URI,_,_),URI). +item_uri(whole(URI,_),URI). +item_uri(merged(URI),URI). + + +%% dataset_size(+DS:dataset, -N:nonneg) is det. +% Get the size of a given dataset. This predicate is persistently memoised, +% since computing the size of a large dataset may involve reading many Humdrum +% files. + +:- persistent_memo dataset_size( +ground, -nonneg). + +dataset_size(Dataset,NumItems) :- + eval_dataset(Dataset,Items), + length(Items,NumItems). + +%% dataset_items(+DS:dataset, -S:list(dataset_item)) is det. +dataset_items(DS,Items) :- eval_dataset(DS,Items). + +%% dataset_sequences(+DS:dataset, -S:list(list(integer))) is det. +dataset_sequences(DS,SS) :- + dataset_items(DS,Items), + maplist(item_sequence,Items,SS). + +%% eval_dataset(+DS:dataset, -Items:list(dataset_item)) is det. +eval_dataset(DS,_) :- must_be(ground,DS), fail. +eval_dataset(extract(DS,N,I), D2) :- !, + eval_dataset(DS, D1), + drop(I, D1, D3), + take(N, D3, D2). + +eval_dataset(subset_ref(DS,N,Ref), D2) :- !, + dataset_size(DS,Size), + random_subset(Size,N,Ref,IX), + eval_dataset(subset(DS,N,IX), D2). + +eval_dataset(subset(DS,N,IX), D2) :- !, + eval_dataset(DS, D1), + length(IX,N), + maplist(\I^X^nth1(I,D1,X), IX, D2). + +eval_dataset(null,[]). +eval_dataset(DS,Items) :- + fileset_items(DS,Items). + +:- thread_local item_/1. +:- volatile_memo fileset_items( +ds:ground, -items:list(ground)). +%% fileset_items(+FS, -Items:list(dataset_item)) is det. +% FS can be a fileset or a term =|phrases(Fileset)|=, denoting the set of +% sequence resulting from segmenting each item in Fileset into phrases. +fileset_items(DS, Items) :- + setup_call_cleanup( + load(DS), + findall(Item,item_(Item),Items), + retractall(item_(_))), + insist(Items\=[]). + +load(phrases(FS)) :- fileset(FS,Spec), forall_kern(Spec,assert_phrases). +load(FS) :- fileset(FS,Spec), forall_kern(Spec,assert_whole). + +%% item_sequence(+Item:dataset_item, -Seq:list(integer)) is det. +% True when Seq is the list of note numbers for a given item. + +%% spine_nth_phrase(+Mod:module,+S:spine,-N:natural,-P:list(integer)) is nondet. +% +% True when P is the list of note numbers in the Nth phrase on spine S in the +% Humdrum file represented in module Mod. Phrases can be defined in two ways: +% 1. Using explicit Kern phrase marks +% 2. Using notes annotated with a pause mark to determine phrase endings. +spine_nth_phrase(Mod,Spine,N,Phrase) :- + Mod:spine(Spine), + ( once(spine_phrase(Mod,Spine,_,_)) + -> % spine has explicit phrases markings + kern_get_events(event_or_delim(spine_notenum,Mod,Spine), Events), + pairs_values(Events,Events1), + bagof(NNs, L^phrase(contains_group(L,NNs),Events1), Phrases), + nth1(N,Phrases,Phrase) + ; % no phrase markings - use pauses + kern_get_events(event_or_pause(spine_notenum,Mod,Spine), Events), + events_nth_phrase(Events, N, Phrase) + ). + +assert_whole(URI,Mod,Spec) :- + (Spec=extract(Spine); Spec=all), + forall( kern_get_events(spine_notenum(Mod,Spine), Events), + ( assert_id(item_sequence(whole(URI,Spine), Events)), + assert(item_(whole(URI,Spine))))). + +assert_whole(URI,Mod,merge) :- + forall( kern_get_events(top_notenum(Mod), Events), + ( assert_id(item_sequence(merged(URI), Events)), + assert(item_(merged(URI))))). + +assert_phrases(URI,Mod,Spec) :- + (Spec=extract(Spine); Spec=all), + forall( spine_nth_phrase(Mod,Spine,N,Phrase), + ( assert_id(item_sequence(phrase(URI,Spine,N), Phrase)), + assert(item_(phrase(URI,Spine,N))))). + +assert_id(Fact) :- call(Fact) -> true; assert(Fact). + + +contains_group(D,XX) --> arb, group(D,XX,[]), rem. + +group(D,X1,X2) --> + delimiter(D,open), + iterate(content(D),X1,X2), + delimiter(D,close). + +content(_,[X|XX],XX) --> [event(X)]. +content(D,XX,XX) --> {dif(D,D1)}, delimiter(D1,_). +content(D,X1,X2) --> group(D,X1,X2). +delimiter(D,T) --> [T/D]. + + +%% dataset_random_subsets(+DS:dataset,+K:nonneg,+L:nonneg,-DSX:list(dataset)) is det. +% +% Returns L random subsets of K sequences each from dataset DS. +% K is the size of each random subset. L is the number of subsets +% returned. Each subset is a term of the form =|subset(DS,K,Indices)|=. +dataset_random_subsets(DS,K,L,DSX) :- + dataset_size(DS,N), + numlist(1,L,SubsetIndices), + maplist(\I^subset(DS,K,S)^random_subset(N,K,I,S),SubsetIndices,DSX). + + +%% uri_spine_pitches(+URI:uri,+S:nonneg,-P:list(pitch)) is det. +%% uri_spine_pitches(+URI:uri,-S:nonneg,-P:list(pitch)) is nondet. +% +% True when Pis a list of the pitches of notes in a spine S +% of the Humdrum file pointed to by URI. +uri_spine_pitches(URI,Spine,Pitches) :- + with_kern_module(URI, Mod, + kern_get_events(spine_pitch(Mod,Spine), Pitches)). + +%% uri_spine_events(+URI:uri,+G:getter,+S:spine,-E:list(event(A))) is det. +%% uri_spine_events(+URI:uri,+G:getter,-S:spine,-E:list(event(A))) is nondet. +% +% Get list of events from a given spine in a Humdrum file. The kind of events extracted +% depends on the getter predicate G, which must be of type: +% == +% getter(A) == pred(+M:module,-S:spine,-T:time,-E:event(A)). +% event(A) ---> event(A) ; pause. +% == + +uri_spine_events(URI,Getter,Spine,Events) :- + with_kern_module(URI, Mod, + kern_get_events(event_or_pause(Getter,Mod,Spine), Events)). + +:- meta_predicate forall_kern(2,3). +forall_kern(Findspec,Pred) :- + with_status_line( + forall( call(Findspec,URI,SpineSpec), ( + status('Loading: ~s',[URI]), + with_kern_module(URI, Mod, call(Pred,URI,Mod,SpineSpec)) + ))), + format('Finished loading.\n',[]). + +%% with_kern_module(+URI:uri, -M:module, +Goal:pred) is nondet. +% +% Calls Goal with M set to the name of a temporary moduling containing +% the information in the Kern file specified by URI. +with_kern_module(URI,Mod,Goal) :- + hum_uri_path(URI,Path), + with_kern_module(Path,utf8,Mod,Goal). + +:- meta_predicate with_spine(+,1,-,-). +with_spine(Spine,Finder,URI,extract(Spine)) :- call(Finder,URI). + +:- meta_predicate all_spines(+,-,-). +all_spines(Finder,URI,all) :- call(Finder,URI). + +:- meta_predicate with_spec(+,+,-,-). +with_spec(SpineSpec,Finder,URI,SpineSpec) :- call(Finder,URI). + +%% kern_uri(+FS:find_spec, -URI:uri) is nondet. +% +% True when URI refers to a Humdrum file that satisfies the given +% specification. The specification type =|find_spec|= is defined in the +% module header comment. +kern_uri(in(Dir),URI) :- rdf(URI,hum:directory,literal(Dir)). +kern_uri(under(Dir),URI) :- rdf(URI,hum:directory,literal(prefix(Dir),_)). +kern_uri(A;B, URI) :- kern_uri(A,URI); kern_uri(B,URI). +kern_uri((A,B), URI) :- kern_uri(A,URI), kern_uri(B,URI). +kern_uri(Prop=Val,URI) :- rdf(URI,Prop,Val). + +%% spine_pitch(+Mod:module,-Spine:nonneg,-Time,-Pitch) is nondet. +spine_pitch(Mod,Spine,Time,P) :- + Mod:note(pitch(P),_,Time,Spine). + +spine_pitch_dur(Mod,Spine,Time,P-D) :- + Mod:note(pitch(P),D,Time,Spine). + +spine_notenum(Mod,Spine,Time,NN) :- + spine_pitch(Mod,Spine,Time,Pitch), + pitch_notenum(Pitch,NN). + + +%% get the highest pitch over all spines at each time slice. +top_notenum(Mod,Time,TopNN) :- + aggregate(max(NN),time_notenum(Mod,Time,NN),TopNN). + +time_notenum(Mod,Time,NN) :- + Mod:note(pitch(P),_,Time,_), + pitch_notenum(P,NN). + +spine_pause(Mod,Spine,Time,pause) :- spine_pause(Mod,Spine,Time). +spine_pause(Mod,Spine,Time) :- + Mod:articulation(pause,Spine,Rec), + Mod:time(T,Rec), + Mod:duration(D,Rec), + Time is T+D. + +spine_phrase(Mod,Spine,Time,Time-(OpenClose/Label)) :- + Mod:data(tok(Toks),Spine,Rec), + member(par(OpenClose,phrase-Label),Toks), + Mod:time(T,Rec), + ( OpenClose=open -> Time=T + ; OpenClose=close -> Mod:duration(D,Rec), Time is T+D + ). + + +twos(L) :- L=[2|L]. + +metre(4/4,1:M) :- twos(M). +metre(3/4,(3 rdiv 4):[3,2|M]) :- twos(M). +metre(6/8,(3 rdiv 4):[2,3|M]) :- twos(M). +metre(9/8,(9 rdiv 8):[3,3|M]) :- twos(M). +metre(12/8,(12 rdiv 8):[2,2,3|M]) :- twos(M). + +%% metpos( +Bar:rational, +Metre:list(nat), +T0:rational, -R:nat) is det. +metpos(Bar,Metre,TT,R) :- metpos_(TT,[1/Bar|Metre],0,R). + +metpos_(0,_,R,R) :- !. +metpos_(T0,[M0|MX],R0,R) :- + mod1(T0*M0,T1), succ(R0,R1), + metpos_(T1,MX,R1,R). + +mod1(X,Y) :- Z is floor(X), Y is X - Z. + +event_or_pause(Pred,Mod,Spine,Time,event(X)) :- call(Pred,Mod,Spine,Time,X). +event_or_pause(_,Mod,Spine,Time,pause) :- spine_pause(Mod,Spine,Time). + +event_or_delim(Pred,Mod,Spine,Time,2-event(X)) :- + call(Pred,Mod,Spine,Time,X). +event_or_delim(_,Mod,Spine,Time,Prio-Delim) :- + spine_phrase(Mod,Spine,Time,_-Delim), + delim_prio(Delim,Prio). + +delim_prio(open/_,1). +delim_prio(close/_,1). + +%% events_nth_phrase(+Events:list(event(A)), +N:natural, -P:list(A)) is det. +% Extract Nth phrase from a list of events or pauses. +events_nth_phrase(Events,N,Phrase) :- + phrase((seqmap_with_sep([pause],seqmap(event),Phrases), opt([pause])),Events,[]), + nth1(N,Phrases,Phrase). + +event(X) --> [event(X)]. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/mazurka_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/mazurka_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,115 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(mazurka_p2r, []). + +/** Access to beets database + */ + + +% :- use_module(library(odbc)). +:- use_module(library(csv)). +:- use_module(library(musicbrainz)). +:- use_module(library(semweb/rdf_db)). +:- use_module(library(termutils)). +:- use_module(library(rdfutils)). +:- use_module(library(stringutils)). +:- use_module(library(dcg/basics)). +:- use_module(entailment(p2r)). +:- use_module(library(memo)). + +:- set_prolog_flag(double_quotes,string). + +:- rdf_register_prefix(mazurka,'http://dml.org/mazurka/'). + +:- setting(csv_database,string,"~/lib/mazurka/mazurka-discography.txt","Location of Mazurka tab-separated-values"). +:- setting(audio_root,ground,nothing,"Location of Mazurka audio files"). + +% :- rdf_meta convert(+,+,o). +% convert(string,X,literal(X)). +% convert(atom,X,literal(Y)) :- atom_string(Y,X). +% convert(number,X,literal(Y)) :- number_string(Y,X). +% convert(date(E),X,literal(Date)) :- string_to_date(E,X,Date). + +rdf(mazurka:title, rdfs:subPropertyOf, dc:title) <== true. +rdf(mazurka:enc(Id), Prop, Obj) <== + setting(csv_database,Pattern), + expand_file_name(Pattern,[DBFile]), + csv_to_rdf(DBFile,Id,Prop,Obj). + +csv_to_rdf(DBFile,Id,Prop,Obj) :- + once(csv_read_file_row(DBFile,Header,[convert(false),separator(0'\t), line(1)])), + functor(Header,row,NumCols), + functor(Row,row,NumCols), + row_field(Header-Row,pid,Id), + csv_read_file_row(DBFile,Row,[convert(false),separator(0'\t), line(L)]), L>1, + status("Importing mazurka: ~w",[Id]), + row_triple(Header-Row,Prop,Obj). + % rdf_global_object(Obj1,Obj). + +:- rdf_meta row_triple(+,r,o). +row_triple(_,mazurka:composer,literal('Chopin')). +row_triple(HR,mazurka:pid,literal(PID)) :- row_field(HR,pid,PID). +row_triple(HR,Prop,Val) :- + row_field(HR,opus,OpusNum), + row_field(HR,key,Key), + atomic_list_concat([Opus,Number],'.',OpusNum), + work_triple(Key,Opus,Number,Prop,Val). + +row_triple(HR,mazurka:performer,literal(Perf)) :- row_field(HR,performer,Perf). +row_triple(HR,mazurka:recording_date,literal(type(T,Year))) :- row_field(HR,year,Year), rdf_global_id(xsd:gYear,T). +row_triple(HR,mazurka:duration,literal(type(T,X))) :- row_field(HR,seconds,A), atom_number(A,X), rdf_global_id(xsd:int,T). +row_triple(HR,mazurka:label,literal(Label)) :- row_field(HR,label,Label). + +:- rdf_meta work_triple(+,+,+,r,o). +work_triple(K,O,N,mazurka:title,literal(T)) :- format(atom(T),"Mazurka in ~w, op.~w, no.~w",[K,O,N]). +work_triple(K,_,_,mazurka:key,literal(K)). +work_triple(_,O,_,mazurka:opus,literal(O)). +work_triple(_,_,N,mazurka:number,literal(N)). +work_triple(_,O,N,mazurka:score,Score) :- + format(atom(Score),"kern:/classical/chopin/mazurka/mazurka~|~`0t~w~2+-~w.krn",[O,N]). + + +row_field(Header-Row,Name,Value) :- arg(N,Header,Name), arg(N,Row,Value). +% null_value("-"). + +:- public import/0. +import :- assert_all(mazurka_p2r). + +:- public audio_file/3. +audio_file(URI,Path,just(Fmt)) :- + rdf(URI,mazurka:pid,literal(PID)), + rdf(URI,mazurka:opus,literal(Opus)), + rdf(URI,mazurka:number,literal(Number)), + setting(audio_root,just(RootPatt)), + expand_file_name(RootPatt,[Root]), + member(Fmt-Ext,[aac-mp4,wav-wav]), + format(atom(Path),"~w/mazurka~|~`0t~w~2+-~w/pid~w.~w",[Root,Opus,Number,PID,Ext]), + exists_file(Path). + +% audio_link(Type,URI,URL) :- +% member(Type,[mp3,flac]), +% rdf(URI,charm:file_name,literal(Filename)), +% ( sub_atom(Filename,_,_,_,'£') +% -> atom_codes(Filename,C1), +% fix_url(C1,C2), +% atom_codes(Filename2,C2) +% ; Filename2=Filename +% ), +% format(atom(URL),'http://charm.cchcdn.net/audio/~w/~w.~w',[Type,Filename2,Type]). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/memo_p2r.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/memo_p2r.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,88 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(memo_p2r, []). + +:- use_module(library(memo)). +:- use_module(entailment(p2r)). + +uripattern:def( func(Mod,Pred,Arity), dml:function/enc(Mod)/enc(Pred)/num(Arity)). + +% Memoisation schema +:- rdf_register_prefix(memo,'http://dml.org/memo/',[force(true)]). + +:- public import/0. +import :- assert_all(memo_p2r). + +rdf(memo:'Module', rdfs:subClassOf, owl:'Thing'), +rdf(memo:'Function', rdfs:subClassOf, owl:'Thing'), +rdf(memo:'Computation', rdfs:subClassOf, event:'Event'), +rdf(memo:function, rdfs:domain, memo:'Computation'), +rdf(memo:function, rdfs:range, memo:'Function'), +rdf(memo:module, rdfs:domain, memo:'Function'), +rdf(memo:module, rdfs:range, memo:'Module'), +rdf(time:duration, rdfs:domain, event:'Event'), +rdf(time:duration, rdfs:range, xsd:decimal), +rdf(memo:type, rdfs:domain, memo:'Function') <== true. +rdf(memo:storage, rdfs:domain, memo:'Function') <== true. + +rdf(dml: module/prolog/enc(Mod), rdf:type, memo:'Module'), +rdf(\func(Mod,Pred,Arity), rdf:type, memo:'Function'), +rdf(\func(Mod,Pred,Arity), memo:module, dml:module/prolog/enc(Mod)) <== + memo_function(Mod,Pred,Arity). + +rdf(\func(Mod,Pred,Arity), rdfs:label, literal(Label)) <== + memo_function(Mod,Pred,Arity), + term_to_atom(Pred/Arity,Label). + +rdf(\func(Mod,Pred,Arity), memo:type, literal(TypeAtom)) <== + memo_property(Mod:Head,type(Type)), + functor(Head,Pred,Arity), + Type =.. [_|Types], + term_to_atom(Types,TypeAtom). + +rdf(\func(Mod,Pred,Arity), memo:storage, literal(Storage)) <== + memo_property(Mod:Head,storage(Storage)), + functor(Head,Pred,Arity). + +% alternative duration type is xsd:duration, +% format as 'PT~fS' +% rdf(dml:computation/enc(Hash), rdf:type, memo:'Computation'), + +% REMOVE COMPUTATIONS FOR NOW +% rdf(dml:computation/enc(Hash), time:duration, literal(type(xsd:double,Dur))), +% rdf(dml:computation/enc(Hash), memo:status, literal(StatusAtom)), +% rdf(dml:computation/enc(Hash), memo:function, \func(Mod,Pred,Arity)) <== +% memo:computer(Mod,Head,_,_), +% memo:browse(Mod:Head,Ev-Status), +% variant_sha1(t(Mod,Head,Ev,Status),Hash), +% (Ev=comp(_,_,Dur); Ev=comp(_,Dur)), % for time:duration +% term_to_atom(Status,StatusAtom), % for memo:status +% functor(Head,Pred,Arity). % for memo:function + +% rdf(dml:computation/enc(Hash), memo:host, literal(Host)) <== +% memo:computer(Mod,Head,_,_), +% memo:browse(Mod:Head,Ev-Status), +% variant_sha1(t(Mod,Head,Ev,Status),Hash), +% (Ev=comp(Host,_,_); Ev=comp(Host,_)), +% Host\='unknown'. + +memo_function(Mod,Pred,Arity) :- + memo_property(Mod:Head,storage(_)), + functor(Head,Pred,Arity). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/mlfigs.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/mlfigs.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,75 @@ +:- module(mlfigs, [ml_fig/6, ml_fig/5,ml_post/3, ml_opts/3]). + +%:- use_module(library(dcg_core)). +:- use_module(library(dcg_pair)). +:- use_module(library(computations),[unzip/3, (*)/4]). +:- use_module(library(mlserver)). +:- use_module(library(optutils)). + +% ------- tools for building matlab charts ------- +ml_fig(Type,XL,YL,Datasets,F) :- ml_fig(Type,XL,YL,Datasets,[],F). +ml_fig(Type,XL,YL,Datasets,Opts,fig(Code;xlabel(q(XL));ylabel(q(YL)),Opts1)) :- + unzip(Datasets,Names,Data), + maplist(term_to_atom*atom_string,Names,Labels), + compile(Type,Labels,Data,Opts,Opts1,Cmds,[]), + sequence(Cmds,Code). + +ml_post(Code,fig(Code0),fig(Code0;Code)). +ml_post(Code,fig(Code0,O),fig(Code0;Code,O)). +ml_opts(Opts,fig(Code),fig(Code,Opts)). +ml_opts(Opts,fig(Code,Opts0), fig(Code,Opts1)) :- + merge_options(Opts,Opts0,Opts1). + + +compile(T,Names,Data,Opts,Opts1) --> + plot(T,Data), + {option_default_select(legend(Pos),best,Opts,Opts1)}, + [box("off"), set(gca,"TickDir","out")], + ( {Pos=off} -> [] + ; [legend(cell(Names),"Location",q(Pos), + "LineWidth",0.25*get(gcf,"DefaultAxesLineWidth"))] + ). + +sequence([C],C) :- !. +sequence([C1|Cs],C1;Ss) :- sequence(Cs,Ss). + +pairs_to_cell(Pairs,{X,Y}) :- unzip(Pairs,X,Y). + +plot(bars,Data) --> plot(bars(grouped),Data). +plot(bars(Arr),Data) --> plot(multi((x,y,varargin)\\bar(x,y,q(Arr),"EdgeColor","none",cref(varargin,[':']))),Data). +plot(areas,Data) --> plot(multi(@area),Data). +plot(multi(Fn),Data) --> + {length(Data,L)}, + {maplist(pairs_to_cell,Data,Cells)}, + [multibar(Fn,cell(Cells)),caxis([1,L+1])]. +plot(scat(T,Ms),Points) --> + hold(run_left(foldl(scat(T,Ms),Points),0,N)), + [caxis([1,N+1])]. +plot(lines,Points) --> + {length(Points,N)}, + hold(run_left(foldl(line(N),Points),0,_)). + +scat(o,Ms,Points) --> + \< (succ, dcg_core:get(N)), + {unzip(Points,X,Y), length(Points,L), nth1(N,Ms,M)}, + \> [scatter(X,Y,get(gcf,"DefaultLineMarkerSize").^2,repmat(N,L,1),M)]. +scat(f,Ms,Points) --> + \< (succ, dcg_core:get(N)), + {unzip(Points,X,Y), length(Points,L), nth1(N,Ms,M)}, + \> [scatter(X,Y,get(gcf,"DefaultLineMarkerSize").^2,repmat(N,L,1),M,"filled")]. + +scat(p,Ms,Points) --> + \< (succ, dcg_core:get(N)), {marker(N,M)}, + {unzip(Points,X,Y)}, + {nth1(N,Ms,M)}, + \> [scat(arr([X,Y]),"marker",M)]. + +line(N,Xs-Ys) --> + \< (succ, dcg_core:get(I)), + \> [plot(Xs,Ys,"-","Color",row(get(gcf,"Colormap"),floor(I/N)))]. + +marker(N,M) :- + I is N mod 5, + nth0(I,["r.","g.","c.","b.","m."],M). + +hold(G) --> [newplot,hold("on")], phrase(G), [hold("off")]. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/musiclab.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/musiclab.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,80 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(musiclab, + [ kern_pc_hist/2 + , pitch_class/2 + , pitch_class_number/2 + , pc_number_name/2 + ]). + +:- use_module(library(persistency)). + +:- use_module(library(humdrum)). +:- use_module(library(humdrum/kern)). +:- use_module(library(humdrum/kernutils)). +:- use_module(library(humdrum/dynam)). +:- use_module(library(humdrum/humdrum_world)). +:- use_module(library(typedef)). +:- use_module(library(memo)). + +:- type pitch_class ---> a ; b ; c ; d ; e ; f ; g ; sharp(pitch_class) ; flat(pitch_class). + +:- volatile_memo kern_pc_hist(+path:ground, -hist:list(pair(pitch_class,nonneg))). + +% ------------ reading kern ---------------- + +pitch_class_number(sharp(PC),N) :- !, pitch_class_number(PC,M), N is (M+1) mod 12. +pitch_class_number(flat(PC),N) :- !, pitch_class_number(PC,M), N is (M-1) mod 12. +pitch_class_number(c,0). +pitch_class_number(d,2). +pitch_class_number(e,4). +pitch_class_number(f,5). +pitch_class_number(g,7). +pitch_class_number(a,9). +pitch_class_number(b,11). + +kern_pc_hist(Path,Hist) :- + with_kern_module(Path,utf8,M,findall(PC-N,aggregate(count,mod_note_pc(M,PC),N),Hist)). + +% pc_hist_to_num(Hist1,Hist2) :- +% findall(PCN-X, (member(PC-X,Hist1), pitch_class_number(PC,PCN)), Hist2), +% numlist(0,11,PCNs), +% maplist(pc_number_name,PCNs,PCNames), +% maplist(\PCN^Count^(member(PCN-Count,Hist2) -> true; Count=0),PCNs,Counts), + + +mod_note_pc(M,PC) :- + M:note(pitch(P),_,_,_), + pitch_class(P,PC). + +pc_number_name(0,"c"). +pc_number_name(1,"c#"). +pc_number_name(2,"d"). +pc_number_name(3,"d#"). +pc_number_name(4,"e"). +pc_number_name(5,"f"). +pc_number_name(6,"f#"). +pc_number_name(7,"g"). +pc_number_name(8,"g#"). +pc_number_name(9,"a"). +pc_number_name(10,"a#"). +pc_number_name(11,"b"). + + + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/odbcutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/odbcutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,32 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(odbcutils, [with_odbc/2, qsql/4]). + +:- meta_predicate with_odbc(+,0). +:- use_module(library(odbc)). + +with_odbc(DBName,Goal) :- + setup_call_cleanup( + odbc_connect(DBName,_,[alias(DBName)]), Goal, + odbc_disconnect(DBName)). + +qsql(DB,Fmt,Args,Result) :- !, + format(string(Q),Fmt,Args), + debug(odbcutils,'SQL query: ~s',[Q]), + odbc_query(DB,Q,Result). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/optutils --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/optutils Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,3 @@ +:- module(optutils, [option_default_select/4]). + +option_default_select(Option,Default,O1,O2) :- select_option(Option,O1,O2,Default). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/pengutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/pengutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,50 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(pengutils, + [ write_html/1 + , term_rendering//3 + ]). + +:- meta_predicate write_html(:). + +:- use_module(library(http/html_write)). +:- use_module(library(pengines)). +:- use_module(library(sandbox)). +:- use_module(library(swish/render)). + +:- register_renderer(html,"Render HTML"). + +:- meta_predicate write_html(:). +sandbox:safe_meta(pengutils:write_html(_),[]). + +%% write_html(+HTML) is det. +% Takes HTML elements as accepted by html//1 and outputs +% them to the pengine. +write_html(M:H) :- + debug(pengutils,'write_html(~w)',[M:H]), + html(M:H,Tokens,[]), + with_output_to(string(S),print_html(Tokens)), + debug(pengutils,'write_html output: ~s',[S]), + pengine_output(S). + +term_rendering(html(Stuff),_,Opts) --> + {option(module(M),Opts)}, + {debug(pengutils,'Rendering as HTML: ~q',[Stuff])}, + html(M:Stuff). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/queries.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/queries.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,47 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(queries, + [ with_output_to_pengine/1 + , write_html/1 + ]). + +:- use_module(library(pengines)). +:- use_module(library(http/html_write)). +:- use_module(library(apply_macros)). +:- use_module(library(dcg_core)). + +sandbox:safe_primitive(html_write:print_html(_)). +sandbox:safe_primitive(flush_output). +sandbox:safe_meta(html_write:html(_,_,_),[]). + +:- meta_predicate + with_output_to_pengine(0), + write_html(:). + +with_output_to_pengine(Goal) :- + with_output_to(atom(Reply), in_pre(Goal)), + % catch( Goal, Ex, + % in_pre((message_to_string(Ex,S),format(S))))), + (Reply='' -> true; pengine_output(Reply)). + +write_html(P) :- + html(P,Toks,[]), + print_html(Toks), + flush_output. + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/rdfutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/rdfutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,140 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(rdfutils, + [ rdf_number/3 , rdf_number/4 + , rdf_text/4 , rdf_text/3 + , rdf_search/5, rdf_search/4 + , literal_number/2 + , literal_text/2 + , (a)/2 + , op(700,xfx,a) + , parse_duration_millis/2 + , as_typed_literal/2 + , rdf_list_take/4 + , rdf_list_length/2 + , rdfx/3 + , op(700,xfx,~=) + , (~=)/2 + ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_label)). +:- use_module(library(semweb/rdfs)). + +:- rdf_meta rdf_text(r,r,-), + rdf_text(r,r,-,+), + rdf_number(r,r,-), + rdf_number(r,r,-,+), + rdf_search(+,r,r,+,-), + rdf_search(+,r,r,+), + a(r,r). + +X a Y :- rdfs_individual_of(Y,X). + +rdf_text(S,P,Text) :- rdf(S,P,L), literal_text(L,Text). +rdf_text(S,P,Text,G) :- rdf(S,P,L,G), literal_text(L,Text). + +rdf_number(S,P,Num) :- + ( var(Num) + -> rdf(S,P,literal(Lit)), literal_number(Lit,Num) + ; literal_number(Lit,Num), rdf(S,P,literal(Lit)) + ). + +rdf_number(S,P,Num,G) :- + ( var(Num) + -> rdf(S,P,literal(Lit),G), literal_number(Lit,Num) + ; literal_number(Lit,Num), rdf(S,P,literal(Lit),G) + ). + +literal_number(type(_Type,A),N) :- number(A) -> N=A; atom_number(A,N). +literal_number(Atom,Num) :- atomic(Atom), atom_number(Atom,Num). + +%% rdf_search(+T:match_type,?Subj:uri,?Pred:uri, +Needle:atom, -Val:atom) is nondet. +%% rdf_search(+T:match_type,?Subj:uri,?Pred:uri, +Needle:atom) is nondet. +% Convenience predicate for using rdf/3 with a literal search specifier - this +% version is more amenable for use with maplist and other metapredicates. +% Match types (see rdf/3) are: +% == +% match_type ---> substring; case; prefix; exact; plain; word; like. +% == +rdf_search(T,S,P,X,Y) :- Q=..[T,X], rdf(S,P,literal(Q,Y)). +rdf_search(T,S,P,X) :- rdf_search(T,S,P,X,_). + +% :- rdf_meta type_text_val(r,+,-). +% lit_decode(literal(type(Type,Val)),X) :- type_text_val(Type,Val,X). +% type_text_val(xsd:decimal,V,X) :- atom_number(V,X). +% type_text_val(xsd:integer,V,X) :- atom_number(V,X), must_be(integer,X). + +parse_duration_millis(Atom,Dur) :- + split_string(Atom,':','',Parts), + ( Parts=[HS,MS,SS] + -> number_string(H,HS), + number_string(M,MS), + number_string(S,SS) + ; Parts=[MS,SS] + -> number_string(M,MS), + number_string(S,SS), + H=0 + ), + Dur is 1000*(60*(60*H + M) + S). + +:- rdf_meta xsd_type(+,r). +xsd_type(X,xsd:integer) :- integer(X), !. +xsd_type(X,xsd:double) :- float(X), !. + +as_typed_literal(X,X) :- atom(X), !. +as_typed_literal(X,Y) :- string(X), !, atom_string(Y,X). +as_typed_literal(X,type(Type,X)) :- xsd_type(X,Type). + +:- rdf_meta rdf_list_take(+,r,-,r), + rdf_list_length(r,-). + +rdf_list_take(0,List,[],List) :- !. +rdf_list_take(_,rdf:nil,[],rdf:nil) :- !. +rdf_list_take(N,List,[H|T],Tail) :- + succ(M,N), + rdf(List,rdf:first,H), + rdf(List,rdf:rest,More), + rdf_list_take(M,More,T,Tail). + +rdf_list_length(rdf:nil,0) :- !. +rdf_list_length(List,N) :- + rdf(List,rdf:rest,More), + rdf_list_length(More,M), + succ(M,N). + +X ~= Match :- match(Match,X). +match(Match,literal(O)) :- + must_be(var,O), + ( get_attr(O,rdfutils,match(Matches)) -> true; Matches=[]), + put_attr(O,rdfutils,match([Match|Matches])). + +:- rdf_meta rdfx(r,t,o). +rdfx(S,Q,literal(O)) :- + ( get_attr(O,rdfutils,match(Matches)) + -> maplist(rdf_matches(Q,S,O),Matches) + ; Q=exact(P), rdf(S,P,literal(O)) + ; Q=sub(P), rdf_has(S,P,literal(O)) + ). + +rdf_matches(exact(P),S,O,M) :- rdf(S,P,literal(M,O)). +rdf_matches(sub(P),S,O,M) :- rdf_has(S,P,literal(M,O)). + +attr_unify_hook(_,_). +attr_portray_hook(match(Matches),Var) :- writeq(Var:Matches). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/resolve.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/resolve.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,133 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(resolve, + [ agent_uri/3 + ]). + +/** Tools for resolving named entities to URIs + + NEW RESOLUTION RESOLUTION + Start from the facts. Resolve entities in the background + 1. Introduce nodes tagged 'unresolved' + 2. Attach facts to nodes. + 3. Resolve later + +*/ +:- use_module(library(memo)). +:- use_module(library(musicbrainz)). +:- use_module(library(sparkle)). +:- use_module(library(listutils)). +:- use_module(library(readutil)). +:- use_module(library(dcg_core)). + +:- persistent_memo composer_uri(+composer:atomic,-uri:atom). + +:- initialization memo_attach(memo(resolve),[]). + + +agent_uri(composer,Name,URI) :- ground(URI), !, browse(composer_uri(Name,URI)). +agent_uri(composer,Name,URI) :- + memo(composer_uri(Name,URI),_-Status), + ( Status=ok -> true + ; Status=fail -> clear_all(composer_uri(Name,_)), fail + ; Status=ex(Ex) -> clear_all(composer_uri(Name,_)), throw(Ex) + ). + +composer_uri(Name,URI) :- + member(Source,[mb,dbp]), + source_composer_uri(Source,Name,URI). + +source_composer_uri(mb,Name,URI) :- + format("Searching Musicbrainz for composer '~w'...\n",[Name]), + mb_lazy_query(artist,search([Name,type:person]),[],Matches), + take_while(score_at_least(98),Matches,TopMatches), + process_matches(TopMatches,Matches,URI). + +source_composer_uri(dbp,SearchName,URI) :- + format("Searching DBPedia for '~w'...\n",[SearchName]), + catch( + ( (dbp ?? rdf(URI,rdf:type,foaf:'Person'), rdf(URI,foaf:name,Name), filter(regex(SearchName,Name))), + format("\nFound '~w'...\n",[URI]), + findall(Class,(dbp ?? rdf(URI,rdf:type,Class)),Classes), + format("\nMember of these classes: ~p\n",[Classes]), + format("\nIs this the right one? [y=yes/n=no/a=abort]",[]), flush_output, + get_key_char(Char), nl, + (Char='a' -> throw(lookup_aborted); Char='y') + ), lookup_aborted, fail). + +process_matches([E],_,URI) :- + mb_facet(E,score(Score)), + format("\nMatch (score=~d):\n\n",[Score]), + forall(mb_facet(E,Facet),writeln(Facet)), nl, + mb_uri(E,URI). + +process_matches([],Matches,URI) :- user_scan(Matches,URI). +process_matches(Top,Matches,URI) :- + length(Top,N), N>1, + format("Found ~d matches: \n",[N]), + nl, seqmap(print_match,Top,0,_), + once((repeat, + format("Enter the number of the correct item, or 0 for none of the above: ",[]), flush_output, + read(K), number(K), + % read_line_to_codes(user_input,Codes), + % number_codes(K,Codes), + between(0,N,K) + )), + ( nth1(K,Top,E) -> mb_uri(E,URI) + ; append(Top,Tail,Matches), + process_matches([],Tail,URI) + ). + +print_match(E,I,J) :- + succ(I,J), + format('~` t~d~2+. ~p\n',[J,E]), + forall(mb_facet(E,Facet),format(" ~p\n",[Facet])), + nl. + +user_scan([E|Es],URI) :- + nl, forall(mb_facet(E,Facet),format(" ~p\n",[Facet])), + format("Is this the right one? [y=yes/n=no/a=abort/t=new search term]",[]), flush_output, + get_key_char(Char), nl, + ( Char=y -> mb_uri(E,URI) + ; Char=n -> user_scan(Es,URI) + ; Char=a -> fail + ; Char=t -> nl, read_line_to_string(user_input,Name), source_composer_uri(mb,Name,URI) + ). + + +score_at_least(Thresh,Element) :- mb_facet(Element,score(S)), S>=Thresh. + +% :- volatile_memo work_uri(+terms:list(ground),-uri:atom). +% work_uri(Terms,URI) :- +% file_work_terms(File,WorkTerms,[]), +% file_composer_terms(File,ComposerTerms,[]), +% mb_search(work,[phrase(WorkTerms),artist:phrase(ComposerTerms)],Score,E), +% sleep(0.05), +% format("Match (score=~d):\n",[Score]), +% forall(mb_facet(E,Facet),writeln(Facet)), +% ( Score>98 +% -> mb_uri(E,URI) +% ; format("Is this the right one? [y/n/a]",[]), flush_output, +% get_key_char(Char), +% (Char='a' -> throw(lookup_aborted(work))), +% Char='y' +% ). + + +get_key_char(Char) :- get_single_char(Code), char_code(Char,Code). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/spotify/echonest.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/spotify/echonest.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,65 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(echonest, + [ echocall/4 + ]). + +/** Interface to echonest Web API + */ + +:- use_module(library(fileutils)). +:- use_module(library(http/json)). +:- use_module(library(jpath)). +:- use_module(library(webby)). +:- use_module(library(state)). + +:- set_prolog_flag(double_quotes,string). + +:- setting(min_wait,number,3,"Minimum time between echonest requests"). +:- initialization set_state(next_request_time,0). + +wait_respectfully :- + get_time(Now), + setting(min_wait,TMin), + get_state(next_request_time,T0), T1 is max(Now,T0) + TMin, + set_state(next_request_time,T1), + ( Now>=T0 -> true + ; DT is T0-Now, + debug(echonest,"Sleeping for ~f seconds to respect rate limit",[DT]), + sleep(DT) + ). + +echocall(Key,PathParts,Params,Response) :- + debug(echonest,"Echonest call: ~q, ~q...",[PathParts,Params]), + parts_path([api,v4|PathParts],Path), + wait_respectfully, + catch( restcall(get([api_key=Key, format=json | Params]), json(Response), + [protocol(http), host('developer.echonest.com'), path(Path)], []), + Ex, handle(Ex)). + +handle(http_bad_status(SC,codes(Doc))) :- !, + with_input_from(codes(Doc),json_read_dict(current_input,Dict)), + jpath(response:status:(code:Code,message:Msg),Dict), + throw(echonest_error(SC,Code,Msg)). +handle(Ex) :- throw(Ex). + + +prolog:message(echonest_error(SC,Code,Msg)) --> + {http_status(SC,Meaning)}, + ["(HTTP ~w: ~w) Echonest error ~w: '~s'."-[SC,Meaning,Code,Msg]]. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/spotify/echotools.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/spotify/echotools.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,101 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(echotools, [ echo/1, mb_to_echo/2, mb_to_spotify/2 ]). + +:- use_module(echonest). +:- use_module(library(jpath)). +:- use_module(library(dictutils)). +:- use_module(library(insist)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_pair)). + +echonest_key('NPIODUIKW9DJN1UCI'). + +echo(Path,Params,Decoder) :- + echonest_key(K), echocall(K,Path,Params,Resp), + decode(response:Decoder,Resp). + +decode(A,X) :- jpath(A,X). + +echo(mood(X)) :- echo([artist,list_terms],[type=mood],terms:_#name:X). +echo(style(X)) :- echo([artist,list_terms],[type=style],terms:_#name:X). +echo(genre(X)) :- echo([genre,list],[],genres:_#name:X). +echo(genre_description(X,D)) :- var(X), !, echo_facets([genre,list],[],genres,[name:X,description:D]). +echo(genre_description(X,D)) :- must_be(text,X), !, echo_facets([genre,profile],[name=X],genres,[description:D]). +echo(search(genre,Term,X,D)) :- echo([genre,search],[name=Term,bucket=description],genres:_#(name:X,description(D))). + +echo(genre_artist(Genre,Facets)) :- echo_facets([genre,artists],[name=Genre],artists,Facets). +echo(artist_genre(ArtistID,G)) :- echo([artist,profile],[id=ArtistID,bucket=genre],artist:genres:_#name:G). +echo(genre_facets(Facets)) :- echo_facets([genre,list],[],genres,Facets). +echo(songs(Ids,Facets,Opts)) :- + seqmap(param(id),Ids,Params,Opts), + echo_facets([song,profile],Params,songs,Facets). + +echo(search(song,Conditions,Facets)) :- + echo_facets([song,search],Conditions,songs,Facets). + +echo(genre_song(Genre,Artist,Title,Id)) :- + echo(genre_artist(Genre,[name:Artist,songs:_#(id:Id,title:Title)])). + +echo(genre_songs_by_title(Genre,Artist,Title,Ids)) :- + setof(Id,echo(genre_song(Genre,Artist,Title,Id)),Ids). + +param(P,X) --> [P=X]. + +echo_facets(Path,Params0,Field,Facets) :- + included(Path,Incs), + seqmap(facet(Incs),Facets,Params-Decs,Params0-[]), + list_to_conj(Decs,Decoder), + echo(Path,Params,\Response), + catch( jpath(Field:_#Decoder,Response), + Ex, ( print_message(warning,Ex), + format(user_error,"Response was:\n",[]), + print_dict(user_error,Response,[]), + fail)). + +list_to_conj([D],D). +list_to_conj([D1,D2|Ds],(D1,D2s)) :- list_to_conj([D2|Ds],D2s). + +facet(_,\X) --> !, \> [\X]. +facet(Included,Name:Decoder) --> !, + if(\+memberchk(Name,Included), \< [bucket=Name]), + \> [Name:Decoder]. + +included(Path,Included) :- insist(included_db(Path,Included),unknown_includes(Path)). + +included_db([genre,list],[name]). +included_db([genre,artists],[id,name]). +included_db([song,profile],[id,title,artist_id,artist_name]). +included_db([song,search],[id,title,artist_id,artist_name]). +included_db([genre,profile],[name]). + +mb_to_echo(ID,Songs) :- + atom_concat('musicbrainz:song:',ID,FID), + findall(Song, + echo(songs([FID],[\Song, tracks:1# \_], [ bucket='id:spotify'])), + Songs). + +%% mb_to_spotify(+MBId:atom,-SpURI:atom) is nondet. +% Finds Spotify URIs corresponding to MusicBrainz recording IDs using +% the Echonest Rosetta web service. +mb_to_spotify(ID,SpID) :- + mb_to_echo(ID,Songs), + member(Song,Songs), + jpath(tracks:_#foreign_id:SpID,Song). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/spotify/spotify.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/spotify/spotify.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,348 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(spotify, + [ spotify_authorise/1 + , spotify_app/2 + , spotify/2 + , spotify_user/2 + , spotify_search/4 + , spotify_player//2 + , spotify_player_url/3 + ]). + +/** Interface to Spotify Web API + +This module provides access to the Spotify web API. +It uses dicts, but does not require the .field syntax to be enabled. + +https://developer.spotify.com/web-api/ + + */ + +:- use_module(library(http/http_dispatch)). +:- use_module(library(http/thread_httpd)). +:- use_module(library(http/http_parameters)). +:- use_module(library(http/http_ssl_plugin)). +:- use_module(library(http/html_write)). +:- use_module(library(base64)). +:- use_module(library(dcg_core)). +:- use_module(library(webby)). +:- use_module(library(insist)). +:- use_module(library(state)). + +:- multifile app_facet/2. +:- dynamic state/2. +:- set_prolog_flag(double_quotes,string). + +:- http_handler(root(authorise), authorise, []). + +%% spotify_app(+App:ground, +Spec:list) is det. +% +% Declares App to be a registered Spotify application. Spec must contain contain +% the following elements containing information obtained during the application +% registration process. They can be atoms or strings. +% * id(ClientID:text) +% * secret(Secret:text) +% * redirect(RedirectURL:text) +% * scope(Scopes:text) +% This can only be used as a directive, as the expansion process included declaring +% an HTTP handler using http_handler/3.% +spotify_app(_,_) :- throw(directive(spotify_app/2)). + +user:term_expansion((:- spotify_app(App,Props)), Clauses) :- !, + Info=[id(_),secret(_),redirect(Redirect),scope(_)], + maplist(spotify:option_inv(Props),Info), + insist(url:parse_url(Redirect,Parts),bad_redirect(Redirect)), + member(path(Path),Parts), + seqmap(spotify:app_clause(App),Info,Clauses,[(:-http_handler(Path, spotify:callback(App), []))]). + +option_inv(Props,Prop) :- insist(option(Prop,Props),missing_app_facet(Prop)). +app_clause(App,Prop) --> [spotify:app_facet(App,Prop)]. + +app_port(App,Port) :- + app_facet(App,redirect(Redirect)), + parse_url(Redirect,Parts), + member(port(Port),Parts). + + +%% spotify_authorise(+App) is det. +% +% Get authorisation for current app from a Spotify user. +% This requires a working www_open_url to initiate an interaction with +% the user to handle the Spotify login process. If this doesn't +% work, consider changing the 'browser' Prolog flag. For example, +% on Mac OS X, add the following to your ~/.plrc +% == +% :- set_prolog_flag(browser,open). +% == +% After logging in (if necessary) and authorising the app, the browser +% should show a page confirming that the process succeeded and giving information +% about the current user. This predicate (spotify_authorise/0) will wait +% until the confirmation page has been shown. It may hang if something +% goes wrong. +spotify_authorise(App) :- + get_time(Time), variant_sha1(App-Time,Hash), + login_url(App,Hash,URL), + app_port(App,Port), + with_message_queue(spotify,[max_size(5)], + with_http_server(Port, + ( thread_send_message(spotify,login(App,Hash,URL)), + print_message(information,spotify:auth_opening_browser(App,Port,URL)), + www_open_url(URL), + print_message(information,spotify:auth_waiting(App)), + thread_get_message(spotify,cont(App,Hash,RC),[timeout(300)]), + (RC=error(Ex) -> throw(Ex); true), + print_message(information,spotify:auth_complete(App)) + ))). + + +with_http_server(Port,Goal) :- + setup_call_cleanup( + http_server(http_dispatch, [port(Port)]), Goal, + http_stop_server(Port,[])). + +with_message_queue(Alias,Opts,Goal) :- + setup_call_cleanup( + message_queue_create(_,[alias(Alias)|Opts]), Goal, + message_queue_destroy(Alias)). + +%% login_url(+App,+Hash,-URL) is det. +login_url(App,Hash,URL) :- + maplist(app_facet(App),[id(ID),redirect(Redirect),scope(Scope)]), + Params=[ response_type=code,client_id=ID,scope=Scope, redirect_uri=Redirect, state=Hash ], + parse_url(URL,[ protocol(https), host('accounts.spotify.com'), path('/authorize'), search(Params)]). + + +%% authorise(Request) is det. +% +% Authorisation process via a web interface. +authorise(Request) :- + ( thread_peek_message(spotify,login(_,_,URL)) + -> http_redirect(see_other,URL,Request) + ; reply_html_page(default, [title("SWI Prolog Spotify client")], + center(p("Nothing to see here. Move on.")))). + + +%% callback(+App,+Request) is det. +% +% Handle the callback from Spotify as part of the authorisation process. +% This handler must be registered with library(http_dispatch) associated +% with 'redirect' URL property of the current app. +callback(App,Request) :- + http_parameters(Request,[ code(Code, [string, optional(true)]) + , error(Error, [string, optional(true)]) + , error_description(ErrorDesc, [string, optional(true)]) + , state(Hash, [atom, optional(false)]) ]), + debug(spotify,"Got callback (~w)",[Hash]), + insist(thread_get_message(spotify,login(App,Hash,_),[timeout(0)]),no_matching_state), + + catch( + ( insist(var(Error), auth_error(Error,ErrorDesc)), + insist(nonvar(Code),no_code_received), + maplist(app_facet(App),[id(ID),secret(Secret),redirect(Redirect)]), + get_authorisation([ grant_type='authorization_code' + , code=Code, redirect_uri=Redirect + , client_id=ID, client_secret=Secret + ], [], Reply), + debug(spotify,"Received access and refresh tokens.",[]), + debug(spotify,"Posting success to login queue ~w...",[Hash]), + Status=ok(Reply) + ), Ex, Status=error(Ex)), + handle_auth_reply(Status,App,Hash). + +handle_auth_reply(ok(Reply),App,Hash) :- + set_tokens(App,Reply), + debug(spotify,"Posting success to login queue ~w...",[Hash]), + thread_send_message(spotify,cont(App,Hash,ok)), + spotify(App,me(Me)), is_dict(Me,user), + set_state(user(App),Me), + reply_html_page(default, + [title("SWI-Prolog Spotify Client > Login ok")], + [ \html_post(head,style( + [ "table.json table.json { border: thin solid gray }" + , "table.json { border-collapse: collapse }" + , "table.json td:first-child { font-weight: bold; text-align: right; padding-right:0.5em }" + , "table.json td { vertical-align:top; padding-left:0.5em }" + , "body { margin:2em; }" + ])) + , center(div([h3("SWI Prolog library app '~w' authorised as user"-App), \json(Me) ])) + ]). + +handle_auth_reply(error(Ex),App,Hash) :- + debug(spotify,"Posting error to login queue ~w...",[Hash]), + thread_send_message(spotify,cont(App,Hash,error(Ex))), + ( Ex=http_bad_status(_,Doc), phrase("",Doc,_) + -> format("Content-type: text/html; charset=UTF-8~n~n~s",[Doc]) + ; throw(Ex) + ). + +%% refresh is det. +% Refresh the access token for the current app. +refresh(App) :- + app_facet(App,id(ID)), + app_facet(App,secret(Secret)), + get_state(refresh_token(App),Token), + format(codes(IDCodes),"~w:~w", [ID,Secret]), + phrase(("Basic ",base64(IDCodes)),AuthCodes), + string_codes(Auth,AuthCodes), + % debug(spotify,"Refreshing access tokens...",[]), + get_authorisation([grant_type=refresh_token, refresh_token=Token], + [request_header('Authorization'=Auth)], Reply), + debug(spotify,"Received new access tokens.",[]), + set_tokens(App,Reply). + +%% set_tokens(+App,+Dict) is det. +% Updates the record of the current access and refresh tokens, +% and their new expiry time. +set_tokens(App,Dict) :- + _{expires_in:Expiry,access_token:Access} :< Dict, + get_time(Now), ExpirationTime is Now+Expiry, + set_state(access_token(App),Access-ExpirationTime), + ( _{refresh_token:Refresh} :< Dict + -> set_state(refresh_token(App),Refresh) + ; true + ). + +%% usable_token(+App,-Token) is det. +% Gets a usable access token, refreshing if the current one expired. +usable_token(App,Token) :- + get_state(access_token(App),Token0-ExpiryDate), + get_time(Now), + ( ExpiryDate>Now -> Token=Token0 + ; refresh(App), usable_token(App,Token) + ). + +%% spotify_player(+URI:atom,+Opts:options) is det. +% HTML component for showing the Spotify web widget. +spotify_player_url(track(URI),Opts,URL) :- + option(theme(Th),Opts,white), must_be(oneof([white,black]),Th), + option(view(Vw),Opts,list), must_be(oneof([list,coverart]),Vw), + parse_url(URL, [ protocol(https),host('embed.spotify.com'),path(/) + , search([uri=URI, theme=Th, view=Vw]) ]). + +spotify_player_url(tracks(Title,URIs),Opts,URL) :- + option(theme(Th),Opts,white), must_be(oneof([white,black]),Th), + option(view(Vw),Opts,list), must_be(oneof([list,coverart]),Vw), + maplist(string_concat('spotify:track:'),IDs,URIs), + atomics_to_string(IDs,',',IDList), + atomics_to_string([spotify,trackset,Title,IDList],':',URI), + parse_url(URL, [ protocol(https),host('embed.spotify.com'),path(/) + , search([uri=URI, theme=Th, view=Vw]) ]). + +spotify_player(Spec,Opts) --> + { spotify_player_url(Spec,Opts,URL), + option(width(W),Opts,300), must_be(between(250,640),W), + option(height(H),Opts,300), must_be(between(80,720),H) + }, + html(iframe([ src=URL,width=W,height=H,frameborder=0,allowtransparency=true],[])). + +% multiple tracks: +% uri='spotify:trackset:PREFEREDTITLE:5Z7ygHQo02SUrFmcgpwsKW,1x6ACsKV4UdWS2FMuPFUiT' +json(Dict) --> + {is_dict(Dict), !, dict_pairs(Dict,_,Pairs)}, + html(table(class=json, + [colgroup([col(style="border-right:thin solid black"),col([])]), \seqmap(pair_row,Pairs)])). +json(List) --> {is_list(List)}, !, html(ol(\seqmap(val_li,List))). +json(Val) --> html("~w"-Val). +val_li(Val) --> html(li(\json(Val))). +pair_row(Name-Val) --> html(tr( [ td(Name), td(\json(Val))])). + +%% spotify(+App,+Request) is nondet. +% +% This is the main predicate for making calls to the Spotify web API. The nature of +% the call, its parameters, and its results are encoded in the term Request. +% See request/4 for information about what requests are recognised. +% This predicate will formulate the call URL, refresh the access token if necessary, +% make the call, and read the results. +spotify(App,Req) :- + request(Req,PathPhrase,Method,Reader), !, + phrase(PathPhrase,PathParts), + parts_path([v1|PathParts],Path), + usable_token(App,Token), + string_concat("Bearer ", Token, Auth), + spotify(Method,Reader,'api.spotify.com',Path, + [ request_header('Authorization'=Auth) ]). + +% just for internal use +get_authorisation(Params,Opts,Reply) :- + spotify(post(form(Params)), json(Reply), 'accounts.spotify.com', '/api/token', Opts). + +% All web calls come through here eventually. +spotify(Method,Reader,Host,Path,Opts) :- + restcall(Method, Reader, + [ protocol(https), host(Host), path(Path) ], + [ request_header('Accept'='application/json') + , cert_verify_hook(spotify:verify) + | Opts ]). + +verify(_, Problem, _All, _First, Error) :- + debug(ssl,"Accepting problem certificate (~w)\n~w\n",[Error,Problem]). + +%% request(-Req:spotify_request, -PathPhrase:phrase(atom), -Method:web_method, -Reader:web_reader) is nondet. +% +% Database of mappings from requests to end-points. +request( me(Me), [me], get([]), json(Me)). +request( track(TID,T), [tracks,TID], get([]), json(T)). +request( playlists(UID,Ls), playlists(UID), get([]), json(Ls)). +request( playlist(UID,PID,L), playlist(UID,PID), get([]), json(L)). +request( playlist_tracks(UID,PID,Ts), tracks(UID,PID), get([]), json(Ts)). +request( search(Type,Term,L), [search], get([(type)=Type,q=Term]), json(L)). +request( create_playlist(UID,Name,PL), playlists(UID), post(json(_{name:Name})), json(PL)). +request( add_tracks(UID,PID,URIs), tracks(UID,PID), post(json(URIs)), nil). +request( set_tracks(UID,PID,URIs), tracks(UID,PID), put(json(_{uris:URIs})), nil). +request( del_tracks(UID,PID,TIDs), tracks(UID,PID), delete(json(TIDs)), json(_)). + +% DCG for building paths as a list of atoms. +playlist(UID,PID) --> playlists(UID), [PID]. +playlists(UID) --> [users,UID,playlists]. +tracks(UID,PID) --> playlist(UID,PID), [tracks]. + +spotify_user(App,Me) :- get_state(user(App),Me). + +spotify_search(App,Type,Term,Item) :- + spotify(App,search(Type,Term,Response)), + type_field(Type,Field), + get_dict(Field,Response,Results), + get_dict(items,Results,Items), + member(Item,Items). + +type_field(artist,artists). +type_field(track,tracks). +type_field(album,albums). + +user:portray(Dict) :- + is_dict(Dict), + get_dict(uri,Dict,URI), + ( get_dict(name,Dict,Name) + -> format("<~s|~s>",[URI,Name]) + ; format("<~s>",[URI]) + ). + +prolog:message(directive(Pred)) --> ["~w can only be used as a directive."-[Pred]]. +prolog:message(spotify:refreshing_token) --> ["Refreshing Spotify access token..."]. +prolog:message(spotify:bad_redirect(R)) --> ["Malformed callback URI '~w'"-[R]]. +prolog:message(spotify:missing_app_facet(P)) --> ["spotify_app declaration missing property ~w"-[P]]. +prolog:message(spotify:no_matching_state) --> ["Authorisation synchronisation broken"]. +prolog:message(spotify:no_code_received) --> ["No authorisation code received"]. +prolog:message(spotify:auth_waiting(App)) --> ["Waiting for authorisation of ~w..."-[App]]. +prolog:message(spotify:auth_complete(App)) --> ["Authorisation of ~w complete."-[App]]. +prolog:message(spotify:auth_opening_browser(App,Port,_)) --> + ["Authorising Spotify app ~w. "-[App]], + ["Your browser should open automatically. If not, please open it manually and"], + [" navigate to < http://localhost:~w/authorise >"-[Port]]. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/spotify/spotools.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/spotify/spotools.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,97 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(spotools, + [ name_playlist/2 + , user_playlist/1 + , user_playlist/2 + , login/1 + , explicit/1 + , playlist_track/2 + , set_tracks/2 + , spotify/1 + ]). + +:- use_module(library(dictutils)). +:- use_module(spotify). + +:- dynamic current_app/1. + +login(App) :- + spotify_authorise(App), + writeln("Logged in as:"), + retractall(current_app(_)), + assert(current_app(App)), + user(Me), + print_dict(Me). + +spotify(Goal) :- current_app(App), spotify(App,Goal). + +user(Me) :- + current_app(App), + spotify_user(App,Me). + +name_playlist(Name,Playlist) :- + user_playlist(Playlist), + atom_string(Name,NameS), + Playlist.name=NameS. + +user_playlist(Playlist) :- + user(Me), + user_playlist(Me,Playlist). + +user_playlist(User,Playlist) :- + spotify(playlists(User.id,Playlists)), + member(Playlist,Playlists.items), + tag(playlist,Playlist). + +playlist_entry(PL,Entry) :- + spotify(playlist_tracks(PL.owner.id,PL.id,Tracks)), + member(Entry,Tracks.items), + tag(track,Entry.track). + +playlist_track(PL,Track) :- + playlist_entry(PL,Entry), + Track = Entry.track, + maplist(tag(artist),Track.artists), + tag(album,Track.album). + +add_tracks(PL,Tracks) :- + maplist(get_dict(uri),Tracks,URIs), + spotify(add_tracks(PL.owner.id,PL.id,URIs)). + +del_tracks(PL,Tracks) :- + findall(_{uri:URI}, (member(T,Tracks),get_dict(uri,T,URI)), Ts), + spotify(del_tracks(PL.owner.id,PL.id,_{tracks:Ts})). + +clear_playlist(PL) :- + findall(T,playlist_track(PL,T),Tracks), + del_tracks(PL,Tracks). + +set_tracks(PL,Tracks) :- + maplist(get_dict(uri),Tracks,URIs), + spotify(set_tracks(PL.owner.id,PL.id,URIs)). + +set_playlist_tracks(Name,Tracks) :- + atom_string(Name,NameS), + name_playlist(NameS,PL), + spotify(set_tracks(PL.owner.id,PL.id,Tracks)). + +explicit(Track) :- Track.explicit=true. + + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/state.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/state.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,43 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(state, [set_state/2, get_state/2, with_state/3, retract_state/1]). + +:- meta_predicate + with_state(:,+,0), + retract_state(:), + set_state(:,+), + get_state(:,-). + +:- use_module(insist). +:- dynamic state/3. + +get_state(M:Key,Value) :- state(M,Key,Value). +set_state(M:Key,Value) :- + retractall(state(M,Key,_)), + assert(state(M,Key,Value)). + +with_state(M:Key,Value,Goal) :- + insist(\+state(M,Key,_),state_exists(M:Key)), + setup_call_cleanup( + assert(state(M,Key,Value)), Goal, + retract_state(M:Key)). + +retract_state(M:Key) :- retractall(state(M,Key,_)). + + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/stringutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/stringutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,27 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(stringutils, [ split_string_around/4, strip_string/2 ]). + +split_string_around(Inter,String,Pre,Post) :- + sub_string(String,Bef,_,Aft,Inter), + sub_string(String,0,Bef,_,Pre1), strip_string(Pre1,Pre), + sub_string(String,_,Aft,0,Post1), strip_string(Post1,Post). + +strip_string(X,Y) :- split_string(X,"","\s",[Y]). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/termutils.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/termutils.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,57 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(termutils, + [ with_status_line/1 + , put_cap/2 + , put_cap/1 + , status/2 + , msg/2 + , msg/1 + , heading/2 + , ask/3 + ]). + +:- meta_predicate with_status_line(0). + +put_cap(Cap) :- tty_get_capability(Cap,string,Atom), tty_put(Atom,1). +put_cap(Cap,Lines) :- tty_get_capability(Cap,string,Atom), tty_put(Atom,Lines). + +user:goal_expansion(put_cap(Cap), tty_put(Atom,1)) :- + tty_get_capability(Cap,string,Atom). +user:goal_expansion(put_cap(Cap,Lines), tty_put(Atom,Lines)) :- + tty_get_capability(Cap,string,Atom). + +with_status_line(Goal) :- + stream_property(user_output,buffer(Buff)), + tty_size(_,Width), W is Width-1, + flag(line_len,_,W), + setup_call_cleanup( + set_stream(user_output,buffer(false)), (put_cap(cr), call(Goal), status("",[])), + set_stream(user_output,buffer(Buff))). + +msg(F) :- msg(F,[]). +msg(F,A) :- format(F,A), nl. +ask(F,A,Ch) :- format(F,A), flush_output, get_single_char(C), put_char(C), char_code(Ch,C), nl. +heading(F,A) :- ansi_format([bold],F,A), nl,nl. +status(F,A) :- + format(string(Msg),F,A), + flag(line_len,MaxLen,MaxLen), + string_length(Msg,Len), + (Len>MaxLen -> sub_string(Msg,0,MaxLen,_,Msg1); Msg=Msg1), + write(Msg1), put_cap(ce), put_cap(cr). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/timeline.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/timeline.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,134 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(mo, [ + load_chord_symbols/0 + , load_chord_symbols_on/1 + , has_title/2 + , timeline/1 + , interval_on/2 + , event_on/2 + , event_time/2 + , event_chord/2 + , sorted_events_on/2 + , sorted_timed_events/2 + , timeline_event_terms/2 + , timed_event_term/2 + , interval_term/2 + , chord_term/2 + , note_term/2 + ]). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_http_plugin)). +:- use_module(library(apply_macros)). + +load_chord_symbols :- + setof(C,A^rdf(A,chord:chord,C),Chords), + rdf_load(Chords). + +load_chord_symbols_on(TL) :- + setof(C,E^I^(interval_on(I,TL),event_time(E,I),event_chord(E,C)),Chords), + rdf_load(Chords). + +has_title(TL,Tit) :- rdf(TL,dc:title,Tit). + +timeline(TL) :- rdf(TL,rdf:type,tl:'TimeLine'). +interval_on(I,TL) :- rdf(I,tl:onTimeLine, TL). +event_time(E,T) :- rdf(E,event:time,T). +event_on(E,TL) :- interval_on(I,TL), event_time(E,I). + +interval_ends(I,T1) :- + rdf(I,tl:endsAtDuration,literal(AT1)), + decode_duration(AT1,T1). + +interval_starts(I,T1) :- + rdf(I,tl:beginsAtDuration,literal(AT1)), + decode_duration(AT1,T1). + +decode_duration(A,T) :- sub_atom(A,1,_,1,B), atom_number(B,T). + +sorted_events_on(TL,Events) :- + sorted_timed_events(TL,STE), + maplist(strip_key,STE,Events). + +sorted_timed_events(TL,Events) :- + findall(interval(T1,T2)-E, ( + interval_on(I,TL), + interval_starts(I,T1), + interval_ends(I,T2), + event_time(E,I) + ),TE), + keysort(TE,Events). + +strip_key(_-E,E). +event_chord(E,C) :- rdf(E,chord:chord,C). + +timed_event_term(interval(T1,T2)-Event, event(T1,Dur,ChordTerm)) :- + Dur is T2-T1, + event_chord(Event,Chord), + chord_term(Chord,ChordTerm). + + +user:term_expansion(note_mapping(A,B),note_mapping(AA,B)) :- rdf_global_id(A,AA). +user:term_expansion(modified(A,B,C),modified(AA,B,C)) :- rdf_global_id(A,AA). + +:- rdf_meta note_term(r,?). +:- rdf_meta chord_term(r,?). +:- rdf_meta modified(r,?,?). + + +% represent a chord algebraically as a Prolog term +chord_term(Chord,Term) :- chord_term_semidet(Chord,T) -> Term=T; Term=no_chord. + +chord_term_semidet(Chord,chord(Root,Bass,Intervals)) :- + rdf(Chord,chord:root,R), + note_term(R,Root), + (rdf(Chord,chord:bass,B)->interval_term(B,Bass);Bass=1), + setof(I,rdf(Chord,chord:interval,I),IX), + maplist(interval_term,IX,Intervals). + +note_term(Note,N) :- note_mapping(Note,N). +note_term(Note,MN) :- + rdf(Note,chord:natural, Nat), note_term(Nat,N), + rdf(Note,chord:modifier, Mod), modified(Mod,N,MN). + +modified(chord:flat, N, flat(N)). +modified(chord:doubleflat, N, flat(flat(N))). +modified(chord:sharp, N, sharp(N)). +modified(chord:doublesharp, N, sharp(sharp(N))). + +note_mapping(chord:'note/A',a). +note_mapping(chord:'note/B',b). +note_mapping(chord:'note/C',c). +note_mapping(chord:'note/D',d). +note_mapping(chord:'note/E',e). +note_mapping(chord:'note/F',f). +note_mapping(chord:'note/G',g). + +interval_term(Interval,Term) :- + rdf(Interval,chord:degree,D), D=literal(type(_,DA)), atom_number(DA,Deg), + ( rdf(Interval,chord:modifier,Mod) + -> modified(Mod,Deg,Term) + ; Term=Deg + ). + +timeline_event_terms(TL,Terms) :- + sorted_timed_events(TL,Events), + maplist(timed_event_term,Events,Terms). + diff -r 000000000000 -r 718306e29690 cpack/dml/lib/vamp.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/vamp.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,390 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(vamp, []). + +:- use_module(library(semweb/rdf_db)). +:- use_module(library(semweb/rdf_label)). +:- use_module(library(archive)). +:- use_module(library(settings)). +:- use_module(library(fileutils), except([file_under/4])). +:- use_module(library(termutils)). +:- use_module(library(rdfutils)). +:- use_module(library(xmlarchive)). +:- use_module(library(dcg_core)). +:- use_module(library(dcg_pair)). +:- use_module(library(dcg/basics)). +:- use_module(library(insist)). +:- use_module(library(lambda)). +:- use_module(entailment(p2r)). +:- use_module(api(archive)). +:- use_module(cliopatria(hooks)). + +:- set_prolog_flag(double_quotes,string). +:- rdf_register_prefix(vamp,'http://purl.org/ontology/vamp/'). +:- rdf_register_prefix(vamp_plugins,'http://vamp-plugins.org/rdf/plugins/'). + + +% -------------- LABEL HOOKS FOR COMPUTATIONS AND TRANSFORMS ---------------- + +rdf_label:display_label_hook(R,_,Label) :- + rdf(R,rdf:type,dml:'Computation'), !, + rdf(R,dml:'comp/function',Fn), rdf_display_label(Fn,FnLabel), + rdf(R,dml:'comp/input',Input), + ( Input=literal(InputLabel) -> true + ; rdf_display_label(Input,InputLabel) + ), + format(string(Label),'~s \u25B8 ~s',[InputLabel,FnLabel]). + +rdf_label:display_label_hook(R,_,Label) :- rdf(_,vamp:parameter,R), !, label(parameter,R,Label). +% rdf_label:display_label_hook(R,_,Label) :- rdf(R,rdf:type,vamp:'Transform'), !, label(transform,R,Label). +rdf_label:display_label_hook(R,_,Label) :- rdf(_,vamp:parameter_binding,R), !, label(binding,R,Label). + +label(binding,URI,Label) :- + rdf(URI,vamp:parameter,Param), label(parameter,Param,ParamLabel), + rdf(URI,vamp:value,Value), rdf_literal_value(Value,Val), + format(string(Label),'~s=~w',[ParamLabel,Val]). + + +label(parameter,URI,Label) :- + rdf(URI,vamp:identifier,ID), literal_text(ID,IDText), + ( rdf(URI,vamp:unit,Unit), + literal_text(Unit,UnitText), + UnitText\='' + -> literal_text(Unit,UnitText), + format(string(Label),'~s (~s)',[IDText,UnitText]) + ; format(string(Label),'~s',[IDText]) + ). + +label(transform,URI,Label) :- + rdf(URI,vamp:plugin,Plugin), rdf_display_label(Plugin,PluginName), + rdf(URI,vamp:output,Output), rdf_display_label(Output,OutputLabel), + ( setof(B,rdf(URI,vamp:parameter_binding,B),Bindings) + -> maplist(label(binding),Bindings,BindingLabels), + atomics_to_string(BindingLabels,', ',BindingsText), + format(string(Label),'~s (~s) | ~s',[PluginName,BindingsText,OutputLabel]) + ; format(string(Label),'~s | ~s',[PluginName,OutputLabel]) + %cdot is \u22C5 + ). + +% ---------------------- HIGH LEVEL OPS --------------------------- + +% :- rdf_meta make_triple(r,r,o,-). +% make_triple(S,P,O,rdf(S,P,O)). + +:- public import/0. +import :- + installed_plugins(Plugins), + load_plugins(Plugins), + assert_all_to( vamp, plugins_triple(Plugins)), + assert_all_to( vamp, vamp_triple(transforms)), + assert_all_to( vamp, vamp_triple('_Audio_Analysis')), + assert_all_to( vamp, vamp_triple('_ILM_Analysis')). + +import_directory_graph(Dir,Graph) :- + must_be(ground,Graph), + must_be(atom,Dir), + retractall(failed(_,_)), + rdf_retractall(_,_,_,Graph), + with_status_line(assert_all_to(Graph, vamp_triple(Dir))). + +vamp_triple(Pattern,Triple) :- + absolute_file_name(archive(vamp),VampRoot), + atomic_list_concat([VampRoot,'/',Pattern],AbsPattern), + absolute_file_name(AbsPattern,AbsDir,[expand(true),file_type(directory)]), + atom_concat(VampRoot,RelDir,AbsDir), + atomic_list_concat([_|RelParts],'/',RelDir), + RelParts=[Top|_], + directory_triple(Top,[vamp|RelParts],AbsDir,Triple). + + +installed_plugins(Plugins) :- + absolute_file_name(path('sonic-annotator'),_,[access(execute)]), + with_input_from_file(pipe('sonic-annotator -l'), read_lines_to_strings(current_input,Lines)), + setof(Library:Name, + O^ID^(member(ID,Lines),atomic_list_concat([vamp,Library,Name,O],':',ID)), + Plugins). + +load_plugins(Plugins) :- + setof(Library, Name^member(Library:Name, Plugins), Libraries), + maplist(\Lib^URL^rdf_global_id(vamp_plugins:Lib,URL), Libraries, URLs), + rdf_load(URLs,[]). + +:- rdf_meta plugins_triple(+,t). +plugins_triple(Plugins,rdf(URI,rdf:type,dml:'Installed')) :- + rdf_current_prefix(vamp_plugins,PluginURLBase), + member(Library:Name,Plugins), + format(atom(URI),'~w~w#~w',[PluginURLBase,Library,Name]). + + +directory_triple(transforms,DirParts,AbsDir,Triple) :- !, + append(DirParts,Parts,LocParts), + file_under(AbsDir,AbsPath,Parts), + file_name_extension(_, n3, AbsPath), + locator_uri( file(LocParts), URI), + dcg_triple( transform_triples(URI, with_file(AbsPath)), Triple). + +directory_triple('_ILM_Analysis',DirParts,AbsDir,Triple) :- !, + append(DirParts,Parts,LocParts), + file_under(AbsDir,_,Parts), + append(_,[FileName],Parts), + file_name_extension(BaseName,csv,FileName), + Locator=file(LocParts), + status("Importing: ~w",[Locator]), + string_codes(BaseName, BaseNameCodes), + ( phrase(ilm_filename(AlbumId,TrackNo,PluginAndOutput), BaseNameCodes) + -> true + ; print_message(warning,failed_to_parse_ilm_file(LocParts)), fail + ), + insist(tmap(PluginAndOutput,TName)), + locator_uri(file([vamp,transforms,TName]),TransformGraph), + atom_concat(TransformGraph,'#transform',Transform), + locator_uri(Locator,FileURI), + pattern_uri(ilm:track/num(AlbumId)/num(TrackNo), AudioObject), + dcg_triple(computation_triples(_,AudioObject,Transform,FileURI), Triple). + +directory_triple(_,DirParts,AbsDir,Triple) :- + append(DirParts,Parts,LocParts), + file_under(AbsDir,AbsPath,Parts), + file_name_extension(_,Ext,AbsPath), + append([_,_|PathParts],[FileName],LocParts), + ( archive_ext(Ext) + -> fail % DISABLED + %append(PathParts,Tail,CompositeParts), + %atomics_to_string(LocParts,'/',RelPath), + %with_archive_file(AbsPath, Name, + % archive_entry_triple(CompositeParts-Tail,RelPath,Name,Triple)) + ; file_name_extension(BaseName,Ext,FileName), + dcg_triple( file_triples(Ext, BaseName, PathParts, file(LocParts), + with_file(AbsPath)), + Triple) + ). + + + +read_lines_to_strings(Stream,Lines) :- + read_line_to_string(Stream,String), + ( String=end_of_file + -> Lines=[] + ; Lines=[String|Rest], + read_lines_to_strings(Stream,Rest) + ). + +ilm_filename(AlbumId,TrackNo,PluginAndOutput) --> + integer(AlbumId), "-", + integer(TrackNo), ".", + integer(_), "_vamp_", + string_without([],Codes), + {atom_codes(PluginAndOutput,Codes)}. + +tmap('beatroot-vamp_beatroot_beats', 'beatroot_standard.n3'). +tmap('qm-vamp-plugins_qm-chromagram_chromagram', 'qm-chromagram_standard.n3'). +tmap('qm-vamp-plugins_qm-mfcc_coefficients', 'qm-mfcc-standard.n3'). +tmap('qm-vamp-plugins_qm-keydetector_key', 'qm_vamp_key_standard.n3'). +tmap('qm-vamp-plugins_qm-keydetector_tonic', 'qm_vamp_key_standard_tonic.n3'). +tmap('qm-vamp-plugins_qm-segmenter_segmentation', 'qm-segmentation_standard.n3'). +tmap('qm-vamp-plugins_qm-tempotracker_beats', 'tempotracker_beats_standard.n3'). +tmap('qm-vamp-plugins_qm-tempotracker_tempo', 'tempotracker_tempo_standard.n3'). + + +with_file(File,Stream,Goal) :- + with_stream(Stream,open(File,read,Stream),Goal). + +%% archive_entry(+Prefix:diff_list(string), +ArchivePath:string,+Name:atom,-Triple:triple,+Archive:archive) is nondet. +% +% Produces all the triples associated with the current archive entry. ArchivePath is The relative +% path to the archive from data root directory (in the setting vamp:data_directory). +% Prefix is a difference list containing the path components to be prefixed to the inter-archive +% path to generate the full path associated with the entry. +archive_entry_triple(Parts-Tail,ArchivePath,Name,Triple,Archive) :- + split_string(Name,"/","",InArchiveParts), + append(Tail,[FileName],InArchiveParts), + % Parts is now full composite path excluding file name + file_name_extension(BaseName,Ext,FileName), + dcg_triple( + file_triples(Ext, BaseName, Parts, archive_entry(ArchivePath,Name), + with_current_entry_stream(Archive)), + Triple). + +archive_ext('7z'). +archive_ext(gz). +archive_ext(bz2). +archive_ext(zip). + +recompute_labels :- + forall( rdf(T,rdf:type,vamp:'Transform'), + ( label(transform,T,LabelS), + atom_string(Label,LabelS), + ( rdf(T,rdfs:label,Old) + -> rdf_update(T,rdfs:label,Old,object(literal(Label))) + ; rdf_assert(T,rdfs:label,literal(Label),vamp) + ) + ) + ). + + +% ------------------- FILE IMPORTER, GENERAL PART --------------------- +% + +% :- rdf_meta rdf(r,r,o,?,?). +rdf(S,P,O) --> + { expand_resource(S,SS), + expand_resource(P,PP), + expand_resource(O,OO) + }, + [rdf(SS,PP,OO)]. + +expand_resource(X,X) :- var(X), !, rdf_bnode(X). +expand_resource(literal(X),O) :- !, rdf_global_object(literal(X),O). +expand_resource(X,Y) :- pattern_uri(X,Y). + +computation_triples(Computation,Input,Function,Output) --> + ( {rdf(_,dml:'comp/output', Output,vamp)} -> [] % Already loaded + ; rdf(Computation, rdf:type, dml:'Computation'), + rdf(Computation, dml:'comp/input', Input), + rdf(Computation, dml:'comp/function', Function), + rdf(Computation, dml:'comp/output', Output) + ). + + +parse_dirname(Dirname,Hash) :- + sub_string(Dirname,_,_,After,".n3_"), + sub_string(Dirname,_,After,0,HashString), + atom_string(Hash,HashString). + +:- dynamic failed/2. +:- meta_predicate file_triples(+,+,+,+,2,?,?). + +file_triples(n3,BaseName,_,_,Reader) --> !, + { (sub_atom(BaseName,B,_,_,'_vamp_') -> B=<2; true), % to allow for qm_vampXXXXX.n3 + sub_atom(BaseName,_,5,0,Hash), + status("Importing transform: ~w.n3",[BaseName]), + pattern_uri(dml:transform/Hash,Graph) + }, + transform_triples(Graph,Reader). + +file_triples(csv,BaseName,PathParts,Locator,_) --> !, + { status("Importing: ~w",[Locator]), + append(PathPrefix,[DirName],PathParts), + parse_dirname(DirName,Hash), + atomic_list_concat([transform,'/',Hash,'#',transform], Transform) , + once(sub_string(BaseName,Bef,_,_,"_vamp")), + sub_string(BaseName,0,Bef,_,IDString), + atom_string(ID,IDString), + locator_uri(Locator,FileURI) + }, + { id_to_audio_uri(PathPrefix,ID,AudioObject) -> true + ; % print_message(warning,failed(id_to_audio_uri(PathParts,PathPrefix,DirName,ID,AudioObject))), + PathParts=[Collection|_], + atomic_list_concat([Collection,ID],'/',AudioLocator), + humdrum_p2r:id_assert(vamp:failed(id_to_audio_uri(PathPrefix,ID,AudioObject),AudioLocator)), + AudioObject=literal(AudioLocator) + }, + computation_triples(_, AudioObject, dml:Transform, FileURI). + + +transform_triples(Graph,Reader) --> + { rdf_graph(Graph) -> true % already loaded + ; call(Reader,S,rdf_load(S,[format(turtle),silent(true),base_uri(Graph),graph(Graph)])) + }, + { rdf(Transform,rdf:type,vamp:'Transform',Graph) }, + ( { rdf(Transform,rdfs:label,_) } -> [] + ; { once(label(transform,Transform,LabelS)) }, % precompute label + { atom_string(Label,LabelS) }, + rdf(Transform,rdfs:label,literal(Label)) + ). + +:- use_module(library(memo)). +:- volatile_memo bare_id_to_audio_uri(+atom,-maybe(atom)). +bare_id_to_audio_uri(ID,just(URI)) :- + rdf(DigSig,bldata:path,literal(substring(ID),_)), + ( rdf(DigSig,mo:sampled_version_of,URI) -> true + ; rdf(DigSig,rdf:type,mo:'Signal'), URI=DigSig + ). +bare_id_to_audio_uri(_,nothing). + +%% id_to_audio_uri(+PathParts:list(atom), +ID:atom -URI:uri) is semidet. +% +% This predicate has to work out wich recording is being referred to +% by the name of this output file. It is a not terribly reliable. +id_to_audio_uri(PathParts,ID,URI) :- + ( PathParts = ['CHARM-Collection'|_] + -> rdf(URI,charm:file_name,literal(ID)) + ; PathParts = ['mazurka-dataset'|_] + -> atom_concat(pid,PID,ID), + rdf(URI,mazurka:pid,literal(PID)) + ; PathParts = ['_Non-music'|_] + -> bare_id_to_audio_uri(ID,URI) + ; atomics_to_string(PathParts,"/",Dir), + atomic_list_concat([Dir,'/',ID,'.'],Prefix), + rdf(DigSig,bldata:path,literal(prefix(Prefix),_)), + ( rdf(DigSig,mo:sampled_version_of,URI) -> true + ; rdf(DigSig,rdf:type,mo:'Signal'), URI=DigSig + ) + ). + + +%% missing_audio(-Path:atom,-Matches:list(uri)) is nondet. +% +% This predicate help to find which recordings referred to by imported +% computations could not be found. +missing_audio(Path,Matches) :- + setof(Path,SS^rdf(SS,dml:'comp/input',literal(Path)),Paths), + member(Path,Paths), + atomic_list_concat([_,Filename],'/',Path), + sub_atom(Filename,0,_,2,II), + ( setof(S-Lit,rdf(S,mo:available_as,literal(prefix(II),Lit)),M) + -> Matches=M + ; Matches=[] + ). + +% show_counts(Name) --> +% \< get(D-F), +% { status('directories: ~|~` t~d~3+, files: ~|~` t~d~5+, ~s',[D,F,Name]) }. + + +assert_all_to(Graph,Pred) :- forall(call(Pred,rdf(S,P,O)), rdf_assert(S,P,O,Graph)). + +dcg_triple(Phrase,rdf(S,P,O)) :- + call_dcg(Phrase,Triples,[]), + member(rdf(S,P,O),Triples). + +pattern_uri(Pattern,URI) :- uripattern:pattern_uri(Pattern,URI), !. + +%% file_under(+Dir:path,-AbsPath:path,-Parts:list(string)) is nondet. +% Finds files under directory Dir, succeeding multiple times with AbsPath +% bound to the absolute path (as an atom), and Parts bound to a list +% of directory components ending with the file name. +file_under(Spec,AbsPath,Parts) :- + absolute_file_name(Spec,Dir), + file_under(Dir,AbsPath,Parts,[]). + +%% file_under(+Root:path(dir), -File:path(file)) is nondet. +file_under(Root,File) --> + { atom_concat(Root,'/*',Pattern), + status("Expanding: ~w",[Pattern]), + expand_pattern(Pattern,Item) + }, + ( {exists_file(Item)} + -> {file_base_name(Item,Name), File=Item}, [Name] + ; {exists_directory(Item)} + -> {file_base_name(Item,DirName)}, [DirName], + file_under(Item,File) + ). + +graph_triples(G,Triples) :- findall(rdf(S,P,O),rdf(S,P,O,G),Triples). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/webby.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/webby.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,99 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(webby, + [ webcall/3 + , restcall/4 + , parts_path/2 + , http_status/2 + ]). +/** Web API tools + +---+++ Types +== +web_reader ---> json(-D:dict) + ; nil. + +web_method ---> get(+Params:list(param)) + ; post(+D:post_data) + ; put(+D:post_data) + ; delete(+D:post_data) + . + +post_data ---> form(list(param)) + ; json(dict) + . + +param ---> atom=_. +== +*/ + +:- multifile read_reply/2. + +:- use_module(library(http/http_open)). +:- use_module(library(http/http_header)). +:- use_module(library(http/json)). + +parts_path(Parts,Path) :- + atomics_to_string([''|Parts],"/",Path). + +%% webcall(+URL:url_spec, +Opt:options, +R:web_reader) is det. +webcall(URL,Opts,Reader) :- + debug(webby,"HTTP connecting to ~w, ~w",[URL,Opts]), + setup_call_cleanup( + http_open(URL,In,[status_code(SC)|Opts]), + ( set_stream(In,encoding(utf8)), % ! + ( between(200,299,SC) -> read_reply(Reader,In) + ; read_stream_to_codes(In,ErrorDoc), + throw(http_bad_status(SC,codes(ErrorDoc))))), + close(In)). + +read_reply(json(Dict),In) :- json_read_dict(In,Dict). +read_reply(nil,_). + +%% post_data(+D:post_data,-D2:post_data) is det. +post_data(json(Dict),codes('application/json',Codes)) :- !, atom_json_dict(Codes,Dict,[as(codes)]). +post_data(Data,Data). + +%% restcall(+M:web_method, +R:web_reader, +URL:url_spec, +Opts:options) is det. +restcall(get(Params), Rdr, URL, Opts) :- webcall([search(Params)|URL], Opts, Rdr). +restcall(post(D), Rdr, URL, Opts) :- post_data(D,Data), webcall(URL, [method(post),post(Data)|Opts], Rdr). +restcall(delete(D), Rdr, URL, Opts) :- post_data(D,Data), webcall(URL, [method(delete),post(Data)|Opts], Rdr). +restcall(put(D), Rdr, URL, Opts) :- post_data(D,Data), webcall(URL, [method(put),post(Data)|Opts], Rdr). + +status_meaning(200,"OK"). +status_meaning(201,"Created"). +status_meaning(204,"No content"). +status_meaning(304,"Not modified"). +status_meaning(400,"Bad request"). +status_meaning(401,"Unauthorised"). +status_meaning(403,"Forbidden"). +status_meaning(404,"Not found"). +status_meaning(405,"Method not allowed"). +status_meaning(429,"Too many requests"). +status_meaning(500,"Internal server error"). +status_meaning(502,"Bad gateway"). +status_meaning(503,"Service unavailable"). + +http_status(Code,Meaning) :- status_meaning(Code,Meaning), !. +http_status(_,""). + +prolog:message(http_bad_status(SC,codes(Doc))) --> + {http_status(SC,Meaning)}, + ["HTTP call returned status ~w (~w)."-[SC,Meaning]], + ["Reply document was |~s|"-[Doc]]. diff -r 000000000000 -r 718306e29690 cpack/dml/lib/xmlarchive.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/xmlarchive.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,220 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(xmlarchive, + [ load_xmlns/3 + , load_xmlns/2 + , archive_doc/3 + , map_archive_entries/4 + , with_archive_stream/3 + , with_archive_file/3 + , with_archive/2 + , with_current_entry_stream/3 + , archive_stats/1 + , op(200,fx,@) + ]). + +/* Provides the ability to read XML documents in an archive +*/ + +:- use_module(library(sgml)). +:- use_module(library(termutils)). +:- use_module(library(lambda)). + +:- meta_predicate map_archive_streams(4,?,?,+), + map_archive_entries(5,?,?,+), + with_archive_stream(+,?,1), + with_archive_file(+,?,1), + with_current_entry_stream(+,-,0), + with_archive(+,1). + +:- thread_local xmlns/2. +:- thread_local errors/2. + +%% load_xmlns(+Source,-Doc:list,+Opts:list) is det. +% +% Loads an XML document using the xmlns dialect to handle element names +% that involve namespaces. On exit, Doc is a list of the top level elements +% in the document. Valid options are: +% * ns(-Namespaces:list(pair(atom,url))) +% On exit, Namespaces will contain a list of abbreviation-URL pairs for +% all the namespaces declared in the document. +% * errors(-Errors:list(pair(oneof([error,warning]),text)) +% On exit, Errors will contain a list of all the errors and warnings +% encountered while parsing the document. +load_xmlns(Source,Doc,Opts) :- + option(ns(Namespaces),Opts,_), + option(errors(Errors),Opts,_), + retractall(xmlns(_,_)), + retractall(errors(_,_)), + load_xml(Source,Doc, + [ dialect(xmlns) + , space(remove) + , call(xmlns,on_xmlns) + , call(error,on_error) + , call(urlns,on_urlns) + , max_errors(-1) + ]), + findall(S-M,errors(S,M),Errors), + findall(N-URL,xmlns(N,URL),Namespaces). + +%% load_xmlns(+Source,-Doc:list) is det. +load_xmlns(Source,Doc) :- + retractall(xmlns(_,_)), + retractall(errors(_,_)), + load_xml(Source,Doc, + [ dialect(xmlns) + , space(remove) + , call(xmlns,on_xmlns) + , call(urlns,on_urlns) + , call(error,on_error) + , max_errors(-1) + ]). + +on_xmlns(Prefix,URL,_) :- + debug(xmlarchive,'XML Namespace: ~w -> ~w',[Prefix,URL]), + ( rdf_current_prefix(Prefix,URL1) + -> debug(xmlarchive,'~w already known as ~w',[Prefix,URL1]), + asserta(xmlns(Prefix,URL)), + ( URL=URL1 -> assert(xmlns(Prefix,URL)) + ; debug(xmlarchive,'*** Namespace CLASH',[]), + assert(xmlns(Prefix,URL)) + ) + ; asserta(xmlns(Prefix,URL)) + ). + +on_urlns(xmlns,xmlns,_) :- !. +on_urlns(URL,Prefix,_) :- + ( xmlns(Prefix,URL) + -> debug(xmlarchive,'URL ~w mapped to ~w',[URL,Prefix]) + ; debug(xmlarchive,'*** on_urlns failed on ~w, ~w',[URL,Prefix]) + ). + +on_error(Severity,Message,_Parser) :- + debug(xmlarchive,'SGML ~w: ~s',[Severity,Message]), + assertz(errors(Severity,Message)). + + + + +%% archive_doc(+File:filename, -Doc:list(xml_element), +Opts:options) is nondet. +% +% Is true when archive File contains a file encoding XML document Doc. +% Valid options are: +% * name(-Name:atom) +% On exit, Name will contain the name of the file in the archive that +% was parsed to produce Doc. +% * ns(-NS:list(pair(atom,url))) +% On exit, NS will contain a list of namespaces used in the document. +archive_doc(File,Doc,Opts) :- + select_option(name(Name),Opts,Opts1,_), + with_archive_stream(File,Name,Doc+\S^load_xmlns(S,Doc,Opts1)). + +archive_stats(File) :- + nl, + with_status_line( with_archive( File, + map_archive_streams(load_and_count,0-e(0,0,[]),T-e(N,M,L)))), + format('Compiling statistics...\n',[]), + aggregate(count, Errs^Msg^errors_error(L,warning,Msg), NumWarnings), + once(aggregate(count, Errs^Msg^errors_error(L,error,Msg), NumErrors); NumErrors=0), + setof(Msg, Sev^errors_error(L,Sev,Msg), Msgs), + length(Msgs,NumMessageTypes), + nl, + format(' Number of loaded files: ~d\n',[T]), + format('Number of files with problems: ~d\n',[N]), + format(' Total number of problems: ~d\n',[M]), + format(' Number of errors: ~d\n',[NumErrors]), + format(' Number of warnings: ~d\n',[NumWarnings]), + format(' Number of distinct messages: ~d\n',[NumMessageTypes]). + +errors_error(L,Sev,Msg) :- + member(_-Errs,L), + member(Sev-Msg,Errs). + +load_and_count(Name,Stream,I1-E1,I2-E2) :- + succ(I1,I2), + status('Loading: ~d - ~s',[I2,Name]), + load_xmlns(Stream,_,[errors(Errors)]), + ( Errors=[] -> E2=E1 + ; length(Errors,DM), + E1=e(N1,M1,L1), E2=e(N2,M2,L2), + N2 is N1 + 1, M2 is M1 + DM, + L2=[Name-Errors|L1] + ). + +% ---------- General archive handling stuff --------- + + +%% with_archive_stream(+File:text,?Name:atom,+Goal:pred(+A:archive) is nondet. +% +% Unifies Name with the name of an entry in archive File, and calls Goal +% as call(Goal,Stream), where Stream is available for reading the entry. +% Runs through all available entries on backtracking. +with_archive_stream(File,Name,Goal) :- + with_archive(File, with_stream_in_archive(Name,Goal)). + + +with_archive_file(File,Name,Goal) :- + with_archive(File, with_file_in_archive(Name,Goal)). + +with_file_in_archive(Name,Goal,Archive) :- + archive_entry_name(Archive,Name), + archive_header_property(Archive,filetype(file)), + call(Goal,Archive). + +with_stream_in_archive(Name,Goal,Archive) :- + archive_entry_name(Archive,Name), + archive_header_property(Archive,filetype(file)), + setup_call_cleanup( + archive_open_entry(Archive,Stream), + call(Goal,Stream), + close(Stream)). + +archive_entry_name(Archive,Name) :- var(Name), !, + catch(( repeat, + (archive_next_header(Archive,Name) -> true; throw(nomore)) + ), nomore,fail). + +archive_entry_name(Archive,Name) :- + archive_next_header(Archive,Name). + +map_archive_entries(Goal,S1,S3,Archive) :- + ( archive_next_header(Archive,Name) + -> archive_header_property(Archive,filetype(Type)), + call(Goal,Archive,Type,Name,S1,S2), + map_archive_entries(Goal,S2,S3,Archive) + ; S1=S3 + ). + +map_archive_streams(Goal,S1,S2,Archive) :- + map_archive_entries( call_with_archive_stream(Goal), S1,S2,Archive). + +call_with_archive_stream(Goal,Archive,file,Name,S1,S2) :- !, + with_current_entry_stream(Archive,Stream, call(Goal,Name,Stream,S1,S2)). +call_with_archive_stream(_,_,_,S1,S1). + +with_current_entry_stream(Archive,Stream,Goal) :- + setup_call_cleanup( + archive_open_entry(Archive,Stream), Goal, + close(Stream)). + + +with_archive(File,Goal) :- + setup_call_cleanup( + archive_open(File,A,[]), call(Goal,A), + archive_close(A)). diff -r 000000000000 -r 718306e29690 cpack/dml/lib/xmltraverse.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/lib/xmltraverse.pl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,50 @@ +/* Part of DML (Digital Music Laboratory) + Copyright 2014-2015 Samer Abdallah, University of London + + 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 2 + 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +:- module(xmltraverse, [traverse/3, op(720,xfx,@), op(750,xfy,~), op(750,xfy,..) ]). +% for traverse/3 paths +:- op(720,xfx,@). +:- op(750,xfy,~). +:- op(750,xfy,..). + +%% traverse(+Dir:oneof([f,b]), +Doc:xml_element, -P:xml_path) is nondet. +% +% Succeeds once for each path through an XML element starting at the top +% and travelling all or part of the way down through the tree structure. +traverse(f,El,Path) :- traverse_f(El,Path). +traverse(b,El,Path) :- traverse_b([],El,Path). + +traverse_f(Other,{Other}) :- atomic(Other), !. +traverse_f(Element,\Element). +traverse_f(element(Name,_,_), n(Name)). +traverse_f(element(Name,Attribs,_),Name @ A) :- member(A,Attribs). +traverse_f(element(Name,_,Content),Name .. Path1) :- + ( Path1 = \Content + ; Path1 = (I~Path2), + nth1(I,Content,SubE), + traverse_f(SubE,Path2) + ). + + +traverse_b(L,Other,{Other}..L) :- atomic(Other), !. +traverse_b(L,element(Name,Attribs,Content),Path) :- !, + ( Path = (A @ Name .. L), member(A,Attribs) + ; nth1(N,Content,SubE), + traverse_b(N ~ Name..L,SubE,Path) + ). + diff -r 000000000000 -r 718306e29690 cpack/dml/matlab/dml_fsetup.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/matlab/dml_fsetup.m Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,10 @@ +function dml_fsetup(w,h,units) +% dml_fsetup(width,height,units) +% similar to asetup, but sizes figure +% instead of axes. units default to +% centimetres. + +if nargin<3, units='centimeters'; end +set(gcf,'Units',units); +set(gcf,'PaperUnits',units); +set(gcf,'PaperPosition',[0 0 w h]); diff -r 000000000000 -r 718306e29690 cpack/dml/matlab/dml_paperfig.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/matlab/dml_paperfig.m Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,36 @@ +function dml_paperfig(fig,fn,fs,lw,colour,ms,lwr) +% dml_paperfig(fontname) +% dml_paperfig(fontname, fontsize) +% dml_paperfig(fontname, fontsize, linewidth) +% dml_paperfig(fontname::string, fontsize::natural, linewidth::nonneg, colour::bool) +% dml_paperfig :: +% string/'Times' ~'font name', +% natural/9 ~'font size', +% nonneg/0.4 ~'line width', +% bool/1 ~'colour or b/w', +% nonneg/4 ~'marker size' +% -> action handle. +% +% Sets up default linewidth and hardcopy inversion +% for printing to white paper at high resolution. +% also, sets to white background. Optional font name +% to used for labels etc. + +figure(fig); +clf; +h=gcf; +whitebg(h,'w'); +set(h,'Color','w'); +set(h,'DefaultTextFontSize',fs); +set(h,'DefaultTextFontName',fn); +set(h,'DefaultAxesFontSize',fs); +set(h,'DefaultAxesFontName',fn); +set(h,'DefaultAxesLineWidth',lwr*lw); +set(h,'DefaultTextColor','k'); +set(h,'DefaultLineLineWidth',lw); +set(h,'DefaultLineMarkerSize',ms); +set(h,'InvertHardcopy','off'); +if ~colour, + set(h,'DefaultAxesColorOrder',[0 0 0]); + set(h,'DefaultAxesLineStyleOrder','-|:|--|-.'); +end diff -r 000000000000 -r 718306e29690 cpack/dml/python --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/python Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,1 @@ +../../dml-cla/python \ No newline at end of file diff -r 000000000000 -r 718306e29690 cpack/dml/rdf/countries.skos.rdf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/rdf/countries.skos.rdf Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,346 @@ + + + + MARC List for Countries + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2011-04-26T00:00:00 + modified + + + + diff -r 000000000000 -r 718306e29690 cpack/dml/rdf/cpack/dml.ttl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/rdf/cpack/dml.ttl Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,22 @@ +@prefix rdf: . +@prefix rdfs: . +@prefix dcterms: . +@prefix cpack: . +@prefix mo: . + +<> a cpack:Ontology ; + cpack:packageName "dml" ; + dcterms:title "Digital Music Lab" ; + cpack:author [ foaf:name "Samer Abdallah" ; + foaf:mbox ; + ] ; + cpack:primaryRepository + [ a cpack:GitRepository ; + cpack:gitURL + ] ; + cpack:description + +"""This package provides components of the Digital Music Lab plugin to Cliopatria +""" . + + diff -r 000000000000 -r 718306e29690 cpack/dml/rdf/dmlclaOntology.n3 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/rdf/dmlclaOntology.n3 Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,1 @@ +../../../dml-cla/ontologies/dmlclaOntology.n3 \ No newline at end of file diff -r 000000000000 -r 718306e29690 cpack/dml/rdf/languages.skos.rdf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/rdf/languages.skos.rdf Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,498 @@ + + + + MARC List for Languages + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2011-04-26T00:00:00 + modified + + + + diff -r 000000000000 -r 718306e29690 cpack/dml/rdf/silvet.n3 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/rdf/silvet.n3 Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,125 @@ +@prefix rdfs: . +@prefix xsd: . +@prefix vamp: . +@prefix plugbase: . +@prefix owl: . +@prefix dc: . +@prefix af: . +@prefix foaf: . +@prefix doap: . +@prefix cc: . +@prefix : <#> . + + +## Properties of this document + +<> a vamp:PluginDescription ; + foaf:maker ; + foaf:primaryTopic . + + +## Maker of the whole plugin library + +:library_maker + foaf:name "Queen Mary, University of London" ; + foaf:logo ; + foaf:page + . + + +## Properties of the plugin library, and references to the plugins it contains + +plugbase:library a vamp:PluginLibrary ; + vamp:identifier "silvet" ; + foaf:maker :library_maker ; + vamp:available_plugin plugbase:silvet ; + dc:title "Silvet Note Transcription" ; # Place library name here and uncomment + dc:description """Silvet, or Shift-Invariant Latent Variable Transcription, is a Vamp plugin for polyphonic music transcription (from audio to note times and pitches).""" ; + foaf:page ; + doap:download-page ; + . + + +## Properties of the Silvet Note Transcription plugin + +plugbase:silvet a vamp:Plugin ; + dc:title "Silvet Note Transcription" ; + vamp:name "Silvet Note Transcription" ; + dc:description """Estimate the note onsets, pitches, and durations that make up a music recording.""" ; + foaf:maker :library_maker ; + dc:rights """Method by Emmanouil Benetos and Simon Dixon; plugin by Chris Cannam and Emmanouil Benetos. GPL licence.""" ; +# cc:license ; + vamp:identifier "silvet" ; + vamp:vamp_API_version vamp:api_version_2 ; + owl:versionInfo "1" ; + vamp:input_domain vamp:TimeDomain ; + vamp:parameter plugbase:silvet_param_mode ; + vamp:parameter plugbase:silvet_param_instrument ; + vamp:parameter plugbase:silvet_param_finetune ; + + vamp:output plugbase:silvet_output_notes ; + vamp:output plugbase:silvet_output_timefreq ; + vamp:output plugbase:silvet_output_pitchactivation ; + . +plugbase:silvet_param_mode a vamp:QuantizedParameter ; + vamp:identifier "mode" ; + dc:title "Processing mode" ; + dc:format "" ; + vamp:min_value 0 ; + vamp:max_value 1 ; + vamp:unit "" ; + vamp:quantize_step 1 ; + vamp:default_value 1 ; + vamp:value_names ( "Draft (faster)" "Intensive (higher quality)"); + . +plugbase:silvet_param_instrument a vamp:QuantizedParameter ; + vamp:identifier "instrument" ; + dc:title "Instrument" ; + dc:format "" ; + vamp:min_value 0 ; + vamp:max_value 13 ; + vamp:unit "" ; + vamp:quantize_step 1 ; + vamp:default_value 0 ; + vamp:value_names ( "Multiple or unknown instruments" "Piano" "Guitar" "Violin" "Viola" "Cello" "Horn" "Flute" "Oboe" "Clarinet" "Tenor Sax" "Bassoon" "String quartet" "Wind ensemble"); + . +plugbase:silvet_param_finetune a vamp:QuantizedParameter ; + vamp:identifier "finetune" ; + dc:title "Return fine pitch estimates" ; + dc:format "" ; + vamp:min_value 0 ; + vamp:max_value 1 ; + vamp:unit "" ; + vamp:quantize_step 1 ; + vamp:default_value 0 ; + vamp:value_names (); + . +plugbase:silvet_output_notes a vamp:SparseOutput ; + vamp:identifier "notes" ; + dc:title "Note transcription" ; + dc:description """Overall note transcription. Each note has time, duration, estimated pitch, and a synthetic MIDI velocity (1-127) estimated from the strength of the pitch in the mixture.""" ; + vamp:fixed_bin_count "true" ; + vamp:unit "Hz" ; + vamp:bin_count 2 ; + vamp:bin_names ( "Frequency" "Velocity"); + vamp:sample_type vamp:VariableSampleRate ; + vamp:computes_event_type af:Note ; + . +plugbase:silvet_output_timefreq a vamp:DenseOutput ; + vamp:identifier "timefreq" ; + dc:title "Time-frequency distribution" ; + dc:description """Filtered constant-Q time-frequency distribution as used as input to the expectation-maximisation algorithm""" ; + vamp:fixed_bin_count "true" ; + vamp:bin_count 545 ; + vamp:unit "" ; + vamp:computes_signal_type af:Spectrogram ; + . +plugbase:silvet_output_pitchactivation a vamp:DenseOutput ; + vamp:identifier "pitchactivation" ; + dc:title "Pitch activation distribution" ; + dc:description """Pitch activation distribution resulting from expectation-maximisation algorithm, prior to note extraction.""" ; + vamp:fixed_bin_count "true" ; + vamp:unit "" ; + vamp:bin_count 88 ; + vamp:computes_signal_type af:Spectrogram ; + . diff -r 000000000000 -r 718306e29690 cpack/dml/scripts/compression/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/scripts/compression/Makefile Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,13 @@ +CC = c99 +CFLAGS = -g -I/opt/local/include +LDFLAGS = -L/opt/local/lib -llzma + +PROGS = dlzma + +all: $(PROGS) + +.c: + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +clean: + -rm -f $(PROGS) diff -r 000000000000 -r 718306e29690 cpack/dml/scripts/compression/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpack/dml/scripts/compression/README Tue Feb 09 21:05:06 2016 +0100 @@ -0,0 +1,72 @@ +# Delta compression + +Scripts in dml-cliopatrial/cpack/dml/scripts/compression provide a common interface +to several delta compression programs. The interface is + + stdin ---> [