TweetFollow Us on Twitter

Sound Wired
Volume Number:1
Issue Number:9
Column Tag:Assembly Language Lab

"Wired for Sound"

By Chris Yerga, MacTutor Contributing Editor

Can You Keep a Secret?

One of the Macintosh's best kept secrets is its wonderful sound driver. This beauty is capable of generating a variety of sounds including simple tones, multi-voice music, complex speech, and digitally recorded sounds. In spite of its power, it is relatively easy to use once the programmer takes the time to understand a few basic concepts. This month's column concerns itself with the sound driver and the techniques the programmer must employ to use it. First will come a description of the device manager, with emphasis on it's relation to the sound driver in particular. The actual sound driver description is next, followed by a sample program that ties it all together.

First Things First

First, a bit of background information on the device manager. The device manager is the part of the Macintosh ROM that allows the use and control of devices, which are usually hardware peripherals connected to the Mac. Examples of devices are the serial ports, the disk drives, the sound driver, etc (desk accessories are also considered devices, however, we will not include them in our general discussion).

There are two types of devices: character and block. Character devices can read or write only one character at a time and they must do so sequentially. That is, they cannot access any data other than the very next character. Whereas block devices read and write data in 512 character blocks and are randomly accessible. This means that they have access to any block of data, regardless of its position. Another matter of note is that many device manager routines may be executed either synchronously or asynchronously. Synchronous execution means that the calling program remains idle while the requested I/O operation is performed. Conversely, asynchronous I/O operations are performed while the calling program is running.

Now Some Specifics

The device manager is one of the portions of the Macintosh ROM that has a register based calling interface. As you may remember from previous columns, this means that the programmer invokes the desired trap macro with address register A0 pointing to a data structure in memory. It is through this data structure that parameters are passed between the calling program and the routine.

The data structure that the device manager routines use is called the ioParamBlock (from here on abbreviated as ioPB). Figure 1 shows the structure of the ioPB. The numbers in parenthesis are the byte offsets from the base address of the ioPB. There is a byte-division ruler to the right of the figure to ease the judgement of lengths.

The programmer need not concern himself with the first four fields of the ioPB, the device manager routines use them internally.

The fifth field, ioCompletion, is used for asyncronous I/O operations. When the device manager has finished an asyncronous operation, it will jump to the routine pointed to by ioCompletion, if it is nonzero. For example, you could request that the device manager send a page of data asynchronously through the serial port. While the device manager was doing this, you could set up the next page of data to be sent. When finished, the device manager would jump to your completion routine, which in turn would send the next page of data.

Upon returning from a device manager call, the ioResult field will contain a code describing what error, if any, occurred. IoNamePtr is only used when first opening a device. It points to the name of the device to be opened. All open devices are assigned reference numbers by the device manager. These reference numbers must be specified by the calling program and are stored in the ioRefNum field.

The device driver allows Control/Status calls to certain devices. These calls allow the user to send commands to devices (such as configuration commands) or to get status information from devices. A control/status call requires that the programmer send a control code to the device; this code is contained in the CSCode field of the ioPB. Certain control calls also need parameters of their own. These parameters are passed through the CSParam field.

When a read or write call is made, the address of the data buffer is passed in ioBuffer. The number of bytes that the programmer wants to read or write is contained in the ioReqCount; the number of bytes successfully read or written is returned in ioActCount. IoPosMode and ioPosOffset are used only with block devices. They allow the data to be accessed non-sequentially.

To use the sound driver from assembly language, the programmer must set up the appropriate fields of the ioPB, load A0 with a pointer to it, and then call the trap macro. Asyncronous execution is flagged by appending ",ASYNC" to the end of the trap name. For example to write a data buffer to a device, you would set up it's reference # etc. in the ioPB, store a pointer to the buffer in the ioBuffer field, load A0, and then execute _Write,ASYNC.

The sound driver is broken into three pieces: the square-wave synthesizer, the four-tone synthesizer, and the free-form synthesizer. Each synthesizer generates a different type of sound and requires a specific amount of processor time. Each type of sound is generated by making a write call to the device manager requesting that the proper data is sent to the sound driver. The square-wave and four-tone synthesizers will be described here.

Nothing Fancy

The simplest subset of the sound driver is the square-wave synthesizer. When running asynchronously, the square-wave synthesizer uses approximately 2% of the processor's time- a modest degree of overhead. However, the type of sounds that this synthesizer is capable of creating are limited to simple tones or beeps.

To get the square-wave synthesizer going, the programmer simply writes a SWSythRec to the sound driver. The first word of the SWSythRec is -1. This tells the sound driver that the data in the record should be routed to the square-wave synthesizer. Following this is a list of tones to be produced. The end of the tone list is dentoed by a zero.

Each tone is 3 words long. The first word is the count value, where frequency = 783360 / count. Complete lists of count values for the C major scale and the equal tempered scale are contained in Inside Macintosh. The second word is the amplitude, or volume, of the tone. This value ranges from 0-255 inclusive, with 255 being maximum volume. The last word is the duration of the tone, in 1/60ths of a second.

An example set of data will make the above explanation clearer. The sample will be 3 tones with frequencies of 1000, 2000, and 4000 Hertz. The amplitude of the tones will be half volume. The lengths of the tones will be .5, 1, and 1.5 seconds.

The count values are calculated by dividing 783360 by the frequency. 783360/1000 = 783; 783360/2000 = 392; and 783360/4000 = 196. The amplitude will be 127 ( half of 255 ). Given that 1 second = 60 duration units, calculating the duration values is done by: (.5 )* 60 = 30; 1 * 60 = 60; 1.5 * 60 = 90.

The data looks like this:

A Barbershop Quartet in Your Mac

The four-tone synthesizer is the most taxing in terms of processor use- approximately 50%. However, it allows up to 4 tones to be produced simultaneously, allowing multi-voice music and chords to be produced. Its record, FTSynthRec, has the most complex structure of the three synthesizers.

The first word of data in the FTSynthRec is always a 1. Following this is the duration of the sound, again in 1/60ths of a second. Next are 4 pairs of values for each of the four tones to be produced.

The first long word of each pair is the rate value, a fixed-point number which is analogous to the SWSynthRec's count value. (A discussion of fixed-point numbers can be found on page 11 of the Memory Manager Introduction in Inside Macintosh ) In this case, the frequency is derived by the formula: frequency (Hz) = 1000000 / (11502.08 / rate). The last element of the pair is a long integer phase value. The phase can range in value from 0-255, and tells the square-wave synthesizer how many bytes in the tone's waveshape definition to skip before starting the tone (If this confuses you, don't worry about it. Great sounds can be created without any regard for phase).

After the four pairs of values come four Waveshape pointers, which point to waveshape definitions in memory. Each waveshape definition consists of 255 bytes that describe the shape of one pulse, or click, sent to the speaker. Consider a tone of any frequency. It is comprised of a series of pulses, or "clicks", that create a tone when generated at a certain rate. The pulse itself is a general unit used by all tones, and therefore has no effect on the frequency of the resulting tone if it is designed correctly. Figure 3 shows the waveform description of a square pulse. Although it is the simplest possible waveform to generate, it is not as "natural" sounding as a sine pulse. In most cases, a square pulse or a sine pulse will suffice; however, by changing the wave definition, various musical instruments can be simulated.

A C major chord will suit well for a set of sample data. This chord is comprised of the notes C, E, and G. The table in Inside Macintosh gives us fixed-point rate values of 3.03654, 3.79568, and 4.55481 for these notes. The equivalent hex values for these numbers are $030959, $03CBB0, and $048E06 respectively. A duration value of 60 will generate the sound for 1 second. Using the default phase value of 0, the only remaining task is the initialization of the waveshape definitions and pointers.

The sample waveshape definition is created by filling a 255 byte block of memory with data - the first half (bytes 0-127) with the value 255 and the last half (bytes 128-255) with the value 0. When this is done, the address of the block of memory is stored in the waveshape pointers of our three tones.

Here is a sample FTSynthRec with the data for a C major chord:

There are two other differences that make the four-tone synthesizer different from the square-wave synthesizer. After the FTSynthRec is set up in memory, it is not directly written to the sound driver. Rather, a six byte block is written. The first two bytes comprise an integer word of value 1. The last four bytes of this block contain a pointer to the actual FTSynthRec in memory. The second difference is that, by nature of this calling scheme, only one FTSynthRec can be written at a time. Therefore, it is necessary to loop if there is more than one sound to generate.

The program gives examples of using both the square-wave synthesizer and the four-tone synthesizer. One useful item is the macro named Center, which when given a string, the center X coordinate of the grafport, and the Y coordinate at which the text should appear, will draw the text centered at the given Y coordinate. This saves a great deal of "hit-and-miss" experimentation if, like me, you don't sit down and calculate the correct centers by hand.

With this information and a bit of patience, the average reader should be able to implement sound in his next assembly application to give it that special touch of style.


;                            
;   Sound Example #1   
;                            
;
; © 1985 By Chris Yerga for MacTutor 

INCLUDE MacTraps.D
 
;  Declare external labels 

XDEF    START 

; Define Macros

;  Note that this clever macro will center a
; string for you about the MidPT, on line Y
; for use with the _DrawString trap call.

MACRO   Center String,MidPT,Y = 

 CLR.W  -(SP)    ;Save room for INTEGER
 ;width of string
 PEA  '{String}' 
 _StringWidth  
 CLR.L  D3;Clear the high word of  ;D3 so the DIVU works 
 MOVE.W (SP)+,D3 ;Get the width (in pixels) in D3 
 DIVU #2,D3 ;Divide by 2
 MOVE.L #{MidPT},D4
 SUB.W  D3,D4  ;Subtract (Width/2) ;from center point 
 MOVE.W D4,-(SP) ;Push the X cordinat
 MOVE.W #{Y},-(SP);Push the Y cordinat
 _MoveTo;Position the pen 
 PEA  '{String}' 
 _DrawString 
|;End of Macro symbol 
;*** Local Constants ***

AllEvents EQU  $0000FFFF
MaxEvents EQU  12 
DWindLenEQU $AA  ; see DS storage area
 
; Start of Main Program 
 
BadPtr: _Debugger ;Should never get  ;here.  Is called when there is 
 ;a problem with the memory ;manager. 

START:  MOVEM.L  D0-D7/A0-A6,-(SP) LEA SAVEREGS,A0       MOVE.L
 A6,(A0)  MOVE.L A7,4(A0) 

;Initialize the ROM routines 

PEA-4(A5) ;QD Global ptr 
_InitGraf ;Init QD global 
_InitFonts;Init font manager 
_InitWindows;Init Window Mgr 
_InitMenus;Guess what...yes!
 
 CLR.L  -(SP)  
_InitDialogs
_TEInit ;Init ROM Text edit 

MOVE.L  #AllEvents,D0
_FlushEvents
_InitCursor ;Get the standard arrow     
;Allocate the memory that we need
 
MOVE.L  #50,D0 ;Get a 50 Byte ;nonrelocatable block 
_NewPtr 
 
CMP#0,D0;Did we get the block??
 BNE  BadPtr;Nope...jump to MacsBug 
LEAParamBlock,A1  ;Save the Ptr 
MOVE.L  A0,(A1)
MOVE.L  #255,D0
 
;Get a 255 byte block for waveform def 
_NewPtr,CLEAR    ;and fill it with
 ;zeros while you're at it 
CMP#0,D0;Did we get the mem? 
BNEBadPtr ;Nope...Debugger time 
LEAWave,A1;Save the Ptr 
MOVE.L  A0,(A1)     
; Set up the ioParamBlock fields     
MOVE.L  ParamBlock,A0
 ;Get the Ptr to ioParamBlock 
CLR.L 12(A0);No completion routine 
MOVE.W  #-4,24(A0) ;The Sound Driver reference # CLR.W   44(A0)
 ;Standard positioning 
CLR.L 46(A0);No offset for the write  
;Fill the Wave buffer with a simple ;Square Wave definition
  
MOVE.L  Wave,A0  ;Get the base     ;address of the block 
MOVE.L  #127,D0  ;Set up the wave definition

MakeWave:

 MOVE.B #255,(A0)+ ;Set bytes 0-127 of the wave def            
 ;and increment A0 
DBRA  D0,MakeWave  ;loop until 127...         
;Set up the Dialog Box 

CLR.L -(SP) ;Save room for DIalogPtr 
MOVE.W  #128,-(SP) ;The ResID of the dialog 
PEADStorage(A5)  ;Where to put the DialogRec 
MOVE.L  #-1,-(SP);Put it in front, 
_GetNewDialog  
LEADHandle,A2    ;Save handle, but keep it
MOVE.L  (SP),(A2);on the stack 
_DrawDialog ;Draw the dialog.. 
LEADHandle,A2  
MOVE.L  (A2),-(SP) ;Set the Dialog to  ;the current GrafPort 
_SetPort    
MOVE.W  #7,-(SP) ;Select Athens 
_TextFont 
MOVE.W  #18,-(SP);in 18Pt size 
_TextSize   

Center  Sound Example #1,206,35      
MOVE.W  #1,-(SP) ;Select Chicago 
_TextFont 
MOVE.W  #12,-(SP);in 12Pt size 
_TextSize   

Center  ©1985 Chris Yerga for MacTutor,206,52 

; Main Event Loop 

MAIN:   

CLR.L -(SP) ;NIL for FilterProc 
PEAItemHit;VAR ItemHit 
_ModalDialog;handle the dialog for us! 
MOVE  ItemHit,D0 ;Get the result 

CMP#1,D0;Is it Square Wave? 
BEQSquare ;Yes....   
CMP#2,D0;Is it 4Tone? 
BEQFourTone ;You got it....   
CMP#3,D0;Is it Bye Bye?? 
BEQ   Adios ;Uh huh...    
BRAMain ;Keep going till we get    ;a valid event...      
Square: 
 
MOVE.L  ParamBlock,A0 ;Get the Ptr to ioParamBlock 
MOVE.L  #SqEnd-SqBegin,36(A0) ;The length of the data, so we   
 ;can tell the device manager
 ;how much to write  
LEASqBegin,A1    ;Ptr to our data buffer 
MOVE.L  A1,32(A0) 
_Write  ;this is the actual Write call.                        
 ;Be sure to have A0 pointing to   ;your ioParamBlock!   
BRAMain ;We're done for now..  

SqBegin: 

DC.W  -1;This tells the sound ;driver that the data is         
 ;for the square-wave     ;driver. 

 ;Play the C major diatonic scale... 
 
DC.W  5937,128,20  ;C
DC.W  5278,128,20  ;D 
DC.W  4750,128,20  ;E
DC.W  4453,128,20  ;F 
DC.W  3958,128,20  ;G
DC.W  3562,128,20  ;A
DC.W  3167,128,20  ;B
DC.W  2969,128,20  ;C
DC.W  3167,128,20  ;B
DC.W  3562,128,20  ;A 
DC.W  3958,128,20  ;G 
DC.W  4453,128,20  ;F 
DC.W  4750,128,20  ;E 
DC.W  5278,128,20  ;D 
DC.W  5937,128,20  ;C 
DC.W  0,0,0 
SqEnd:  DC.W0  ;End of the data  

FourTone:
 
MOVE.L  ParamBlock,A0 ;Get the Ptr to  ;our ioParamBlock 
MOVE.L  #6,36(A0)  ;ioCount (how many   ;bytes to write)       
  ;in this case always     ;6 bytes  
MOVE.L  Wave,A2  ;Get the Ptr to the 
 ;waveshape def 
LEAFTSynthRec,A1 ;Get the Ptr to the sound table 
MOVE.L  #3,D0    ;Loop 4 times 

SetWave: 
 
MOVE.W  #30,(A1) ;Set the tone length  ;to .5 seconds 
ADDA  #34,A1;Adjust A1 to point    ;to WavePtr fields 
MOVE.L  A2,(A1)+ ;Set 1st WavePtr 
MOVE.L  A2,(A1)+ ;Set 2nd WavePtr 
MOVE.L  A2,(A1)+ ;Set 3rd WavePtr 
MOVE.L  A2,(A1)+ ;Set 4th WavePtr 
DBRA  D0,SetWave   
LEAFTBegin,A3    ;Set the BuffPtr in ;the ParamBlock 
MOVE.L  A3,32(A0);to point to our data ;buffer 
LEAFTSynthRec,A2 ;Set the FTSRecPtr  ;in the Data
MOVE.L  #3,D3    ;Loop 4 times 

FTLoop: MOVE.L A2,2(A3) ;Set the
 ;pointer to point 
 ;to the next sound  
MOVE.L  ParamBlock,A0 ;Get Ptr to  ;ioParamBlock in A0 
_Write  ;Write it! 
ADDA  #50,A2;Point to the next     ;tone record 
DBRA  D3,FTLoop    ;and loop...    
BRAMain ;Thank you...    

;The four-tone record is unique in that it is not actually written ;to 
the sound driver.  Rather,  only a ptr to the actual tones is ;written. 
This means that only one set of 4 tones can be written ;at a time. 

FTBegin:  

DC.W 1  ;Four tone = 1 
DC.L   0  ;Holder for Ptr to the actual
        ;tones   

 FTSynthRec:   

DC.W  60;Do sound for 1 sec 
DC.L  $3CBB0,0    
DC.L  $5B188,0
DC.L  $4DBC3,0
DC.L  $00000,0 
DC.L  0,0,0,0    ;Place holders for  ;WavePtr's          
DC.W  60;Do sound for 1 sec 
DC.L  $36A85,0
DC.L  $50F95,0   
DC.L  $6D50A,0   
DC.L  $00000,0   
DC.L  0,0,0,0    ;Place holders for  ;WavePtr's          
DC.W  75;.5 SEC 
DC.L  $287CA,0   
DC.L  $3CBB0,0   
DC.L  $30959,0 
DC.L  $00000,0   
DC.L  0,0,0,0    

DC.W  30  
DC.L  $1E5D8,0   
DC.L  $287CA,0 
DC.L  $30959,0   
DC.L  $00000,0   
DC.L  0,0,0,0     

ADIOS:  LEA SaveRegs,A0   MOVE.L (A0),A6     
 MOVE.L 4(A0),A7 
 MOVEM.L(SP)+,D0-D7/A0-A6 RTS 

; Program Variables 
 
SaveRegs: DCB.L  2,0 ;For saving the SP etc.. 

DHandle:DC.L0    ;For the dialog Handle 
ItemHit:DC.W0    ;For _ModalDialog ParamBlock:     
 DC.L 0 ;For the ioPB 
Wave: DC.L0 ;For the WaveShape definition 

; Dialog Record 
 
DStorage: DS.W   DWindLen 
;  END OF SOURCE CODE


;     Resource File    
; for Sound Exercize #1
 
RESOURCE 'BDOG' 0 'IDENTIFICATION' 

STRING_FORMAT  2 
DC.B  'FREEWAVE VER -0.1 OF 3/19/85' STRING_FORMAT  0 

.ALIGN 2 
RESOURCE 'BNDL' 128 'BUNDLE' 

DC.L  'BDOG';Name of Signature
DC.W  0,1 ;Data 

DC.L  'FREF';FREF Mappings 
DC.W  0 ;1 Mapping ( 1-1 = 0 ) 
DC.W  0,128  
DC.L  'ICN#';ICN# Mappings 
DC.W  0 ;2 Mappings ( 1-1 = 0 ) 
DC.W  0,128
 
.ALIGN 2 
RESOURCE 'FREF' 128 'FREF#1' 
 
DC.B  'APPL',0,0,0  
.ALIGN 2 
RESOURCE 'ICN#' 128 'Application Icon' 

INCLUDE WaveIcon.ASM 

.ALIGN 2 
RESOURCE 'ICON' 128 'DlogIcon' 

INCLUDE SoundIcon.ASM 

;      Dialog Box    

.ALIGN 2 
RESOURCE 'DLOG' 128 'AboutBox' STRING_FORMAT  2
DC.W  95,50,270,462;BoundsRect
DC.W  1 ;ProcID
DC.B  1,1 ;TRUE for visible
DC.B  0,0 ;FALSE for GoAway 
DC.L  0 ;Refcon (Chuckle!)
DC.W  129 ;DITL ResID
DC.B  'HI';Title (unused) 

;    Dialog Box Items    
.ALIGN 2 
RESOURCE 'DITL' 129 'AboutBox items' 

DC.W  3 ;4 Items in the list 
 ;(4 - 1) = 3
;  Item #1   
DC.L  0 ;Handle holder
DC.W  114,41,136,201 ;BoundsRect 
DC.B  4 ;Button 
DC.B  'Square Wave ' ;Text Preceded by length byte 
;  Item #2     
DC.L  0 ;Handle holder
DC.W  114,210,136,361;BoundsRect DC.B4 ;Button
DC.B  'Four Tone '   ;Text Preceded by length byte 
;  Item #3   
DC.L  0 ;Handle holder
DC.W  144,41,166,361 ;BoundsRect 
DC.B  4 ;Button
DC.B  'Ive had enough fun for now' ;Text Preceded by length byte 
;  Item #4     
DC.L  0 ;Handle Holder
DC.W  60,194,92,226  ;BoundsRect
DC.B  128+32;Disabled Icon
DC.B  2 
DC.W  128 ;ICON ResID STRING_FORMAT  0 
 ;EOF 

Linker file

 !START

 /Output Sound

 ]
 
 SoundOff

 /Resources
 SOResource

 /TYPE 'APPL' 'BDOG'

 $
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

OnyX 3.2.4 - Maintenance and optimizatio...
OnyX is a multifunction utility that you can use to verify the startup disk and the structure of its system files, to run miscellaneous maintenance and cleaning tasks, to configure parameters in the... Read more
Opera 43.0.2442.991 - High-performance W...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more
VueScan 9.5.71 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
SpamSieve 2.9.28 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
GarageSale 7.0.7 - Create outstanding eB...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease. With GarageSale, you can create, edit, track, and manage... Read more
Thunderbird 45.7.1 - Email client from M...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
GarageSale 7.0.7 - Create outstanding eB...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease. With GarageSale, you can create, edit, track, and manage... Read more
SpamSieve 2.9.28 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
Thunderbird 45.7.1 - Email client from M...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Opera 43.0.2442.991 - High-performance W...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more

Last week on Pocket Gamer
If you’re wondering what’s going on in the wider world of portable gaming, our sister site PocketGamer has you covered. Each week we like to check in on the PG team and see what they’ve been preoccupied with. From the latest on the Nintendo Switch... | Read more »
Mudd Masher arrives this week
Atooi Games, the minds behind Totes the Goat and Mutant Mudds, have a new game in the works -- Mudd Masher. The game, a hybrid of the independent studio's first two titles, is expected to launch this week on March 2. [Read more] | Read more »
The best sales on the App Store this wee...
The App Store has quite an exciting lineup of discount games this week that range across a variety of genres. It's a great opportunity to catch up on some of the premium games you may have been holding off on -- and some you can even grab for free... | Read more »
The best new games we played this week
Ah, here we are again at the close of another busy week. Don't rest too easy, though. We had a lot of great new releases in mobile games this week, and now you're going to have to spend all weekend playing them. That shouldn't be too much of a... | Read more »
Rollercoaster Tycoon Touch Guide: How to...
| Read more »
Rabbids Crazy Rush Guide: How to unlock...
The Rabbids are back in a new endless running adventure, Rabbids Crazy Rush. It's more ridiculous cartoon craziness as you help the little furballs gather enough fuel (soda) to get to the moon. Sure, it's a silly idea, but everyone has dreams --... | Read more »
Tavern Guardians (Games)
Tavern Guardians 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Tavern Guardians is a Hack-and-Slash action game played in the style of a match-three. You can experience high pace action... | Read more »
Slay your way to glory in idle RPG Endle...
It’s a golden age for idle games on the mobile market, and those addictive little clickers have a new best friend. South Korean developer Ekkorr released Endless Frontier last year, and players have been idling away the hours in the company of its... | Read more »
Tiny Striker: World Football Guide - How...
| Read more »
Good news everyone! Futurama: Worlds of...
Futurama is finding a new home on mobile in TinyCo and Fox Interactive's new game, Futurama: Worlds of Tomorrow. They're really doing it up, bringing on board Futurama creator Matt Groening along with the original cast and writers. TinyCo wants... | Read more »

Price Scanner via MacPrices.net

13-inch 2.7GHz Retina MacBook Pro on sale for...
B&H Photo has the 2015 13″ 2.7GHz/128GB Retina Apple MacBook Pro on sale for $150 off MSRP. Shipping is free, and B&H charges NY tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro (MF839LL/A): $... Read more
13-inch 1.6GHz/256GB MacBook Air on sale for...
Newegg has the 13″ 1.6GHz/256GB MacBook Air (MMGG2LL/A) on sale for $1029.99 including free shipping. Their price is $170 off MSRP, and it’s the lowest price available for this model. Choose Newegg... Read more
Apple refurbished Apple TVs available for up...
Apple has Certified Refurbished 32GB and 64GB Apple TVs available for up to $30 off the cost of new models. Apple’s standard one-year warranty is included with each model, and shipping is free: -... Read more
27-inch 3.3GHz 5K iMac on sale for $2099, sav...
B&H Photo has the 27″ 3.3GHz 5K Apple iMac on sale for $2099.99 including free shipping plus NY sales tax only. Their price is $200 off MSRP. Amazon also has the 27″ 3.3GHz 5K iMac on sale for $... Read more
21-inch iMacs on sale for up to $111 off MSRP
B&H Photo has select 21″ Apple iMacs on sale for up to $110 off MSRP, each including free shipping plus NY sales tax only: - 21″ 2.8GHz iMac: $1189 $110 off MSRP - 21″ 1.6GHz iMac: $999 $100 off... Read more
12-inch 1.2GHz Retina MacBooks on sale for $2...
Newegg has the 12″ 1.2GHz Space Gray Retina MacBook (sku MLH82LL/A) on sale for $1349.99 including free shipping. Their price is $250 off MSRP, and it’s the lowest price available for this model.... Read more
13-inch MacBook Airs on sale for $100 off MSR...
B&H Photo has 13″ MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 1.6GHz/128GB MacBook Air (MMGF2LL/A): $899 $100 off MSRP - 13″ 1.6GHz/... Read more
9-inch 32GB Silver iPad Pro on sale for $549,...
B&H Photo has the 9.7″ 32GB Silver Apple iPad Pro on sale for $549 for a limited time. Shipping is free, and B&H charges NY sales tax only. Their price is $50 off standard MSRP for this model... Read more
13-inch 2.0GHz Apple MacBook Pros on sale for...
B&H has the non-Touch Bar 13″ 2.0GHz MacBook Pros in stock today and on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.0GHz MacBook Pro Space Gray (... Read more
15-inch Touch Bar MacBook Pros on sale for up...
B&H Photo has the new 2016 15″ Apple Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.7GHz Touch Bar... Read more

Jobs Board

*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 55676865 Los Angeles, California, United States Posted: Feb. 22, 2017 Weekly Hours: 40.00 **Job Summary** As an Apple Read more
Programmer/Editor *Apple* Music Dance - App...
# Programmer/Editor Apple Music Dance Job Number: 55565967 Culver City, California, United States Posted: Feb. 23, 2017 Weekly Hours: **Job Summary** Apple Music Read more
Digital Marketing Specialist - *Apple* iClo...
# Digital Marketing Specialist - Apple iCloud Job Number: 54729233 Culver City, California, United States Posted: Feb. 22, 2017 Weekly Hours: 40.00 **Job Summary** Read more
Marketing Specialist, iTunes & *Apple*...
# Marketing Specialist, iTunes & Apple Music Job Number: 55704205 Culver City, California, United States Posted: Feb. 23, 2017 Weekly Hours: 40.00 **Job Summary** Read more
*Apple* Wireless Lead - T-ROC - The Retail O...
…of knowledge in wireless sales and activations to the Beautiful and NEW APPLE Experiencestore within MACYS. THIS role, APPLE Wireless Lead, isbrandnewas MACYS Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.