Merge pull request #459 from redtide/moved-scripts

Move Doxygen scripts
This commit is contained in:
JP Cimalando 2020-10-06 00:25:37 +02:00 committed by GitHub
commit e8d052d50c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 186 additions and 760 deletions

View file

@ -166,17 +166,6 @@ jobs:
install: sudo pip install git-archive-all
script: git-archive-all --prefix="sfizz-${TRAVIS_BRANCH}/" -9 "${INSTALL_DIR}.tar.gz"
- name: "Generate documentation"
if: (tag IS present) AND (branch = master) AND (type = push)
addons:
apt:
packages:
- doxygen
- cmake
- libsndfile-dev
install: skip
script: .travis/update_dox.sh
- name: "Discord Webhook"
install: skip
script: bash ${TRAVIS_BUILD_DIR}/.travis/discord_webhook.sh success

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -x # No fail, we need to go back to the original branch at the end
. .travis/environment.sh
mkdir build && cd build && cmake -DSFIZZ_JACK=OFF -DSFIZZ_SHARED=OFF -DSFIZZ_LV2=OFF .. && cd ..
doxygen Doxyfile
./doxygen/scripts/generate_api_index.sh
git fetch --depth=1 https://github.com/${TRAVIS_REPO_SLUG}.git refs/heads/gh-pages:refs/remotes/origin/gh-pages
git checkout origin/gh-pages
git checkout -b gh-pages
mv _api api/${TRAVIS_TAG}
mv api_index.md api/index.md
git add api && git commit -m "Release ${TRAVIS_TAG} (Travis build: ${TRAVIS_BUILD_NUMBER})"
git remote add origin-pages https://${GITHUB_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git > /dev/null 2>&1
git push --quiet --set-upstream origin-pages gh-pages
git checkout ${TRAVIS_BRANCH}

View file

@ -1,187 +0,0 @@
<doxygenlayout version="1.0">
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="no" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="modules" visible="yes" title="Categories" intro=""/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="no"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<detaileddescription title=""/>
<memberdecl>
<membergroups visible="yes"/>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
</memberdecl>
<allmemberslink visible="yes"/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="no"/>
<detaileddescription title=""/>
<memberdecl>
<membergroups visible="yes"/>
<nestednamespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="no"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<detaileddescription title=""/>
<memberdecl>
<membergroups visible="yes"/>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="no"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<detaileddescription title=""/>
<memberdecl>
<membergroups visible="yes"/>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdecl>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<detaileddescription title=""/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
</directory>
</doxygenlayout>

View file

@ -1,12 +0,0 @@
<hr>
<footer>
<p style="text-align:left">Copyright &copy; 2019-2020 Paul Ferrand
<span style="float:right">Generated for sfizz by
<a href="http://www.doxygen.org/index.html"
target="_new">Doxygen</a> $doxygenversion</span>
</p>
</footer>
</div><!-- container -->
<script src="/sfizz/assets/js/scripts.min.js"></script>
</body>
</html>

View file

@ -1,155 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Home - sfizz</title>
<meta name="author" content="Paul Ferrand">
<meta name="web-author" content="Andrea Zanellato">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Atom Feeds -->
<link href="/sfizz/atom.xml" rel="alternate" title="News"
type="application/atom+xml" />
<!-- Favicon Generator Icons -->
<link rel="apple-touch-icon" sizes="180x180"
href="/sfizz/assets/ico/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/sfizz/assets/ico/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/sfizz/assets/ico/favicon-16x16.png">
<link rel="manifest" href="/sfizz/assets/ico/site.webmanifest">
<link rel="mask-icon" href="/sfizz/assets/ico/safari-pinned-tab.svg"
color="#5bbad5">
<link rel="shortcut icon" href="/sfizz/assets/ico/favicon.ico">
<meta name="msapplication-TileColor"
content="#da532c">
<meta name="msapplication-config" content="/sfizz/assets/ico/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath$jquery.js"></script>
<script type="text/javascript" src="$relpath$dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath$$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<!-- Stylesheets -->
<link href="/sfizz/assets/css/style.min.css"
rel="stylesheet" media="screen">
<!-- Font Awesome Icons -->
<script src="https://kit.fontawesome.com/8d25d19870.js"></script>
</head>
<body>
<button onclick="topFunction()" id="scrollButton" title="Go to top">Top</button>
<div class="container">
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color:#222">
<a class="navbar-brand" href="/sfizz/">
<img src="/sfizz/assets/img/logo.png"
width="30" height="30" class="d-inline-block" alt="">
sfizz</a>
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarContent" aria-controls="navbarContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarContent">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0">
<li class="nav-item">
<a class="nav-link" href="/">
<i class="fas fa-home fa-fw" aria-hidden="true"></i>
&nbsp;Home</a>
</li>
<!-- FIXME: Dropdown buttons are shown but menus are broken for some reason
(not the container div)
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#"
id="navbarProjects" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fas fa-hammer fa-fw" aria-hidden="true"></i>
&nbsp;Projects</a>
<div class="dropdown-menu" aria-labelledby="navbarProjects">
<a class="dropdown-item"
href="/beatbox/">
<i class="fas fa-drum fa-fw" aria-hidden="true"></i>
&nbsp;BeatBox</a>
<a class="dropdown-item disabled"
href="/sfizz/">
<i class="fas fa-play-circle fa-fw" aria-hidden="true"></i>
&nbsp;sfizz</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
href="https://github.com/sfztools/sfizz-render/">
sfizz-render</a>
<a class="dropdown-item"
href="https://github.com/sfztools/sfz-flat/">
sfz-flat</a>
<a class="dropdown-item"
href="https://github.com/sfztools/sfz-opcode-checker/">
sfz-opcode-checker</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
href="https://github.com/sfztools/emacs-sfz-mode/">
Emacs Syntax Highlight</a>
<a class="dropdown-item"
href="https://github.com/sfztools/syntax-highlighting-gedit/">
gedit Syntax Highlight</a>
<a class="dropdown-item"
href="https://github.com/sfztools/syntax-highlighting-geany/">
Geany Syntax Highlight</a>
<a class="dropdown-item"
href="https://github.com/sfztools/syntax-highlighting-sublime-text/">
Sublime Text Syntax Highlight</a>
<a class="dropdown-item"
href="https://github.com/sfztools/sfz.vim">
Vim Syntax Highlight</a>
<a class="dropdown-item"
href="https://github.com/sfztools/syntax-highlighting-vscode/">
VSCode Syntax Highlight</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#"
id="navbarDocumentation" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fas fa-book fa-fw" aria-hidden="true"></i>
&nbsp;Documentation</a>
<div class="dropdown-menu" aria-labelledby="navbarDocumentation">
<a class="dropdown-item"
href="/sfizz/api"><i class="fas fa-code fa-fw" aria-hidden="true"></i>
&nbsp;API</a>
<a class="dropdown-item"
href="/sfizz/development/build">
<i class="fas fa-code fa-fw" aria-hidden="true"></i>
&nbsp;Build</a>
<a class="dropdown-item"
href="/sfizz/development/status">
<i class="fas fa-tasks fa-fw" aria-hidden="true"></i>
&nbsp;SFZ Opcodes</a>
</div>
</li>
-->
</ul>
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
<li class="nav-item">
<a class="nav-link" href="/sfizz/downloads">
<i class="fas fa-download fa-fw" aria-hidden="true"></i>
Download</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/sfizz/search/">
<i class="fas fa-search fa-fw" aria-hidden="true"></i>
Search</a>
</li>
</ul>
</div>
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
$searchbox
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</nav>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->

View file

@ -1,198 +0,0 @@
#page_container {
position: relative;
margin: 0;
padding: 0;
height: auto !important;
height: 100%;
min-height: 100%;
}
div.contents, div.searchresults {
margin-top: 10px;
margin-right: 12px;
padding-bottom: 70px;
}
#projectlogo {
text-align: left;
}
#projectnumber {
font-size: 120%;
font-family: Tahoma, Arial, sans-serif;
text-align: right;
padding: 0.5em 1em;
}
.tabs {
font-size: 14px;
}
.tabs2, .tabs3 {
font-size: 12px;
}
.navpath ul {
font-size: 12px;
}
h1, h2, h3, h4, h5, h6 {
color: #002D88;
font-weight: normal;
margin-top: 1em;
margin-bottom: 0.5em;
padding-top: 8px;
padding-bottom: 4px;
width: 100%;
}
h1 {
font-size: 150%;
border-bottom: 1px solid #3276FF;
}
h2 {
font-size: 135%;
margin-top: 0.75em;
}
h3 {
font-size: 120%;
margin-top: 0.5em;
}
h4 {
font-size: 100%;
margin-top: 0.5em;
}
div.headertitle h1 {
margin: 10px 2px;
border: none;
padding: 0;
width: auto;
color: black;
font-weight: bold;
}
div.toc h3 {
font-size: 14px;
}
div.toc li {
font-size: 12px;
line-height: 1.3;
padding-left: 14px;
}
img.logo {
float: right;
margin: 20px;
}
div.logo {
float: right;
margin: 20px;
}
table.directory {
line-height: 1.5;
}
.icon {
line-height: 1.25;
}
div.appearance {
margin: 1em 0em;
}
div.appearance table {
margin: 0.5em 0em;
width: 100%;
text-align: center;
}
div.appearance img {
margin: 0.5em;
}
div.appearance .caption {
font-style: italic;
font-weight: normal;
font-size: 90%;
}
div.appearance_brief table {
width: 100%;
table-layout: fixed;
text-align: center;
border-collapse: collapse;
}
div.appearance_brief table td:first-child {
width: 20em;
text-align: left;
padding-left: 2em;
}
div.appearance_brief table td {
border-style: none solid solid none;
border-width: 1px;
border-color: lightblue;
}
td.green { color: green; }
td.orange { color: #ff8000; }
td.red { color: red; }
span.literal {
text-decoration: none;
font-weight: bold;
font-family: monospace, fixed;
}
/* we make all the following <span> tags render the text just like
the standard Doxygen @remarks, @see tags do, to obtain a uniform
look and feel */
span.itemdef, span.lib, span.category, span.stdobj, span.styles,
span.events, span.flags, span.appearance, span.impl, span.avail {
font-weight: bold;
line-height: 130%;
}
span.style, span.event, span.flag {
font-weight: bold;
color: #880000;
}
div.styleDesc, div.eventDesc, div.flagDesc {
margin-left: 3%;
margin-bottom: 1ex;
}
div.eventHandler {
margin: 1em;
text-indent: 3%;
}
div.eventHandler span {
padding: 5px;
background-color: #eeeeee;
font-family: monospace, fixed;
}
code {
font-size: 110%;
color: #444444;
}
address.footer {
position: absolute;
bottom: 0;
margin: 0;
padding: 10px 0;
width: 100%;
border-top: 1px solid #0043CC;
background-image: url('nav_h.png');
background-repeat: repeat-x;
background-color: #F4F8FF;
}
address.footer small {
padding: 0 10px;
}

View file

@ -1,154 +0,0 @@
# Global view of the engine
The sfizz engine is basically a "Synth" object that takes an SFZ file in, receives MIDI-type events
and is able to render audio through successive calls to a callback function. This is in line with
the way most audio applications and plugins are working. A high-level overview is presented in the
following diagram.
```
C and C++ API entry point
|
|
|
|
+--------v-------+
| |
+-------------------------- Synth -----------------------------+
| | | |
| +----------------+ |
| | |
+--------v------+ | +---------v--------+
| | +---------v---------+ | |
| Region list | | Common resources | | Voice pool |
| | | and state | | |
+---------------+ | ----------------- | +------------------+
Built from the SFZ file | File pool |
| Envelope pool | The voices are the polyphony
Each region is a semi-passive | LFO pool | of the synth. They are idle
description object that can | Buffer pool | and they get activated by the
decide whether it is "active" | Midi state | synth to play a region on a
or not depending on the chain | ... | specific event. They are then
of MIDI events it receives. +-------------------+ "linked" to the region while
Once activated, a voice is There are a number of common it is played, and reset to
chosen to play the region until resources that are needed for their idle state when they
it ends naturally or through all the regions and in parti- are done playing the region.
note-offs or off-groups. cular the voices. This includes
all the (preloaded) files for
the SFZ instrument, but will
include in the future the EG
and LFOs that are needed to
achieve compliance with the
SFZ v2 specification. This will
also include a temporary buffer
holder that voices may share.
A common resource of importance
is the MIDI state: note durations
are needed for some opcodes --
for example rt_decay -- and
triggering velocities too.
```
The Synth, Voices and Regions form the bulk of the code complexity. The rest of the engine is dedicated of
mostly helper classes to enable easy management of floating-point buffers in which the audio data is held,
signal processing and accelerated (SIMD) computations, and abstractions that are specific to the SFZ format
such as envelope generators, curves or LFOs.
# Parsing the SFZ files
The sfz file logic is pretty simple and well defined. The sfzformat.com website contains an extensive documentation
on it. At its core, an SFZ file describes a list of `region` objects on which a certain number of "opcodes" will
apply. Opcodes can determine the sample played, the event conditions that will trigger the sample such as the range
of notes, channels, velocities, the processing to apply on the sample while playing, and many more things. It is
also possible to describe a `group` of regions, as well as exclusive groups that will shut off other regions that may
already be playing. There are also `master` groups, and `global` opcodes and some other types.
All the opcodes are declared within a header, in a pseudo-xml markup language that looks like this
```sfz
<global> volume=6
<control> set_cc4=5
<region> key=36 sample=kick.wav
```
Here we have 3 headers (`global`, `control` and `region`) and each header holds some opcodes. All of these opcodes
have a value---for example the volume is equal to 6 in the `global` header. Some opcodes also have parameters.
The `control` header holds an opcode `set_cc` with the parameter `4` and value `5`. The parameter here is the CC to set,
and the value at which to set it is 5.
The parsing logic of sfizz is handled through a base class called Parser---a very original choice. This parser has
a virtual callback that gets called whenever a header description is "complete", along with a list of opcodes that
apply to the header. Subclassing the Parser then allows to build different SFZ handlers, from full-blown synths as
with sfizz to simpler things such as printers (see in particular https://github.com/sfztools/sfz-flat/). If we look
at the core of the latter example, it will look something like the following
```cpp
class PrintingParser: public sfz::Parser
{
protected:
void callback(absl::string_view header, const std::vector<sfz::Opcode>& members) final
{
switch (hash(header)) // The hash(...) function transforms strings to large integers
{
case hash("global"): // It is also compile-time defined, which allows to do switch-case
// statements on strings, something that is usually not possible
globalMembers = members; // We save the global headers since they apply to the next
// region (and groups and masters)
masterMembers.clear();
groupMembers.clear();
break;
case hash("master"):
masterMembers = members; // So on
groupMembers.clear();
break;
case hash("group"):
groupMembers = members; // .. and so forth
break;
case hash("region"):
std::cout << "<" << header << ">" << ' '; // Now we print the region along with all the opcodes
// we memorized from earlier headers.
printMembers(globalMembers);
printMembers(masterMembers);
printMembers(groupMembers);
printMembers(members);
std::cout << '\n';
break;
default:
std::cout << "<" << header << ">" << ' ';
printMembers(members);
std::cout << '\n';
break;
}
}
private:
std::vector<sfz::Opcode> globalMembers;
std::vector<sfz::Opcode> masterMembers;
std::vector<sfz::Opcode> groupMembers;
void printMembers(const std::vector<sfz::Opcode>& members)
{
for (auto& member: members)
{
std::cout << member.opcode;
if (member.parameter)
std::cout << +*member.parameter;
std::cout << "=" << member.value;
std::cout << ' ';
}
}
};
```
The main function is then quite straightforward and we call a function from the Parser class that loads a file
```cpp
PrintingParser parser;
parser.loadSfzFile("my_sfz_file.sfz");
```
If you circle back to the parser you will see that opcodes are stored in an `Opcode` class. This class does some parsing
itself and separates the opcode name itself, parameters if any, and the value. Opcodes are very cheap to copy and pass
around because they only refer to characters in the file that are stored inside the `Parser` class, so feel free to
create vectors of them and move them around.
Note that you may also derive the loadSfzFile method if you have any processing you need to do before the actual parsing happens.
# Building the region list in sfizz
The callback method from sfizz is actually quite similar to the one shown above, except that instead of printing the region
we actually fill a big structure from it.

View file

@ -1,6 +0,0 @@
# sfizz
SFZ file format library
- [public C API](sfizz_8h.html)
- [public C++ API](classsfz_1_1_sfizz.html)

View file

@ -1,19 +0,0 @@
#!/bin/bash
# Must be called from the root directory
if [[ -f api_index.md ]]; then rm api_index.md; fi
cat >>api_index.md <<EOF
---
title: "API"
---
EOF
tags=()
for tag in $(git tag --list); do
if [[ ${tag} != "list" && ${tag} != *"test"* ]]; then
tag=$(echo "${tag}" | sed -r 's/v//g')
tags+=("${tag}")
fi
done
IFS=$'\n' tags=($(sort <<<"${tags[*]}")); unset IFS
for tag in "${tags[@]}"; do
echo "- [${tag}](${tag})" >> api_index.md
done

View file

@ -0,0 +1,185 @@
#!/usr/bin/env python3
"""
SPDX-License-Identifier: BSD-2-Clause
This code is part of the sfizz library and is licensed under a BSD 2-clause
license. You should have receive a LICENSE.md file along with the code.
If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
Converts the Doxygen XML output to a custom JSON structure.
The JSON output will be used on a Jekyll website,
parsed by a related layout (_layouts/doxygen.html).
Known bugs / wish list:
- Replace `strip_tags_in_text()` and `tag_list_as_string()` with a recursive
parsing function able to extract also detailed descriptions paragraphs
(E.g. `sfizz_oversampling_factor_t` has 3), getting rid of various
`@since`, `@note` and `@return`, which are parsed separately.
It should also covert the Doxygen custom tags (like <bold>, see below,
or should this be done by some XSLT trasformation file?).
- Tags in ALIASES list needs to be escaped (parsed by tag_list_as_string())
to avoid Doxygen convert them in its own tag structure, by loosing some
details (e.g.: <b style=\"color:blue\">true</b> becomes <bold>true</bold>).
- Merge the work done previously to be able to fully automate the process
to be used in various CIs.
"""
import xml.etree.ElementTree as ET
import json
# TODO: scan for files
tree = ET.parse('xml/classsfz_1_1_sfizz.xml')
root = tree.getroot()
data = {}
def strip_tags_in_text(element):
if element is None:
return ""
returned_string = element.text or ""
for t in element:
if t.tag == "ref":
returned_string += "<a href='#{}'>{}</a>".format(t.text.replace("()", ''), t.text)
returned_string += t.tail or ""
elif t.tag == "computeroutput":
returned_string += "<code>{}</code>".format(t.text)
returned_string += t.tail or ""
else:
returned_string += t.text or ""
returned_string += t.tail or ""
return returned_string.strip()
def tag_list_as_string(element_list):
if element_list is None or len(element_list) == 0:
return ""
if element_list[0].text is not None:
return element_list[0].text.strip()
returned_string = ""
for element in element_list:
for t in element:
# if t.tag == "bold": t.tag = 'b'
returned_string += ET.tostring(t, encoding="unicode")
return returned_string.strip()
name = root.find("./compounddef/compoundname")
kind = root.find("./compounddef").get("kind")
brief = root.find("./compounddef/briefdescription/para")
include = root.find("./compounddef/includes")
location = root.find("./compounddef/location").get("file")
language = root.find("./compounddef").get("language")
version = root.get("version")
if name is not None and name.text is not None: data["name"] = name.text
if kind is not None: data["kind"] = kind
if brief is not None and brief.text is not None: data["brief"] = brief.text.strip()
if include is not None and include.text is not None: data["include"] = include.text.strip()
if location is not None: data["location"] = location
if language is not None: data["language"] = language
if version is not None: data["doxygen_version"] = version
definitions = []
for sectiondef in root.iter("sectiondef"):
def_kind = sectiondef.get("kind")
definition = {}
members = []
definition["kind"] = def_kind
for memberdef in sectiondef:
member = {}
member["name"] = memberdef.find("name").text
type_member = memberdef.find("type")
initializer_member = memberdef.find("initializer")
brief_member = memberdef.find("briefdescription/para")
description_member = memberdef.find("detaileddescription/para")
return_member = memberdef.findall("detaileddescription/para/simplesect[@kind='return']/para")
since_member = memberdef.find("detaileddescription/para/simplesect[@kind='since']/para")
note_member = memberdef.find("detaileddescription/para/simplesect[@kind='note']/para")
if type_member is not None:
type_member = strip_tags_in_text(type_member)
if type_member != '':
member["type"] = type_member
if initializer_member is not None and initializer_member.text is not None:
member["initializer"] = initializer_member.text
if brief_member is not None:
member["brief"] = strip_tags_in_text(brief_member)
if description_member is not None:
description_member = strip_tags_in_text(description_member)
if description_member != '':
member["description"] = description_member
if return_member is not None:
return_member = tag_list_as_string(return_member)
if return_member != '':
member["return"] = return_member
if since_member is not None and since_member.text is not None:
member["since"] = since_member.text.strip()
if note_member is not None and note_member.text is not None:
member["note"] = strip_tags_in_text(note_member)
members.append(member)
if def_kind == "enum" or def_kind == "public-type":
enumvalues = []
for enumvalue in memberdef.iter("enumvalue"):
enum = {}
enum["name"] = enumvalue.find("name").text
initializer_member = enumvalue.find("initializer")
brief_member = enumvalue.find("briefdescription/para")
description_member = enumvalue.find("detaileddescription/para")
if initializer_member is not None and initializer_member.text is not None:
enum["initializer"] = initializer_member.text
if brief_member is not None:
enum["brief"] = strip_tags_in_text(brief_member)
if description_member is not None:
enum["description"] = strip_tags_in_text(description_member)
enumvalues.append(enum)
member["values"] = enumvalues
params = []
for paramtag in memberdef.findall("param"):
param = {}
param["name"] = paramtag.find("declname").text
param["type"] = strip_tags_in_text(paramtag.find("type"))
param_items = memberdef.findall("detaileddescription/para/parameterlist[@kind='param']/parameteritem")
for param_item in param_items:
param_name = param_item.find("parameternamelist/parametername").text
if param_name == param.get("name"):
description = param_item.find("parameterdescription/para")
if description is not None:
param["description"] = strip_tags_in_text(description)
params.append(param)
if params:
member["params"] = params
definition["members"] = members
definitions.append(definition)
data["definitions"] = definitions
print(json.dumps(data, indent=2))

View file

@ -245,7 +245,7 @@ if(WIN32)
configure_file (${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in ${PROJECT_BINARY_DIR}/innosetup.iss @ONLY)
endif()
configure_file (${PROJECT_SOURCE_DIR}/doxygen/scripts/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY)
configure_file (${PROJECT_SOURCE_DIR}/scripts/doxygen/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY)
add_library (sfizz::parser ALIAS sfizz_parser)
add_library (sfizz::sfizz ALIAS sfizz_static)