TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program SoundAndSpeech

Goto Contents

// *******************************************************************************************
// SoundAndSpeech.c                                                         CARBON EVENT MODEL
// *******************************************************************************************
//
// This program opens a modeless dialog containing five bevel button controls arranged in
// two groups, namely, a synchronous sound group and an asynchronous sound group.  Clicking on
// the bevel buttons causes sound to be played back or recorded as follows:
//
// o  Synchronous group:
//
//    o  Play sound resource.
//
//    o  Record sound resource (Mac OS 8/9 only).
//
//    o  Speak text string.
//
// o  Asynchronous group:
//
//    o  Play sound resource.
//
//    o  Speak text string.
//
// The asynchronous sound sections of the program utilise a special library called
// AsyncSoundLibPPC, which must be included in the CodeWarrior project.
//
// The program utilises the following resources:
//
// o  A 'plst' resource.
//
// o  A 'DLOG' resource and associated 'DITL', 'dlgx', and 'dftb' resources (all purgeable).
//
// o  'CNTL' resources (purgeable) for the controls within the dialog.
//
// o  Two 'snd ' resources, one for synchronous playback (purgeable) and one for asynchronous
//    playback (purgeable).
//
// o  Four 'cicn' resources (purgeable).  Two are used to provide an animated display which
//    halts during synchronous playback and continues during asynchronous playback.  The
//    remaining two are used by the bevel button controls.
//
// o  Two 'STR#' resources containing "speak text" strings and error message strings (all
//    purgeable).
//
// o  'hrct' and 'hwin' resources (purgeable) for balloon help.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// Each time it is invoked, the function doRecordResource creates a new 'snd' resource with a
// unique ID in the resource fork of a file titled "SoundResources".
//
// *******************************************************************************************

// .................................................................................. includes

#include <Carbon.h>
#include <string.h>

// ................................................................................... defines

#define rDialog                 128
#define  iDone                  1
#define  iPlayResourceSync      4
#define  iRecordResource        5
#define  iSpeakTextSync         6
#define  iPlayResourceASync     7
#define  iSpeakTextAsync        8
#define rPlaySoundResourceSync  8192
#define rPlaySoundResourceASync 8193
#define rSpeechStrings          128
#define rErrorStrings           129
#define  eOpenDialogFail        1
#define  eCannotInitialise      2
#define  eGetResource           3
#define  eMemory                4
#define  eMakeFSSpec            5
#define  eWriteResource         6
#define  eNoChannelsAvailable   7
#define  ePlaySound             8
#define  eSndPlay               9
#define  eSndRecord             10
#define  eSpeakString           11
#define rColourIcon1            128
#define rColourIcon2            129
#define kMaxChannels            8
#define kOutOfChannels          1

// .......................................................................... global variables

Boolean     gRunningOnX = false;
DialogRef   gDialogRef;
CIconHandle gColourIconHdl1;
CIconHandle gColourIconHdl2;

// .............................................................. AsyncSoundLib attention flag

Boolean  gCallAS_CloseChannel = false;

// ....................................................................... function prototypes

void      main                 (void);
void      doPreliminaries      (void);
OSStatus  windowEventHandler   (EventHandlerCallRef,EventRef,void *);
void      doIdle               (void);
void      doInitialiseSoundLib (void);
void      doDialogHit          (SInt16);
void      doPlayResourceSync   (void);
void      doRecordResource     (void);
void      doSpeakStringSync    (void);
void      doPlayResourceASync  (void);
void      doSpeakStringAsync   (void);
void      doSetUpDialog        (void);
void      doErrorAlert         (SInt16);
void      helpTags             (DialogRef);

// ......................................................... AsyncSoundLib function prototypes

OSErr  AS_Initialise   (Boolean *,SInt16);
OSErr  AS_GetChannel   (SInt32,SndChannelPtr *);
OSErr  AS_PlayID       (SInt16, SInt32 *);
OSErr  AS_PlayHandle   (Handle,SInt32 *);
void   AS_CloseChannel (void);
void   AS_CloseDown    (void);

// ************************************************************************************** main

void main(void)
{
  SInt32         response;
  EventTypeSpec  windowEvents[] = { { kEventClassWindow, kEventWindowClose },
                                    { kEventClassMouse,  kEventMouseDown   } };

  // ........................................................................ do preliminaries

  doPreliminaries();

  // .......................................... disable Quit item in Mac OS X Application menu

  DisableMenuCommand(NULL,'quit');

  // ......................................................................... install a timer
  
  InstallEventLoopTimer(GetCurrentEventLoop(),0,TicksToEventTime(10),
                        NewEventLoopTimerUPP((EventLoopTimerProcPtr) doIdle),NULL,
                        NULL);

  // .................................................................. open and set up dialog

  if(!(gDialogRef = GetNewDialog(rDialog,NULL,(WindowRef) -1)))
  {
    doErrorAlert(eOpenDialogFail);
    ExitToShell();
  }

  SetPortDialogPort(gDialogRef);
  SetDialogDefaultItem(gDialogRef,kStdOkItemIndex);

  ChangeWindowAttributes(GetDialogWindow(gDialogRef),kWindowStandardHandlerAttribute |
                                                      kWindowCloseBoxAttribute,
                                                      kWindowCollapseBoxAttribute);

  InstallWindowEventHandler(GetDialogWindow(gDialogRef),
                            NewEventHandlerUPP((EventHandlerProcPtr) windowEventHandler),
                            GetEventTypeCount(windowEvents),windowEvents,0,NULL);

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    helpTags(gDialogRef);
    gRunningOnX = true;
  }

  doSetUpDialog();

  // ................................................................ initialise AsyncSoundLib

  doInitialiseSoundLib();

  // ........................................................................ get colour icons

  gColourIconHdl1 = GetCIcon(rColourIcon1);
  gColourIconHdl2 = GetCIcon(rColourIcon2);

  // .............................................................. run application event loop

  RunApplicationEventLoop();
}

// *************************************************************************** doPreliminaries

void  doPreliminaries(void)
{
  MoreMasterPointers(64);
  InitCursor();
  FlushEvents(everyEvent,0);
}

// ************************************************************************ windowEventHandler

OSStatus  windowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
                             void* userData)
{
  OSStatus    result = eventNotHandledErr;
  UInt32      eventClass;
  UInt32      eventKind;
  EventRecord eventRecord;
  SInt16      itemHit;
  
  eventClass = GetEventClass(eventRef);
  eventKind  = GetEventKind(eventRef);

  switch(eventClass)
  {
    case kEventClassWindow:                                               // event class window
      switch(eventKind)
      {
        case kEventWindowClose:
          AS_CloseDown();
          QuitApplicationEventLoop();
          result = noErr;
          break;
      }

    case kEventClassMouse:                                                // event class mouse
      ConvertEventRefToEventRecord(eventRef,&eventRecord);
      switch(eventKind)
      {
        case kEventMouseDown:
          if(IsDialogEvent(&eventRecord))
          {
            if(DialogSelect(&eventRecord,&gDialogRef,&itemHit))
              doDialogHit(itemHit);
            result = noErr;
          }
          break;
      }
      break;
  }

  return result;
}

// ************************************************************************************ doIdle

void  doIdle(void)
{
  Rect           theRect, eraseRect;
  UInt32         finalTicks;
  SInt16         fontNum;
  static Boolean flip;

  SetRect(&theRect,262,169,294,201);
  SetRect(&eraseRect,310,170,481,200);

  if(gCallAS_CloseChannel)
  {
    AS_CloseChannel();

    GetFNum("\pGeneva",&fontNum);
    TextFont(fontNum);
    TextSize(10);
    MoveTo(341,189);
    DrawString("\pAS_CloseChannel called");
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(45,&finalTicks);
  }

  if(flip)
    PlotCIcon(&theRect,gColourIconHdl1);
  else
    PlotCIcon(&theRect,gColourIconHdl2);

  flip = !flip;

  EraseRect(&eraseRect);
}

// ********************************************************************** doInitialiseSoundLib

void  doInitialiseSoundLib(void)
{
  if(AS_Initialise(&gCallAS_CloseChannel,kMaxChannels) != noErr)
  {
    doErrorAlert(eCannotInitialise);
    ExitToShell();
  }
}

// ******************************************************************************* doDialogHit

void  doDialogHit(SInt16 item)
{
  switch(item) 
  {
    case iDone:
      AS_CloseDown();
      QuitApplicationEventLoop();
      break;

    case iPlayResourceSync:
      doPlayResourceSync();
      break;

    case iRecordResource:
      doRecordResource();
      break;

    case iSpeakTextSync:
      doSpeakStringSync();
      break;

    case iPlayResourceASync:
      doPlayResourceASync();
      break;

    case iSpeakTextAsync:
      doSpeakStringAsync();
      break;
  }
}

// ************************************************************************ doPlayResourceSync

void  doPlayResourceSync(void)
{
  SndListHandle sndListHdl;
  SInt16        resErr;
  OSErr         osErr;
  ControlRef    controlRef;

  sndListHdl = (SndListHandle) GetResource('snd ',rPlaySoundResourceSync);
  resErr = ResError();
  if(resErr != noErr)
    doErrorAlert(eGetResource);

  if(sndListHdl != NULL)
  {
    HLock((Handle) sndListHdl);
    osErr = SndPlay(NULL,sndListHdl,false);
    if(osErr != noErr)
      doErrorAlert(eSndPlay);
    HUnlock((Handle) sndListHdl);
    ReleaseResource((Handle) sndListHdl);

    GetDialogItemAsControl(gDialogRef,iPlayResourceSync,&controlRef);
    SetControlValue(controlRef,0);
  }
}

// ************************************************************************** doRecordResource

void  doRecordResource(void)
{
  SInt16     oldResFileRefNum, theResourceID, resErr, tempResFileRefNum;
  BitMap     screenBits;
  Point      topLeft;
  OSErr      memErr, osErr;
  Handle     soundHdl;
  FSSpec     fileSpecTemp;
  ControlRef controlRef;

  oldResFileRefNum = CurResFile();

  GetQDGlobalsScreenBits(&screenBits);
  topLeft.h = (screenBits.bounds.right / 2) - 156;
  topLeft.v = 150;
  
  soundHdl = NewHandle(25000);
  memErr = MemError();
  if(memErr != noErr)
  {
    doErrorAlert(eMemory);
    return;
  }

  osErr = FSMakeFSSpec(0,0,"\pSoundResources",&fileSpecTemp);
  if(osErr == noErr)
  {
    tempResFileRefNum = FSpOpenResFile(&fileSpecTemp,fsWrPerm);
    UseResFile(tempResFileRefNum);
  }
  else
    doErrorAlert(eMakeFSSpec);

  if(osErr == noErr)
  {
    osErr = SndRecord(NULL,topLeft,siBetterQuality,&(SndListHandle) soundHdl);
    if(osErr != noErr && osErr != userCanceledErr)
      doErrorAlert(eSndRecord);
    else if(osErr != userCanceledErr)
    {
      do
      {
        theResourceID = UniqueID('snd ');
      } while(theResourceID <= 8191 && theResourceID >= 0);

      AddResource(soundHdl,'snd ',theResourceID,"\pTest");
      resErr = ResError();
      if(resErr == noErr)
        UpdateResFile(tempResFileRefNum);
      resErr = ResError();
      if(resErr != noErr)
        doErrorAlert(eWriteResource);
    }

    CloseResFile(tempResFileRefNum);
  }

  DisposeHandle(soundHdl);
  UseResFile(oldResFileRefNum);

  GetDialogItemAsControl(gDialogRef,iRecordResource,&controlRef);
  SetControlValue(controlRef,0);
}

// ************************************************************************* doSpeakStringSync

void  doSpeakStringSync(void)
{
  SInt16     activeChannels;
  Str255     theString;
  OSErr      resErr, osErr;
  ControlRef controlRef;

  activeChannels = SpeechBusy();

  GetIndString(theString,rSpeechStrings,1);
  resErr = ResError();
  if(resErr != noErr)
  {
    doErrorAlert(eGetResource);
    return;
  }

  osErr = SpeakString(theString);
  if(osErr != noErr)
    doErrorAlert(eSpeakString);

  while(SpeechBusy() != activeChannels)
    ;

  GetDialogItemAsControl(gDialogRef,iSpeakTextSync,&controlRef);
  SetControlValue(controlRef,0);
}

// *********************************************************************** doPlayResourceASync

void  doPlayResourceASync(void)
{
  SInt16 error;

  error = AS_PlayID(rPlaySoundResourceASync,NULL);
  if(error == kOutOfChannels)
    doErrorAlert(eNoChannelsAvailable);
  else
    if(error != noErr)
      doErrorAlert(ePlaySound);
}

// ************************************************************************ doSpeakStringAsync

void  doSpeakStringAsync(void)
{
  Str255 theString;
  OSErr  resErr, osErr;

  GetIndString(theString,rSpeechStrings,2);
  resErr = ResError();
  if(resErr != noErr)
  {
    doErrorAlert(eGetResource);
    return;
  }

  osErr = SpeakString(theString);
  if(osErr != noErr)
    doErrorAlert(eSpeakString);
}

// ***************************************************************************** doSetUpDialog

void  doSetUpDialog(void)
{
  SInt16                        a;
  Point                         offset;
  ControlRef                    controlRef;
  ControlButtonGraphicAlignment alignConstant = kControlBevelButtonAlignLeft;
  ControlButtonTextPlacement    placeConstant = kControlBevelButtonPlaceToRightOfGraphic;

  offset.v = 1;
  offset.h = 5;

  for(a=iPlayResourceSync;a<iSpeakTextAsync+1;a++)
  {
    GetDialogItemAsControl(gDialogRef,a,&controlRef);
    SetControlData(controlRef,kControlEntireControl,kControlBevelButtonGraphicAlignTag,
                   sizeof(alignConstant),&alignConstant);
    SetControlData(controlRef,kControlEntireControl,kControlBevelButtonGraphicOffsetTag,
                   sizeof(offset),&offset);
    SetControlData(controlRef,kControlEntireControl,kControlBevelButtonTextPlaceTag,
                  sizeof(placeConstant),&placeConstant);
  }

  if(gRunningOnX)
  {
    GetDialogItemAsControl(gDialogRef,iRecordResource,&controlRef);
    DeactivateControl(controlRef);
  }
}

// ****************************************************************************** doErrorAlert

void  doErrorAlert(SInt16 errorStringIndex)
{
  Str255 errorString;
  SInt16 itemHit;

  GetIndString(errorString,rErrorStrings,errorStringIndex);

  StandardAlert(kAlertCautionAlert,errorString,NULL,NULL,&itemHit);
}

// ********************************************************************************** helpTags

void  helpTags(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));
  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 130;

  for(a = 1;a <= 5; a++)
  {
    if(a == 2)
      continue;
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,a + 3,&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

// *******************************************************************************************

Demonstration Program SoundAndSpeech Comments

When this program is run, the user should click on the various buttons in the dialog to play
back and record (Mac OS 8/9 only) sound resources and to play back the provided "speak text"
strings.  The user should observe the effects of asynchronous and synchronous playback on the
"working man" icon in the image well in the dialog.  The user should also observe that the text
"AS_CloseChannel called" appears briefly in the secondary group box to the right of the
"working man" icon when AsynchSoundLib sets the application's "attention" flag to true, thus
causing the application to call the AsynchSoundLib function AS_CloseChannel.

Note that the doRecordResource function saves recorded sounds as 'snd ' resources with unique
IDs in the resource fork of the file titled "SoundResources".

On Mac OS 9, ensure that the Speech Manager extension is activated before running this program.

defines

kMaxChannels will be used to specify the maximum number of sound channels that AsynchSoundLib
is to open.  kOutOfChannels will be used to determine whether the AsynchSoundLib function
AS_PlayID returns a "no channels available" error.

main

A timer is installed and set to fire repeatedly every 10 ticks.  When the timer fires, the
function doIdle is called.

doInitialiseSoundLib is called to initialise the AsynchSoundLib library.

doIdle

doIdle is called every time the timer fires.

The "attention" flag (gAS_CloseChannel) required by AsynchSoundLib is checked.  If
AsynchSoundLib has set it to true, the AsynchSoundLib function AS_CloseChannel is called to
free up the relevant ASStructure, close the relevant sound channel, and clear the "attention"
flag.  In addition, some text is drawn in the group box to the right of the "working man" icon
to indicate to the user that AS_CloseChannel has just been called.

The next block draws one or other of the two "working man" icons, following which the interior
of the group box is erased.

doInitialiseSoundLib

doInitialiseSoundLib initialises the AsynchSoundLib library.  More specifically, it calls the
AsynchSoundLib function AS_Initialise and passes to AsynchSoundLib the address of the
application's "attention" flag (gAS_CloseChannel), together with the requested number of
channels.

If AS_Initialise returns a non-zero value, an error alert is displayed and the program
terminates.

doPlayResourceSync

doPlayResourceSync is the first of the synchronous playback functions.  It uses SndPlay to play
a specified 'snd ' resource.

GetResource attempts to load the resource.  If the subsequent call to ResError indicates an
error, an error alert is presented.

If the load was successful, the sound handle is locked prior to a call to SndPlay.  Since NULL
is passed in the first parameter of the SndPlay call, SndPlay automatically allocates a sound
channel to play the sound and deallocates the channel when the playback is complete.  false
passed in the third parameter specifies that the playback is to be synchronous.

Note: The 39940-byte 'snd ' resource being used contains one command only (bufferCmd).  The
compressed sound header indicates MACE 3:1 compression.  The sound length is 119568 frames. 
The 8-bit mono sound was sampled at 22kHz.
SndPlay causes all commands and data contained in the sound handle to be sent to the channel. Since there is a bufferCmd command in the 'snd ' resource, the sound is played. If SndPlay returns an error, an error alert is presented. When SndPlay returns, HUnlock unlocks the sound handle and ReleaseResource releases the resource.

doRecordResource

On Mac OS 8/9 only, doRecordResource uses SndRecord to record a sound synchronously and then
saves the sound in a 'snd ' resource.  The 'snd ' resource will be saved to the resource fork
of the file "SoundResources".

The first line saves the file reference number of the current resource file.  The next three
lines establish the location for the top left corner of the sound recording dialog.

NewHandle creates a relocatable block.  The address of the handle will be passed as the fourth
parameter of the SndRecord call.  The size of this block determines the recording time
available.  (If NULL is passed as the fourth parameter of a SndRecord call, the Sound Manager
allocates the largest block possible in the application's heap.)  If NewHandle cannot allocate
the block, an error alert is presented and the function returns.

The next block opens the resource fork of the file "SoundResources" and makes it the current
resource file.

SndRecord opens the sound recording dialog and handles all user interaction until the user
clicks the Cancel or Save button.  Note that the second parameter of the SndRecord call
establishes the location for the top left corner of the sound recording dialog and that the
third parameter specifies 22kHz, mono, 3:1 compression.

When the user clicks the Save button, the handle is resized automatically.  If the user clicks
the Cancel button, SndRecord returns userCanceledErr.  If SndRecord returns an error other than
userCanceledErr, an error alert is presented and the function returns after closing the
resource fork of the file, disposing of the relocatable block, and restoring the saved resource
file reference number.

The relocatable block allocated by NewHandle, and resized as appropriate by SndPlay, has the
structure of a 'snd ' resource, but its handle is not a handle to an existing resource.  To
save the recorded sound as a 'snd ' resource in the resource fork of the current resource file,
the do/while loop first finds an acceptable unique resource ID for the resource.  (For the
System file, resource IDs for 'snd ' resources in the range 0 to 8191 are reserved for use by
Apple Computer, Inc.  Avoiding those IDs in this demonstration is not strictly necessary, since
there is no intention to move those resources to the System file.)

The call to AddResource causes the Resource Manager to regard the relocatable block containing
the sound as a 'snd ' resource.  If the call is successful, UpdateResFile writes the changed
resource map and the 'snd ' resource to disk.  If an error occurs, an error alert is presented.

The relocatable block is then disposed of, the resource fork of the file "SoundResources" is
closed, and the saved resource file reference number is restored.

doSpeakStringSync

doSpeakStringSync uses SpeakString to speak a specified string resource and takes measures to
cause the speech to be generated in a psuedo-synchronous manner.

The speech that SpeakString generates is asynchronous, that is, control returns to the
application before SpeakString finishes speaking the string.  In this function, SpeechBusy is
used to cause the speech activity to be synchronous so far as the function as a whole is
concerned.  That is, doSpeakStringSync will not return until the speech activity is complete.

As a first step, the first line saves the number of speech channels that are active immediately
before the call to SpeakString.

GetIndString loads the first string from the specified 'STR#' resource.  If an error occurs, an
error alert is presented and the function returns.

SpeakString, which automatically allocates a speech channel, is called to speak the string.  If
SpeakString returns an error, an error alert is presented.

Although SpeakString returns control to the application immediately it starts generating the
speech, the speech channel it opens remains open until the speech concludes.  While the speech
continues, the number of speech channels open will be one more that the number saved at the
first line.  Accordingly, the while loop continues until the number of open speech channels is
equal to the number saved at the first line.  Then, and only then, does doSpeakStringSync exit.

doPlayResourceASync

doPlayResourceASync uses the AsynchSoundLib function AS_PlayID to play a 'snd ' resource
asynchronously.

Note: The 24194-byte 'snd ' resource being used contains one command only (bufferCmd).  The
compressed sound header indicates no compression.  The sound length is 24195 frames.  The 8-bit
mono sound was sampled at 5kHz.

AS_PlayID is called to play the 'snd ' resource specified in the first parameter. Since no further control over the playback is required, NULL is passed in the second parameter. (Recall that, if you pass a pointer to a variable in the second parameter, AS_PlayID returns a reference number in that parameter. That reference number may be used to gain more control over the playback process. If you simply want to trigger a sound and let it to run to completion, you pass NULL in the second parameter, in which case a reference number is not returned by AS_PlayID.) If AS_PlayID returns the "no channels currently available" error, an error alert is presented advising of that specific condition. If any other error is returned, a more generalised error message is presented. When the sound has finished playing, ASynchSoundLib advises the application by setting the application's "attention" flag to true. Recall that this will cause the AsynchSoundLib function AS_CloseChannel to be called to free up the relevant ASStructure, close the relevant sound channel, clear the "attention" flag, and draw some text in the group box to the right of the image well to indicate to the user that AS_CloseChannel has just been called.

doSpeakStringAsync

doSpeakStringAsync is identical to the function doSpeakStringSync except that, in this
function, SpeechBusy is not used to delay the function returning until the speech activity
spawned by SpeakString has run its course.

doSetUpDialog

Within doSetUpDialog, the Record Sound Resource bevel button is disabled if the program is
running on OS X.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

VOX 2.8.24 - Music player that supports...
VOX just sounds better! The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features and support for all audio formats you should ever need.... Read more
Dropbox 24.4.17 - Cloud backup and synch...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
OmniPlan Pro 3.7.1 - Professional-grade...
With OmniPlan Pro, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success... Read more
OmniPlan 3.7.1 - Robust project manageme...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Adium 1.5.10.4 - Popular instant messagi...
Adium is a fast and free instant messaging client which supports AIM, ICQ, Jabber, MSN, Yahoo!, Google Talk, Yahoo! Japan, Bonjour, Gadu-Gadu, Novell Groupwise, SIP/SIMPLE (Text), and Lotus Sametime... Read more
SteerMouse 5.1 - Powerful third-party mo...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
File Juicer 4.57 - $18.00
File Juicer is a drag-and-drop can opener and data archaeologist. Its specialty is to find and extract images, video, audio, or text from files which are hard to open in other ways. In computer... Read more
1Password 6.7 - Powerful password manage...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
CleanMyMac 3.8.1 - $39.95
CleanMyMac makes space for the things you love. Sporting a range of ingenious new features, CleanMyMac lets you safely and intelligently scan and clean your entire system, delete large, unused files... Read more
Monolingual 1.7.8 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. If you use your computer in only one (human) language, you... Read more

Latest Forum Discussions

See All

Olli by Tinrocket (Photography)
Olli by Tinrocket 1.0 Device: iOS iPhone Category: Photography Price: $2.99, Version: 1.0 (iTunes) Description: Get drawn in with Olli by TinrocketOlli instantly turns your everyday moments into hand-drawn art and animations. • Watch... | Read more »
Penarium (Games)
Penarium 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: | Read more »
Fire Emblem Heroes is way more profitabl...
Profits for Nintendo's mobile game Fire Emblem Heroes are apparently impressive enough to beat out other Nintendo titles likeSuper Mario Run, despite having 10 times fewer downloads. [Read more] | Read more »
Classic series Robot Unicorn Attack 3 no...
The classic Adult Swim browser game, Robot Unicorn Attack, branched off into a series of popular mobile games. Now, the latest entry into the series, Robot Unicorn Attack 3, is available for iOS and Android mobile devices. [Read more] | Read more »
Sudoku Sweeper (Games)
Sudoku Sweeper 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: A minimalist mashup of Minesweeper and Sudoku. Logic puzzle perfection. Every row, column and zone contains a bomb and one of... | Read more »
Under Leaves (Games)
Under Leaves 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: Journey into the forest, the jungle or the depths of the deep blue sea. Find chestnuts for the pigs, a caterpillar for the... | Read more »
Ninja Pizza Girl (Games)
Ninja Pizza Girl 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: In the not-so-distant future, rampart traffic congestion has resulted in only one way to deliver pizzas across town in thirty... | Read more »
SCRAP (Games)
SCRAP 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: That day, for no apparent reason, SCRAP decided to wake up and run. He had to, because his activation was a mistake the "Factory" could... | Read more »
The Bunker (Games)
The Bunker 1.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.1 (iTunes) Description: The critically acclaimed console hit "The Bunker" comes to iOS, The groundbreaking live-action thriller adventure set in a real... | Read more »
Die With Glory (Games)
Die With Glory 1.2.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.2.0 (iTunes) Description: Die with Glory is an epic adventure game where your goal is to die in glorious fashion. You must help Sigurd, a brave old... | Read more »

Price Scanner via MacPrices.net

New System Clock for macOS by B-Eng Now Avail...
Fehraltorf, Switzerland based B-Eng has announced the release and immediate availability of System Clock, the company’s new system monitor and information app developed exclusively for macOS. System... Read more
DEVONtechnologies Celebrates 15th Anniversary...
DEVONtechnologies celebrates its 15th company anniversary with a 30% discount on all its software products from May 1st through 5th, 2017. In spring 2002, DEVONtechnologies opened its website and... Read more
WaterField Designs Invites Customers to Help...
San Francisco based WaterField Designs invites customers and air travelers to participate in developing the next generation in-flight travel case, the Air Porter. Frustrated with limited legroom,... Read more
Save up to $260 with Apple refurbished 12-inc...
Apple has Certified Refurbished 2016 12″ Retina MacBooks available for $200-$260 off MSRP. Apple will include a standard one-year warranty with each MacBook, and shipping is free. The following... Read more
Digital Paper Tablet Offers Distraction Free...
I typically spend 8-10 hours a day gazing at the screens in my laptops and iPad, as tools of my livelihood, I don’t as a rule use electronic devices for pleasure reading. I subscribe to a daily... Read more
“Today at Apple” Bringing New Educational Ses...
Apple has announced plans to launch dozens of new educational sessions next month in all 495 Apple Stores ranging in topics from photo and video to music, coding, art and design, and more. The hands-... Read more
Smart Finance Free Comprehensive Personal Fin...
Moscow-based indie developer, Alexander Survillo has announced the release and immediate availability of Smart Finance: Personal Finance, Budget & Money 1.1.4, an update to his comprehensive... Read more
12-inch 1.1GHz Retina MacBooks on sale for $1...
B&H has 12″ 1.1GHz Retina MacBooks on sale for $100 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1199.99 $100 off MSRP - 12... Read more
13-inch 2.7GHz Retina MacBook Pro on sale for...
B&H Photo has the 13″ 2.7GHz Retina MacBook Pro on sale for $130 off MSRP. Shipping is free, and B&H charges NY & NJ tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro (MF839LL/A): $1169 $... Read more
15-inch 2.2GHz Retina MacBook Pros available...
B&H Photo has the 15″ 2.2GHz Retina MacBook Pro available for $200 off MSRP including free shipping plus NY & NJ sales tax only: - 15″ 2.2GHz Retina MacBook Pro (MJLQ2LL/A): $1799.99 $200 off... Read more

Jobs Board

*Apple* Retail - Multiple Positions- Chicago...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Systems Engineer - California Polyte...
Cal Poly, San Luis Obispo Apple Systems Engineer Department: ITS - Customer & Tech Support (134900) College/Division: Academic Affairs Salary Range: Position Read more
*Apple* Mobile Master - Best Buy (United Sta...
**501042BR** **Job Title:** Apple Mobile Master **Location Number:** 000416-East Lansing-Store **Job Description:** **What does a Best Buy Apple Mobile Master Read more
Best Buy *Apple* Computing Master - Best Bu...
**501195BR** **Job Title:** Best Buy Apple Computing Master **Location Number:** 000211-Colorado Blvd-Store **Job Description:** **What does a Best Buy Apple Read more
*Apple* Mac Computer Technician - GeekHampto...
…complex computer issues over the phone and in person? GeekHampton, Long Island's Apple Premium Service Provider, is looking for you! Come work with our crew Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.