giovedì 18 agosto 2011

GPSpeechSynth - General Purpose Speech Synth (UPDATED)

Is not clear to me why so many people want to have an iOS eSpeak port. All the applications built on top of such port cannot be distributed via Apple app store. May be the plan is to distribute on jailbreak iPhones.

So, you convinced me, let see what will happen. I just added the GPSpeechSynth library code on github. There is a Xcode project that generates three different static libraries. One based on eSpeak v1.44.05 (I didn't have time to update it to the latest version) and other two based on FLite 1.4
The library based on FLite 1.4 was successfully used in Math Teacher application that is now distributed by Apple. here you have the links:

UPDATE (17th Nov 2011):
I just added a working example in this repo.

john boydon

venerdì 4 marzo 2011

How to execute a NSTimer from NSThread

Few days ago I run into a problem related to user interaction on UIPickerView and a NSTimer. When the user interact with UIPickerView the NSTimer is delayed. That is obvious but really annoying.
I found a partial solution Naren blog, but unfortunately it is incomplete. I would like to stop and restart the NSTimer many times and with Naren's code there is a memory leak (NSThread).

The the final solution is the following:

@interface Test : NSObject
     NSTimer *_timer;
     NSRunLoop *_runLoop;
     NSThread *_timerThread;

- (void)suspendTimer;
- (void)resumeTimer;
- (void)timerFireMethod:(NSTimer*)timer;

@end // End Test interface

@implementation Test

- (void)suspendTimer
     if(_timer != nil)
          [_timer invalidate];
          [_timer release];
          _timer = nil;

          CFRunLoopStop([_runLoop getCFRunLoop]);

          [_timerThread release];
          _timerThread = nil;

- (void)_startTimerThread
     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

     _runLoop = [NSRunLoop currentRunLoop];
     _timer = [[NSTimer scheduledTimerWithTimeInterval:1.0
          repeats:YES] retain];
     [_runLoop run];
     [pool release];

- (void)resumeTimer
     if(_timer == nil)
          _timerThread = [[NSThread alloc] initWithTarget:self
          [_timerThread start];

- (void)timerFireMethod:(NSTimer*)timer
     // ...

@end // End Test implementation

For some strange reason NSRunLoop class doesn't provide an API to stop the run loop. The trick is to convert NSRunLoop into CFRunLoop and stop it.

In NSRunLoop class description is specified that the methods are not thread safe. I didn't experienced any problems with this implementation. As alternative the code above can be completely written using CFRunLoop type and functions:

  • [NSRunLoop currentRunLoop] -> CFRunLoopCurrent()
  • NSRunLoop * -> CFRunLoopRef
In CFRunLoop documentation I didn't found any thread safety warning.

Enjoy !


mercoledì 22 settembre 2010

iPhone VS GPLv3/v2 (UPDATED^2)

Hi all, as pointed out in a comment, there are some problems with ESpeak license (GPLv3) and other open source libraries that I ported to iPhone.

Seems that the GPLv3 is not compatible with Apple AppStore constraints.

Here you have an interesting discussion:

Seems that the only possibility to use ESpeak in an application compatible with AppStore constraints is to release it with a double-license (GPLv3 and GPLv2 for iPhone for example). To do that all the ESpeak contributors must accept the change..... almost impossible !!!

I will give up this porting, it is pity because it is working well !

UPDATE-1: Thanks to Tejas Shah there are some good news. He found an application in Apple AppStore that uses eSpeak: SpeakToMe

So seems that is possible to have commercial application that are compliant with GPLv3 in AppStore.

I will continue with this port and publish soon the results on github.

UPDATE-2: The life is hard !
I am really confused, see VLC story and this page. What should I do ?


giovedì 22 luglio 2010

iOS-ESpeak API proposal (UPDATE)

I would like to know your opinion of the following API proposal.
Instead of using an API like the one defined in NSSpeechSynthesizer where the strings are parsed every time you want to speech it, I decided to divide the 'parsing' and 'speaking' responsibility in two different classes:
  • ESSpeechSynthesizer
  • ESSpeechSynthesis
Here you have the API.

* ESSpeechSynthesis
* =================
* This class represent an unmutable synthesized message ready to be played.
@interface ESSpeechSynthesis : NSObject
{ .. }

@property(nonatomic, assign) id delegate;
@property(nonatomic, readonly) NSString *string;
@property(nonatomic, retain) NSString *identifier;
@property(nonatomic, readonly) NSDictionary *properties;

- (BOOL)isSpeaking;
- (BOOL)startSpeaking;
- (void)stopSpeaking;
- (void)pauseSpeaking;
- (void)continueSpeaking;


* ESSpeechSynthesisDelegate
* =========================
* This protocol represent the Synthesis delegate.
@protocol ESSpeechSynthesisDelegate

- (void)speechSynthesisBeginInterruption:(ESSpeechSynthesis *)sender;
- (void)speechSynthesisEndInterruption:(ESSpeechSynthesis *)sender;

- (void)speechSynthesisDecodeErrorDidOccur:(ESSpeechSynthesis *)sender error:(NSError *)error;
- (void)speechSynthesisDidFinishPlaying:(ESSpeechSynthesis *)sender successfully:(BOOL)flag;


* ESSpeechSynthesizer
* ===================
* This class represent a singleton that can convert a string into a sound message.
@interface ESSpeechSynthesizer: NSObject
{ ... }

@property(nonatomic, readonly) NSString* defaultVoice;
@property(nonatomic, retain) NSString* voice;

// ...

+ (ESSpeechSynthesizer *)sharedESSpeechSynthesizer;

- (NSArray *)availableVoices;
- (NSDictionary *)attributesForVoice:(NSString *)voice;

- (ESSpeechSynthesis *)synthesize:(NSString *)text;


Here you have an example of how to use this API:

// First obtain the synthesize singleton instance.
ESSpeechSynthesizer *synth = [ESSpeechSynthesizer sharedESSpeechSynthesizer];

// Then configure it, in this case just setup the voice language.
[synth setVoice:@"english"];

// Convert string into sound
ESpeechSynthesis speech = [synth synthesize:msg];

// Some log
NSLog(@"Available voices: %@", [synth availableVoices]);
NSLog(@"Start speacking: %@", speech);

// Set the delegate for notification
[speech setDelegate:self];

// Start speaking
[speech startSpeaking];

// This method will be invoked when the speaking is terminated
- (void)speechSynthesizerDidFinishPlaying:(ESSpeechSynthesis *)sender successfully:(BOOL)flag
// Release here if sound is not needed anymore
[speech release];
speech = nil;

All comments are welcome.

UPDATE: Please notice that the ESSpeechSynthesizer API is not thread safe, What do you think about a new thread safe method like the following:

@interface ESSpeechSynthesizer: NSObject

- (ESSpeechSynthesis *)synthesize:(NSString *)text properties:(NSDictionary *)props;


Where the dictionary instance is used to specify the synthesis attributes like: voice, gender, pitch, ....

As usual all comments are welcome !


martedì 20 luglio 2010

I am still alive !

Unfortunately some months ago my beloved mac die and no money for a new one. But after a while I collected enough money for beautiful hackintosh, here you have the specs:
  • INTEL i7 860 2.8 GHz
  • Corsair H50 liquid cooler
  • Gigabyte GA-P55-UD6
  • Patriot 8 GByte, 1600
  • NVidia geForce 9800 GT
  • 2x 500 GByte Segate HDD
  • LG DVD Drive
  • Cooler Master case
Now the next step is to overclock it to 4 GHz.... I will keep you informed.
Many many many many thanks to Tonymac for the Beast !


venerdì 8 gennaio 2010

Git Repository Created (Updated)

Hi all, I just created an account on and start adding the following XCode projects in it:

venerdì 14 agosto 2009

Exception Stack Trace on iPhone

In case of exception, the stack trace provided in the console is completely useless. But Google toolbox for mac can provide all required information. Have a look here.

Now you can really enjoy the exception raised.