#!/usr/bin/perl
# Rob van Son,   20010221
# David Weenink, 20000629

# CGN label as key in hash array.
#    values: 0. phoneme category.
#            1. phonetic label in praat's longchar notation.
#            2. label as part of file name.

# Manner: Vowel, Glide, Stops, Fricatives, Nasals, Others
# Articulator: Labial, Coronal, Dorsum, Body, Root, Glottal, Oral (?)
# Voicing: +/-
#
#              Manner Articulator Voicing
###############################################################################
#
# Copyright David Weenink, R.J.J.H. van Son © 2000, 2001
#
# Author David Weenink, Rob van Son
# Institute of Phonetic Sciences & ACLC
# University of Amsterdam
# Herengracht 338
# NL-1016CG Amsterdam, The Netherlands
# Email: Rob.van.Son@hum.uva.nl
#        rob.van.son@workmail.com
# WWW  : http://www.fon.hum.uva.nl/rob/
# mail:  Institute of Phonetic Sciences
#        University of Amsterdam
#        Herengracht 338
#        NL-1016CG Amsterdam
#        The Netherlands
#        tel +31 205252183
#        fax +31 205252197
#
# License for use and disclaimers
#
# 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#
#######################################################
#
%CGN_phonemes = (
#Vowels (klinkers)
# Note: In a rather arbitrary way, (minor) articulators 
# are associated with the three corners and the center 
# of the vowel triangle: 
# j(aw) to /EaAE+/	(Open)
# d(orsal) to /iIey/	(High/Front)
# b(ody) to /OouO+/	(Low/Back)
# n(eutral) to /@Y299+/	(Central)
        'I',    ['V', 'd', '+',         'lip:   l I p'],
        'E',    ['V', 'j', '+',         'leg:   l E g'],
        'A',    ['V', 'j', '+',         'lat:   l A t'],
        'O',    ['V', 'b', '+',         'bom:   b O m'],
        'Y',    ['V', 'n', '+',         'put:   p Y t'],
        'i',    ['V', 'd', '+',         'liep:  l i p'],
        'y',    ['V', 'd', '+',         'buur:  b y r'],
        'e',    ['V', 'd', '+',         'leeg:  l e x'],
        '2',    ['V', 'n', '+',         'deuk:  d 2 k'],
        'a',    ['V', 'j', '+',         'laat:  l a t'],
        'o',    ['V', 'b', '+',         'boom:  b o m'],
        'u',    ['V', 'b', '+',         'boek:  b u k'],
        '@',    ['V', 'n', '+',         'gelijk: x @ - l E+ k'],
        'E+',   ['V', 'j', '+',         'wijs:  w E+ s'],
        '9+',   ['V', 'n', '+',         'huis:  h 9+ s'],
        'A+',   ['V', 'b', '+',         'koud:  k A+ t'],
        'O+',   ['V', 'b', '+',         'koud:  k O+ t'],
        'Y+',   ['V', 'n', '+',         'duidelijk: d Y+ d @ l @ k'],
        'a:',   ['V', 'j', '+',         'laat:  l a t'],
        'e:',   ['V', 'd', '+',         'leeg:  l e x'],
        'o:',   ['V', 'b', '+',         'boom:  b o m'],
        'E:',   ['V', 'j', '+',         'scene: s E: - n @'],
        '9:',   ['V', 'n', '+',         'freule:        f r 9: - l @'],
        'O:',   ['V', 'b', '+',         'zone:  z O: - n @'],
        'E~',   ['V', 'j', '+',         'vaccin:        v A k - s E~'],
        'A~',   ['V', 'j', '+',         'croissant:     k r w A - s A~'],
        'O~',   ['V', 'b', '+',         'conge: k O~ - Z e'],
        'Y~',   ['V', 'n', '+',         'parfum:        p A r - f Y~'],

#Glides & semivowels (klinkerachtigen)
        'l',    ['G', 'C', '+',         'lat:   l A t'],
        'r',    ['G', 'B', '+',         'rat:   r A t'],
        'w',    ['G', 'L', '+',         'wat:   w A t'],
        'j',    ['G', 'D', '+',         'jas:   j A s'],

#Stops (plosieven)
        'p',    ['S', 'L', '-',         'put:   p Y t'],
        'b',    ['S', 'L', '+',         'bad:   b A t'],
        't',    ['S', 'C', '-',         'tak:   t A k'],
        'd',    ['S', 'C', '+',         'dak:   d A k'],
        'k',    ['S', 'B', '-',         'kat:   k A t'],
        'g',    ['S', 'B', '+',         'goal:  g o l'],

#Fricatives (fricatieven
        'f',    ['F', 'L', '-',         'fiets: f i t s'],
        'v',    ['F', 'L', '+',         'vat:   v A t'],
        's',    ['F', 'C', '-',         'sap:   s A p'],
        'z',    ['F', 'C', '+',         'zat:   z A t'],
        'S',    ['F', 'D', '-',         'sjaal: S a l'],
        'Z',    ['F', 'D', '+',         'ravage:        r a - v a - Z @'],
        'x',    ['F', 'B', '-',         'licht: l I x t'],
        'G',    ['F', 'B', '+',         'regen: r e - G @'],
        'h',    ['F', 'G', '-',         'geheel:        x @ - h e l'],

#Nasals (nasalen)
        'N',    ['N', 'B', '+',         'lang:  l A N'],
        'm',    ['N', 'L', '+',         'mat:   m A t'],
        'n',    ['N', 'C', '+',         'nat:   n A t'],
        'J',    ['N', 'D', '+',         'oranje:        o - r A - J @'],

#Others (Stilte, maar de schwa kan ook een "pauze" zijn)
        '*',    ['O', '-', '-',          'SIL:   *'],
        'SIL',  ['O', '-', '-',          'SIL:   SIL'],
);

@CGN_phonemeOrder = (
        #Vowels
        'A~', 'E~', 'Y~', 'O~', 'O:', '9:', 'E:', 'O+', '9+', 'E+', 'Y+',  
        'a', 'u', 'o', '2', 'e', 'y', 'i', 'Y', 'O', 'A', 'E', 'I', '@',
        #Glides & semivowels,
        'l', 'r', 'w', 'j', 
        #Nasals,
        'J', 'N', 'm', 'n', 
        #Fricatives,
        'z', 's', 'Z', 'S', 'v', 'f', 'G', 'x', 'h',
        #Stops,
        'b', 'd', 'g', 'p', 't', 'k', 
        #Others,
        '*', 'SIL', 
);

@CGN_phonemeTypeOrder = ('V', 'G', 'N', 'S', 'F', 'O');

sub isVowel
{
        $CGN_phonemes{$_[0]}[0] eq 'V' ? 1 : 0
};

sub isPlosive
{
        $CGN_phonemes{$_[0]}[0] eq 'S' ? 1 : 0
};

sub isFricative
{
        $CGN_phonemes{$_[0]}[0] eq 'F' ? 1 : 0
};

sub isOther
{
        $CGN_phonemes{$_[0]}[0] eq 'O' ? 1 : 0
};

sub sameCategory
{
        $CGN_phonemes{$_[0]}[0] eq $CGN_phonemes{$_[1]}[0] ? 1 : 0
};

# Convert CGN phoneme string into a Manner transcription
sub CGNtoManner	# (CGNstring) -> Mannerstring
{
	my $string = shift || "";
	$string =~ 
	s/(\S[\+\~\:]?)/$CGN_phonemes{"$1"}[0] ? $CGN_phonemes{"$1"}[0] : $1;/iseg;
	return $string;
};
# Convert CGN phoneme string into an Articulation transcription
sub CGNtoArticulator	# (CGNstring) -> Articulatorstring
{
	my $string = shift || "";
	$string =~ 
	s/(\S[\+\~\:]?)/$CGN_phonemes{"$1"}[1] ? $CGN_phonemes{"$1"}[1] : '-';/iseg;
	return $string;
};
# Convert CGN phoneme string into a Voicing transcription
sub CGNtoVoicing	# (CGNstring) -> Voicingstring
{
	my $string = shift || "";
	$string =~ 
	s/(\S[\+\~\:]?)/$CGN_phonemes{"$1"}[2] ? (($CGN_phonemes{"$1"}[2] eq '+') ? 'V' : 'U') : $1;/iseg;
	return $string;
};

# Construct reverse Articulator, Manner, Voicing hastables with phoneme regexp patterns
sub MannerRegexpHash	# () -> %MannerRegexpHash
{
	my %MannerRegexpHash = ();
	my $phoneme, $manner;
	foreach $phoneme (keys(%CGN_phonemes))
	{
		$MannerRegexpHash{$CGN_phonemes{$phoneme}[0]} .= "$phoneme|";
	};
	
	foreach $manner (keys(%MannerRegexpHash))
	{
		chop($MannerRegexpHash{$manner});
		$MannerRegexpHash{$manner} =~ s/([\+\:\~\*])/[\1]/g;
	};
	
	return %MannerRegexpHash;
};

sub ArticulatorRegexpHash	# () -> %ArticulatorRegexpHash
{
	my %ArticulatorRegexpHash = ();
	my $phoneme, $articulator;
	foreach $phoneme (keys(%CGN_phonemes))
	{
		$ArticulatorRegexpHash{$CGN_phonemes{$phoneme}[1]} .= "$phoneme|";
	};
	
	foreach $Articulator (keys(%ArticulatorRegexpHash))
	{
		chop($ArticulatorRegexpHash{$Articulator});
		$ArticulatorRegexpHash{$Articulator} =~ s/([\+\:\~\*])/[\1]/g;
	};
	
	return %ArticulatorRegexpHash;
};

sub VoicingRegexpHash	# () -> %VoicingRegexpHash
{
	my %VoicingRegexpHash = ();
	my $phoneme, $Voicing;
	foreach $phoneme (keys(%CGN_phonemes))
	{
		my $VoiceSymbol = ($CGN_phonemes{$phoneme}[2]) eq "+" ? 'V' : 'U';
		$VoicingRegexpHash{$VoiceSymbol} .= "$phoneme|";
	};
	
	foreach $Voicing (keys(%VoicingRegexpHash))
	{
		chop($VoicingRegexpHash{$Voicing});
		$VoicingRegexpHash{$Voicing} =~ s/([\+\:\~\*])/\[\1\]/g;
	};
	
	return %VoicingRegexpHash;
};

sub splitPhonemes   # (String) -> @ListOfPhonemes
{
    my $String = shift;
    
    my @PhonemeSymbols = map {$_;} sort {length($b) <=> length($a)} keys(%CGN_phonemes);
    my $MatchPhonemes = join("|", @PhonemeSymbols);

    $String =~ s/($MatchPhonemes|[\|\-])/\1 /g;
    @PhonemeList = split(' ', $String);

    return @PhonemeList;
}
# Make require happy
1;
