|Version 12 (modified by sm0svx, 3 months ago)|
Contributing to the SvxLink project
There are a lot of ways in which you can contribute to the SvxLink project. Even if you are not a programmer, you can still contribute other things.
To be written... :-)
Qtel language translation
Creating a translation to another language for Qtel is rather simple. First you should install the software used for doing the translation. It is called Qt Linguist. In Fedora 14, for example, the package containing this utility is called qt3-devel. Then you need to get hold of a file containing the strings that should be translated. The easiest way to do this is to download the latest template file directly from this link: http://svn.code.sf.net/p/svxlink/svn/trunk/src/qtel/translations/qtel_tmpl.ts. Rename the downloaded template file, replacing "tmpl" with your ISO 639 language code. The language code consists of two or three letters (e.g. sv=Swedish, en=English). If you are not sure what your language code is, have a look on this page for example: http://www.loc.gov/standards/iso639-2/php/code_list.php. Use the two letter variant if available.
Now start Qt Linguist from the menu Programming/Qt3 Linguist and open the template file or launch it directly on the command line with:
Start translating! Help on using Qt Linguist is available inside that application so I won't repeat any of it here.
When you're done, compress the file (e.g. gzip qtel_xx.ts) and send it to the email@example.com mailing list.
Language translations already available are: German (de), Spanish (es), Hungarian (hu), Russian (ru), Swedish (sv), Turkish (tr) and Ukrainian (uk).
SvxLink Server language translation
The SvxLink Server application use sound clips to play back announcements. These are small sound clips that may range from part of a word to full help messages with multiple sentences. The default language used in SvxLink is US English so using that setup as a template is a good start. The end result after completing the steps below should be an archive containing sound clips and possibly some language specific TCL script adaptions. This is called a "language pack". More on the TCL script adaptions below.
Setting up the build environment
Start by setting up a build directory for the sounds and cd into it.
mkdir sounds cd sounds
Prepare the build environment by getting hold of the build scripts that are used to build the final sound clips. If you already have a checked out source tree the best way may be to softlink to the script files which can be found under src/svxlink/scripts/. Another way is to get them directly from Subversion.
svn export svn://svn.code.sf.net/p/svxlink/svn/trunk/src/svxlink/scripts/play_sound.sh svn export svn://svn.code.sf.net/p/svxlink/svn/trunk/src/svxlink/scripts/filter_sounds.sh
Set up a language pack template directory
Now decide what your directory for this translation should be called. The directory should be named "orig-ll_LL-name" where "ll" and "LL" should be replaced with the ISO language codes (e.g. sv_SE for Swedish) and name should be replaced with the voice name. The word "orig" should not be replaced since it just signifies that this is the original, unprocessed sound clip files. The default voice is called en_US-heather since it's US English and the voice is called Heather. To get a template to start from we now use the en_US-heather directory. This is most easily obtained using Subversion to get the latest version.
svn export svn://svn.code.sf.net/p/svxlink/svn/trunk/src/svxlink/scripts/sounds/en_US-heather orig-ll_LL-name
The orig-ll_LL-name directory now created should contain a base structure, configuration files and text files. The text files are the text representation used to generate a specific sound clip. Either keep them as a reference or remove them. If kept, they should be edited to reflect the language that the language pack is being created for.
Creating the clips
Now comes the hard part, which is generating all the sound clips. The preferred way to generate sound clips is to use the online service at Acapela Box. The service is not free but generate good quality sound clips in a lot of languages. Using a publicly available service is good since other people may want to generate additional sound clips for a specific installation and then it's easy to get the same voice. There are lots of other commercial text to speech applications but the license on the generated sound clips may make it illegal to release the clips publicly. There are also a number of free text to speech applications but I have so far not found one that is good enough. Of course it's also possible to use your own voice to record the sound clips but then only you can generate new sound clips with the same voice. The sampling rate for the sound clips should be at least 16kHz. If possible use an even higher sampling rate, like 48kHz, to get the highest quality in the originals. A script will be used later to convert the sampling rate to the one SvxLink is using.
So what sound clips should be generated then? In each subdirectory under orig-ll_LL-name you will find a configuration file called subdir.cfg. In this file you can find a list of file names for all sound clips that need to be generated for this subdirectory. The file contains three configuration variables. The two that is of interest right now is MAXIMIZE_SOUNDS and TRIM_SOUNDS. For each listed sound clip name, a corresponding wav file should be created that is named clipname.wav (e.g. help.wav, press_0_for_help.wav etc). Another way of finding out which clips to generate is to use the text files mentioned above. Simply generate a sound clip with the same name as the text file. For example, if there is a text file called help.txt, a file named help.wav should be created. What content the sound clip should have can be found out by looking at the content of the text file. Note that the text in some text files have been misspelled on purpose to force the text to speech system to generate the correct pronunciation.
A good tip is to start small and try the whole process of generating the final sound clips before going ahead and create all clips. Start with the clips is the Core subdirectory, the first one being "online". That clip should contain the translation of "SvxLink online".
Run the filter script
The script filter_sounds.sh is used to filter the sound clips to enhance them further. For example, the clips are maximized in level and silence is trimmed at the beginning and end to get them tighter together. The script use some configuration files. Directly under the orig-ll_LL-name directory there is a configuration file called filter_sounds.cfg. At this moment we're only interested in the SUBDIRS configuration variable. Comment out the original lines and set SUBDIRS="Core". This will make the script only process the Core directory. If we don't do this, an error message will be printed for each missing file and there will be a lot of them. Now we can try to run the script. You should stand in the same directory as where the script is located. This should be the "sounds" directory, that is the directory above the orig-ll_LL-name directory, if this instruction have been followed correctly. Now run the following.
./filter_sounds.sh orig-ll_LL-name ll_LL-name
This will process the files under the orig-ll_LL-name directory and put them in the ll_LL-name directory. The latter directory will contain the end product, the files that SvxLink can use. A warning will be printed for each missing file.
To try your language pack in SvxLink, copy the ll_LL-name directory to the sounds directory configured in SvxLink. See the InstallationInstructions for how to do that. If you only generated the online.wav clip you can trigger a manual identification (*) to make it use that clip. Missing sound clips will be printed out.
If everything seem to work, start creating the rest of the sound clips. The most important subdirectories are "Core" and "Default". Then there is one subdirectory for each SvxLink module. If it is desirable to tweak the quality of the sound in some way that is done in the filter_sounds.cfg file. Read the comments above the configuration variables to understand what they do. To choose which sound clips that should be created, edit the subdir.cfg file in each subdirectory. There may be clips that are unnecessary for a certain language and to suppress the error printout they should be removed from the subdir.cfg file.
Adapting the TCL scripts
Not all languages have the same word ordering as English have. In this case the TCL scripts, that decide in which order sound clips should be played, have to be modified for correct word ordering. Frequent candidates for differences is when announcing time and numbers. Time and numbers are handled in the file locale.tcl which can be found under the /usr/share/svxlink/events.d directory on a standard installed SvxLink system. Create a events.d directory in the orig-ll_LL-name directory and copy the locale.tcl file there. Then modify it for correct word ordering. If you don't know how to do this, request help on the svxlink-devel mailing list. The events.d directory will be copied to the target directory by the filter_sounds.sh script.
All new features should be developed using the latest code from Subversion. Check the source tree out like this:
svn co svn://svn.code.sf.net/p/svxlink/svn/trunk/src svxlink
Some guidelines for contributing code to SvxLink. If these are not followed it will take me longer to accept the patch and if it's really bad it will be rejected all together.
- Before putting in a lot of time to code a feature, send an e-mail to the svxlink-devel mailing list to see if someone else is working on something similar and that what you are about to do is in compliance with the architecture in SvxLink.
- Stick to the coding standards. Just look at existing code and do the same. Examples:
- Never ever change the TAB size in your editor. It should always be eight characters wide.
- Indentation should be two spaces.
- No single line of code should exceed 80 characters unless it is impossible to break it up.
- Variables are always in small caps. Words should be separated using underscore (e.g. my_variable)
- Member variables may be prefixed with "m_" to distinguish them from other variables (e.g. m_my_member_variable).
- Type and class definitions are written in upper camel case (e.g. MyClass)
- Member and class functions are written in lower camel case (e.g. myFunction)
- Macros and static constants are written in all upper case (e.g. MY_CONSTANT)
- One patch should ideally contain one new feature. If it contains a mix of features it will be harder to review the patch and also harder to accept one feature if another feature is not OK.
- Update the appropriate manual page if you have added a new feature.
Creating a patch
When you are satisfied with your work, send a patch to the mailing list (firstname.lastname@example.org). The patch should be created from the top source directory, never from a subdirectory. The top source directory is the one corresponding to ^/trunk/src in Subversion. That's the one we checked out above. The reason for always creating patches from the source root is that the patches are easier to apply then. Otherwise one have to first figure out from which directory level it was created to be able to apply it.
Creating a patch is very simple. If everything you have changed in the source tree should go into the patch, use the command below.
svn diff | gzip > /tmp/my_new_feature.patch.gz
If you don't want to include all changes in the patch, just point out the directories and/or files that you want to include. This should still be done from the top source directory. Don't cd into the subdirectory you want to create a patch for. The command below will for example create a patch of all changes in the async directory and the changes in the file svxlink/svxlink/Logic.cpp.
svn diff async svxlink/svxlink/Logic.cpp | gzip > /tmp/my_new_feature.patch.gz
Note that there is a 100kB limit set up on the mailing list so if the patch is bigger than that, you'll have to break it into multiple parts. This can be done using the split command.
split -b 90k my_new_feature.patch.gz my_new_feature.patch.gz.
This will produce 90k chunk files called my_new_feature.patch.gz.aa, my_new_feature.patch.gz.ab etc. Send each part in separate e-mails.
Subversion write access
If you contribute a lot of code, handling patches start to become a burden for both the contributor and for the one who are going to apply and check in the patches. If this is the case, you may be given write access to Subversion. However, this is not something that is lightly handed out. There should be a concrete need and you need to have contributed a number of bigger patches first.
The following guidelines should be followed or your write access may be revoked.
- For now, I (Tobias) want to be the only one checking code into trunk. That includes merging from branches unless I say otherwise.
- Don't check stuff into other branches than your own unless you have permission from the branch owner/creator.
- Try to keep branches as clean as possible. One branch should contain one new feature, if possible. Try to avoid lumping a lot of new features into one "personal" branch. The risk here is that the branch will grow larger while new features are added but not finished. Creating separate branches for each feature will encourage finishing implementing a feature so that it can be merged to trunk and then merged into other branches that need it.
- When creating a new branch, always do that from trunk and not from a subdirectory: svn cp ^/trunk ^/branches/my_branch, where ^ is an alias for the repository root URL (introduced in Subversion 1.5). This will reduce confusion.
- You are responsible for keeping your branches in sync with trunk. This is to make later merging easier and of course so that you get the latest features into the branches. It's pretty easy to do as well unless lots of changes conflict. Then it can be a bit of a pain. This should not be a big problem unless we start to have a lot of overlapping features being developed at the same time. Just do a "svn merge ^/trunk" now and then. You may need to modify that path, depending on how you checked out the svxlink source tree (e.g. svn merge ^/trunk/src).
- All checkins should have a meaningful comment. This is very important. The checkin comment will be shown on the Trac Timeline so it serves as information to other users of what is going on. It is also very important to have a good comment if one want to go back to check when something specific was changed. Maybe a bug was introduced at some point. It will be easier to find if a good comment is used.
- Try to check stuff in together that belong together in one go. Don't check it in file by file.
- Don't check multiple changes in together that don't directly belong together. One may later want to remove something that was checked in earlier. That will be much harder if multiple unrelated changes are lumped in the same checkin.
Here are some examples for developers for how to use Subversion in the SvxLink project.
Checking out trunk
Checking out trunk is probably the first thing you want to do. The checkout can be done on the trunk level but it's often more practical to do it on the src level instead.
svn co --username=user svn+ssh://email@example.com/p/svxlink/svn/trunk/src svxlink
Creating a branch
Creating a branch is simple. There is no separate branch command in Subversion. Instead, the copy command is used. It's easiest if you are standing in an already checked out source tree, for example trunk. Then the full URL:s does not have to be written.
svn cp ^/trunk ^/branches/my_branch -m "Created new branch my_branch"
Choose a good branch name which describes the purpose for it.
Checking out a branch
Checking out a branch is just as simple as checking out trunk.
svn co --username=user svn+ssh://firstname.lastname@example.org/p/svxlink/svn/my_branch/src my_branch-svxlink
Merging latest changes from trunk
Merging trunk into branches should be done by the branch maintainer regularly so that trunk and the branch don't drift too far apart.
Merging has been made much simpler in Subversion since version 1.5 when merge tracking was introduced. Before that, one had to manually keep track of which revisions had been merged previously. Now it's quite simple if you follow the guidelines below. Merging always have to be done in a clean source tree to not risk checking stuff in that has nothing to do with the merge. If your normal working copy is not clean, just check out a new clean copy.
Start by making sure that the source tree is up to date.
Then make sure it's clean. Only the current revision should be printed.
Merge the latest changes from trunk.
svn merge ^/trunk/src
Now fix any conflicts that was encountered. Files that have status "C" have a conflict. The files that have conflicts can be found using the following command.
svn st | grep ^C
When a conflict has been fixed, Subversion must be told so.
svn resolved path/to/file.cpp
Now make sure everything looks good and that it compiles. Always check the diff so that nothing unintentional will be checked in.
If you're in a graphical environment, the diff can be piped to a graphical diff application, for example "kompare".
svn diff | kompare -
If everything looks good you are now ready to check the merge in. The checkin message should contain the word "Merge" so that the merge points can be easily found in the log later. Also include the branch name. A good template look like this:
svn ci -m "Merged latest changes from ^/trunk/src into the my_branch branch"