mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-25 11:11:05 +00:00
122 lines
2.5 KiB
Mathematica
122 lines
2.5 KiB
Mathematica
|
#import "GSSpeechEngine.h"
|
||
|
#include <flite/flite.h>
|
||
|
|
||
|
cst_voice *register_cmu_us_kal();
|
||
|
|
||
|
/**
|
||
|
* Implementation of a speech engine using flite. This should be the default
|
||
|
* for resource-constrained platforms.
|
||
|
*/
|
||
|
@interface FliteSpeechEngine : GSSpeechEngine {
|
||
|
/** The audio device used for sound output. */
|
||
|
cst_audiodev *ad;
|
||
|
/** The current voice. Only one supported at the moment. */
|
||
|
cst_voice *v;
|
||
|
/** Flag set to tell the playback thread to exit. */
|
||
|
volatile BOOL shouldEndSpeaking;
|
||
|
/** Flag indicating whether the engine is currently speaking. */
|
||
|
volatile BOOL isSpeaking;
|
||
|
}
|
||
|
@end
|
||
|
|
||
|
@implementation FliteSpeechEngine
|
||
|
+ (void)initialize
|
||
|
{
|
||
|
flite_init();
|
||
|
|
||
|
}
|
||
|
- (id)init
|
||
|
{
|
||
|
if (nil == (self = [super init])) { return nil; }
|
||
|
|
||
|
// Only one voice supported by flite unless others are compiled in.
|
||
|
v = register_cmu_us_kal();
|
||
|
if (NULL == v)
|
||
|
{
|
||
|
[self release];
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
// Each wave should be the same format.
|
||
|
cst_wave *w = flite_text_to_wave("test", v);
|
||
|
ad = audio_open(w->sample_rate, w->num_channels, CST_AUDIO_LINEAR16);
|
||
|
delete_wave(w);
|
||
|
if (NULL == ad)
|
||
|
{
|
||
|
[self release];
|
||
|
return nil;
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
- (void)sayString: (NSArray*)args
|
||
|
{
|
||
|
id pool = [NSAutoreleasePool new];
|
||
|
NSString *aString = [args objectAtIndex: 0];
|
||
|
int i,n,r;
|
||
|
int num_shorts;
|
||
|
BOOL didFinish = YES;
|
||
|
cst_wave *w = flite_text_to_wave([aString UTF8String], v);
|
||
|
|
||
|
num_shorts = w->num_samples * w->num_channels;
|
||
|
for (i=0; i < num_shorts; i += r/2)
|
||
|
{
|
||
|
if (num_shorts > i+CST_AUDIOBUFFSIZE)
|
||
|
{
|
||
|
n = CST_AUDIOBUFFSIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
n = num_shorts-i;
|
||
|
}
|
||
|
r = audio_write(ad, &w->samples[i], n*2);
|
||
|
if (shouldEndSpeaking)
|
||
|
{
|
||
|
didFinish = NO;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
isSpeaking = NO;
|
||
|
NS_DURING
|
||
|
[[args objectAtIndex: 1] didFinishSpeaking: didFinish];
|
||
|
NS_HANDLER
|
||
|
NS_ENDHANDLER
|
||
|
[args release];
|
||
|
[pool release];
|
||
|
delete_wave(w);
|
||
|
}
|
||
|
- (void)startSpeaking: (NSString*)aString notifyWhenDone: (id)aDelegate
|
||
|
{
|
||
|
[[[aDelegate delegate] connectionForProxy] enableMultipleThreads];
|
||
|
NSArray *arg = [[NSArray alloc] initWithObjects: aString, aDelegate, nil];
|
||
|
shouldEndSpeaking = NO;
|
||
|
isSpeaking = YES;
|
||
|
[NSThread detachNewThreadSelector: @selector(sayString:)
|
||
|
toTarget: self
|
||
|
withObject: arg];
|
||
|
|
||
|
}
|
||
|
- (BOOL)isSpeaking
|
||
|
{
|
||
|
return isSpeaking;
|
||
|
}
|
||
|
- (void)stopSpeaking
|
||
|
{
|
||
|
shouldEndSpeaking = YES;
|
||
|
// Spin until the other thread has died.
|
||
|
while (isSpeaking) {}
|
||
|
}
|
||
|
- (void)dealloc
|
||
|
{
|
||
|
[self stopSpeaking];
|
||
|
audio_close(ad);
|
||
|
[super dealloc];
|
||
|
}
|
||
|
@end
|
||
|
|
||
|
@implementation GSSpeechEngine (Flite)
|
||
|
+ (GSSpeechEngine*)defaultSpeechEngine
|
||
|
{
|
||
|
return [[[FliteSpeechEngine alloc] init] autorelease];
|
||
|
}
|
||
|
@end
|