Source code for Macintosh II start beep

On internet I find source code for Mac Plus start beep but can't any information about Macintosh II start beep or how create it. Any person from Apple early history can help about this? Original 68000 assembly fine.Thanks!

Answered by 级三包 in 61627022

/* C code for Macinitosh II start beep */

/* Mac_II.c */

/* Boot Beep Mac II */

/* 级三包 */

/* 2558/09/06 */



#include <stdio.h>



#define kNUMBER_SAMPLES 30000

#define kDELAY_NOTE 300

#define kWAVE_TABLE_VALUE 0x30013f10

#define kSAMPLE_RATE 22257 // Hz



void prepareWaveTable( unsigned short *waveTable, unsigned int value );

void upDateWaveTable( unsigned short *waveTable, unsigned short chiSo );

void saveSound( char *fileName, short *soundData, unsigned int numberFrames, unsigned int sampleRate );



int main () {


// ---- wave table

unsigned short waveTable[256];

// ---- sound data, stereo

short soundData[kNUMBER_SAMPLES << 1];

// ---- increment array (16/16 bit fix point integer)

int arrayIncrement[] = {3 << 16, 4 << 16, (3 << 16) + 0x2f2, 6 << 16};


// ---- prepare wave table

prepareWaveTable( waveTable, kWAVE_TABLE_VALUE );



// ---- array phase (16/16 bit fix point integer)

unsigned int arrayPhase[] = {0, 0, 0, 0}; // set all = 0



unsigned int sampleNumber = 0;

while( sampleNumber < kNUMBER_SAMPLES ) {



// ---- calculate sample

unsigned int channelLeft = 0;

unsigned int channelRight = 0;

unsigned char noteNumber = 0;

while ( noteNumber < 4 ) {

// ---- see if should update phase for note, only do if play note

if( sampleNumber >= noteNumber*kDELAY_NOTE ) {

// ---- up date phase before

arrayPhase[noteNumber] += arrayIncrement[noteNumber];

// ---- not let out of range [0; 255]

if( arrayPhase[noteNumber] > 0xff0000 ) // 0xff0000 == 255 << 16

arrayPhase[noteNumber] -= 0xff0000; // return to begin of wave table

}

unsigned short mauVat = waveTable[arrayPhase[noteNumber] >> 16];



// ---- add sound components

if( noteNumber < 2 ) // ---- first 2 notes left channel

channelLeft += mauVat;

else // ---- last 2 notes right channel

channelRight += mauVat;

// ---- next note

noteNumber++;

}

// ---- save left and right samples

soundData[sampleNumber << 1] = (channelLeft << 9) - 0x8000; // use << 1 for 16 bit

soundData[(sampleNumber << 1) + 1] = (channelRight << 9) - 0x8000; // use << 1 for 16 bit

upDateWaveTable( waveTable, sampleNumber & 0xff );

sampleNumber++;

}


// ---- save WAV file

saveSound( "Mac II.wav", soundData, sampleNumber << 1, kSAMPLE_RATE ); // multiply 2 because stereo



return 1;

}



void prepareWaveTable( unsigned short *waveTable, unsigned int value ) {



// ---- prepare wave table

unsigned short index = 0;

unsigned short waveTableValue = value & 0xff;

while( index < 64 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}



waveTableValue = (value >> 8) & 0xff;

while( index < 128 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}



waveTableValue = (value >> 16) & 0xff;

while( index < 192 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}


waveTableValue = (value >> 24) & 0xff;

while( index < 256 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}

}



void upDateWaveTable( unsigned short *waveTable, unsigned short index ) {


// ---- get value from wave table

unsigned short value = waveTable[index];


// ---- calculate new value for wave table

if( index == 255 ) { // careful at last element of wave table

value += waveTable[0];

value = (value >> 1);

waveTable[0] = value;

}

else {

value += waveTable[index+1];

value = (value >> 1);

waveTable[index+1] = value;

}



}



#pragma mark ---- SAVE WAV

void saveHeader( FILE *fileName, unsigned int sampleRate );

void saveSoundDataInteger16bit( FILE *fileName, short *soundData, unsigned int numberSamples );



void saveSound( char *fileName, short *soundData, unsigned int numberFrames, unsigned int sampleRate ) {


// ---- open file

FILE *file = fopen( fileName, "wb" );


if( file ) {

// ---- "RIFF"

fprintf( file, "RIFF" );

// ---- length sound file - 8

unsigned int lengthSoundFile = 32;

lengthSoundFile += numberFrames << 1; // một không có một mẫu vạt cho kênh trái và phải

// ---- save file length

fputc( (lengthSoundFile) & 0xff, file );

fputc( (lengthSoundFile >> 8) & 0xff, file );

fputc( (lengthSoundFile >> 16) & 0xff, file );

fputc( (lengthSoundFile >> 24) & 0xff, file );

// ---- "WAVE"

fprintf( file, "WAVE" );

// ---- save header

saveHeader( file, sampleRate );

// ---- save sound data

saveSoundDataInteger16bit( file, soundData, numberFrames );

// ---- close file

fclose( file );

}

else {

printf( "Problem save file %s\n", fileName );

}

}



void saveHeader( FILE *file, unsigned int sampleRate ) {


// ---- name for header "fmt "

fprintf( file, "fmt " );


// ---- header length

fputc( 0x10, file ); // length 16 byte

fputc( 0x00, file );

fputc( 0x00, file );

fputc( 0x00, file );


// ---- method for encode, 16 bit PCM

fputc( 0x01 & 0xff, file );

fputc( (0x00 >> 8) & 0xff, file );


// ---- number channels (stereo)

fputc( 0x02, file );

fputc( 0x00, file );


// ---- sample rate (Hz)

fputc( sampleRate & 0xff, file );

fputc( (sampleRate >> 8) & 0xff, file );

fputc( (sampleRate >> 16) & 0xff, file );

fputc( (sampleRate >> 24) & 0xff, file );


// ---- number bytes/second

unsigned int numberBytesSecond = sampleRate << 2; // multiply 4 because short (2 byte) * 2 channel


fputc( numberBytesSecond & 0xff, file );

fputc( (numberBytesSecond >> 8) & 0xff, file );

fputc( (numberBytesSecond >> 16) & 0xff, file );

fputc( (numberBytesSecond >> 24) & 0xff, file );


// ---- byte cho một khung (nên = số lượng mẫu vật * số lượng kênh)

// ---- number bytes for sample

unsigned short bytesOneFrame = 4; // short (2 byte) * 2 channel

u

I find from Wikipedia: Mark Lentczner created the code for the arpeggiated chord used on the Macintosh II

I ask Mark, he tell me:

"No, I don't. The code belonged to Apple when I left, and I couldn't take a copy with me"


Can people at Apple can help find this code?

As you were told - that code belongs to Apple. I doubt they're willing to let it go, because then someone else could profit from their hi$tory.

You would probably have better luck finding an image of the ROM from that model which someone has created to use with an emulator, and going through it to find and extract the relevant code.

Good idea! MC68k dissasembly!

Mark worked on the Sound Manager in the OS, he did not write the startup sound.

That was created by Jim Reakes.

Macintosh II rom (check sum 0x9779 d2c4, version 0x78):

code start beep at 0x5e4a and end at 0x5f76.

wave table at 0x5f78 to 0x6004.


Some person known if this correct?

Jim Reekes record sound for replace Macintosh II start beep. He no like it:


"It’s disconcerting, provoking a feeling of agitation and anxiety. So irritating was this combination of notes that tritones were thought in Gregorian times to invoke evil incarnate. Tritones were all but banned in early religious [Europa] music. And yet, there was a loud tritone, kicking off your experience with an early Macintosh. It wasn’t the experience a customer wanted. It wasn’t what Apple wanted to give them either"

I discover two Macintosh II start beep code versions exist:


Version 1:

ROM: Mac II, Mac IIx, Mac IIcx

Location: 0x5E4A

Length: 442 byte


Version 2:

ROM: Mac IIcii, IIfx, Classic II, IIsi, IIvx, IIvi, LC, LC II, LC III, Color Classic, PowerBook 150, Color Classic II, PowerBook 140, BowerBook 170, PowerBook 160, PowerBook 165c, PowerBook 180, PowerBook 210, PowerBook 230, Powerbook 250, PowerBook 280, PowerBook 280c, PowerBook 520, PowerBook 520c, PowerBook 540, PowerBook 540c, Quadra 605, Quadra 630, Quadra 700, Quadra 900, Quadra 950, Performa 580, Performa 588

Location: 0x7040

Length: 420 byte


Version 2 is shorter. Strange many Macintosh have version but not use it!


Location in ROM, not memory address space.

Dissassembly for Mac IIci start beep. Compare with Mac II version.


Models: Mac IIcii, IIfx, IIsi, IIvx, IIvi, LC, LC II, LC III, Classic II, Color Classic, Color Classic II, PowerBook 140, PowerBook 150, BowerBook 170, PowerBook 160, PowerBook 165c, PowerBook 180, PowerBook 210, PowerBook 230, Powerbook 250, PowerBook 280, PowerBook 280c, PowerBook 520, PowerBook 520c, PowerBook 540, PowerBook 540c, Quadra 605, Quadra 630, Quadra 700, Quadra 900, Quadra 950, Performa 580, Performa 588



Location: 0x7040

Length: 420 byte



Apple Sound Chip (ASC) output: 8 bit signed audio?





; Boot Beep

.data:00000000 24 4e moveal %fp,%a2 ; Save return address

.data:00000002 49 fa 01 14 lea %pc@(0x00000118),%a4 ; Address for boot beep data

.data:00000006 4d fa 00 06 lea %pc@(0x0000000e),%fp ; Save address for return after JMP

.data:0000000a 4e fa 00 22 jmp %pc@(0x0000002e) ; Set up ASC and play beep

.data:0000000e 2c 4a moveal %a2,%fp ; Load return address

.data:00000010 4e 75 rts ; Return



; Boot Beep

.data:00000012 49 fa 01 04 lea %pc@(0x00000118),%a4 ; Address for boot beep data

.data:00000016 60 16 bras 0x0000002e ; Set up ASC and play beep



; Error Beep 0

.data:00000018 49 fa 01 1e lea %pc@(0x00000138),%a4 ; Address for error beep 0 data

.data:0000001c 60 10 bras 0x0000002e ; Set up ASC and play beep



; Error Beep 1

.data:0000001e 49 fa 01 38 lea %pc@(0x00000158),%a4 ; Address for error beep 1 data

.data:00000022 60 0a bras 0x0000002e ; Set up ASC and play beep



; Error Beep 2

.data:00000024 49 fa 01 46 lea %pc@(0x0000016c),%a4 ; Address for error beep 2 data

.data:00000028 60 04 bras 0x0000002e ; Set up ASC and play beep



; Error Beep 3

.data:0000002a 49 fa 01 58 lea %pc@(0x00000184),%a4 ; Address for error beep 3 data



; Set up ASC

.data:0000002e 42 2b 08 01 clrb %a3@($801) ; ASC clear mode

.data:00000032 42 2b 08 07 clrb %a3@($807) ; ASC set sample speed = 22257 Hz

.data:00000036 30 1c movew %a4@+,%d0 ; Read volume data

.data:00000038 e5 48 lslw #2,%d0 ; Volume x 4

.data:0000003a 4a 2b 08 00 tstb %a3@($800) ; ASC check version

.data:0000003e 66 02 bnes 0x00000042 ; Branch 0x0042 if not ASC version 0

.data:00000040 ea 48 lsrw #5,%d0 ; Volume / 32



.data:00000042 17 40 08 06 moveb %d0,%a3@($806) ; ASC set volume

.data:00000046 70 01 moveq #1,%d0 ; Control = 1, stereo?

.data:00000048 4a 2b 08 00 tstb %a3@($800) ; ASC check version

.data:0000004c 66 02 bnes 0x00000050 ; Branch 0x0050 if not ASC version 0

.data:0000004e 70 00 moveq #0,%d0 ; Control = 0, mono?

.data:00000050 17 40 08 02 moveb %d0,%a3@($802) ; ASC set analog/PWM



; Clear ASC register

.data:00000054 41 eb 08 10 lea %a3@($810),%a0 ; Address for ASC registers

.data:00000058 70 1f moveq #31,%d0 ; Number byte for ASC wave table registers (8 byte x 4 tables) - 1

.data:0000005a 42 18 clrb %a0@+ ; Clear byte at (A0)

.data:0000005c 51 c8 ff fc dbf %d0,0x0000005a ; Finish when D0 = -1, loop 32 times

.data:00000060 70 fe moveq #$fe,%d0 ; D0 = 0xfe, store value 0xfe after registers

.data:00000062 10 c0 moveb %d0,%a0@+ ; %a3@($830) = 0xfe

.data:00000064 10 c0 moveb %d0,%a0@+ ; %a3@($831) = 0xfe

.data:00000066 10 c0 moveb %d0,%a0@+ ; %a3@($832) = 0xfe

.data:00000068 10 c0 moveb %d0,%a0@+ ; %a3@($833) = 0xfe

.data:0000006a 10 c0 moveb %d0,%a0@+ ; %a3@($834) = 0xfe

.data:0000006c 10 c0 moveb %d0,%a0@+ ; %a3@($835) = 0xfe

.data:0000006e 10 c0 moveb %d0,%a0@+ ; %a3@($836) = 0xfe

.data:00000070 10 c0 moveb %d0,%a0@+ ; %a3@($837) = 0xfe

.data:00000072 17 7c 00 02 08 01 moveb #2,%a3@($801) ; ASC set wave table mode

.data:00000078 42 2b 08 03 clrb %a3@($803) ; ASC set FIFO mode

.data:0000007c 20 3c c0 01 ff 40 movel #$c001ff40,%d0 ; Value for place in wave tables

.data:00000082 4a 2b 08 00 tstb %a3@($800) ; ASC check version

.data:00000086 66 06 bnes 0x0000008e ; Branch 0x004a if not ASC version 0

.data:00000088 20 3c 30 01 3f 10 movel #30013f10,%d0 ; Value for place in wave tables



; Build wave table (4 tables)

.data:0000008e 20 4b moveal %a3,%a0 ; Address for wave table 0

.data:00000090 72 1f moveq #31,%d1 ; Count variable for rotate number in D0, 32 times

.data:00000092 74 3f moveq #63,%d2 ; Count variable for store (copy) byte from D0, 64 times

.data:00000094 10 c0 moveb %d0,%a0@+ ; Store byte in wave table 0

.data:00000096 51 ca ff fc dbf %d2,0x00000094 ; Finish copy 64 times yet?, D2 = -1?

.data:0000009a e0 98 rorl #8,%d0 ; Rotate right 8 bit for next byte

.data:0000009c 51 c9 ff f4 dbf %d1,0x00000092 ; Finish store 32 times yet?, D1 = -1?



; Play notes

.data:000000a0 4c dc 00 07 moveml %a4@+,%d0-%d2 ; D0 = Step length, D1 = Time between notes, D2 = Play time

.data:000000a4 36 1c movew %a4@+,%d3 ; Number notes

.data:000000a6 7a 00 moveq #0,%d5 ; Count variable for wait time between notes

.data:000000a8 4b ed 1c 00 lea %a5@($1c00),%a5 ; VIA1 address + 7168

.data:000000ac 43 eb 08 14 lea %a3@($814),%a1 ; ASC address for wave table 0 increment

.data:000000b0 20 4b moveal %a3,%a0 ; Address for wave table 0

.data:000000b2 47 eb 02 00 lea %a3@($200),%a3 ; Address for wave table 1, end for wave table 0

.data:000000b6 60 24 bras 0x000000dc ; Go get note data

.data:000000b8 18 18 moveb %a0@+,%d4 ; Copy byte from wave table, put in D4

.data:000000ba b7 c8 cmpal %a0,%a3 ; Finish wave table whole yet?

.data:000000bc 62 04 bhis 0x000000c2 ; No finish yet, go update wave table

.data:000000be 41 e8 fe 00 lea %a0@(-512),%a0 ; Reset back to start wave table



; Update wave table (4 tables)

.data:000000c2 d8 10 addb %a0@,%d4 ; Add byte from wave table, with previous byte in D4

.data:000000c4 e2 14 roxrb #1,%d4 ; Rotate right 1 bit

.data:000000c6 11 44 06 00 moveb %d4,%a0@($600) ; Put result from D4 in wave table 3

.data:000000ca 11 44 04 00 moveb %d4,%a0@($400) ; Put result from D4 in wave table 2

.data:000000ce 11 44 02 00 moveb %d4,%a0@($200) ; Put result from D4 in wave table 1

.data:000000d2 10 84 moveb %d4,%a0@ ; Put result from D4 in wave table 0

.data:000000d4 38 00 movew %d0,%d4 ; Copy step length, put in D4

.data:000000d6 4a 15 tstb %a5@ ; VIA1 = 0 yet???

.data:000000d8 51 cc ff fc dbf %d4,0x000000d6 ; Step length finish yet?

.data:000000dc 51 cd 00 14 dbf %d5,0x000000f2 ; Go Clear ASC register (check if finish play sound)



; Get note data and send to ASC

.data:000000e0 4a 43 tstw %d3 ; Read all note yet?

.data:000000e2 67 0e beqs 0x000000f2 ; If finish all note (D3 = 0), go clear ASC register

.data:000000e4 3a 01 movew %d1,%d5 ; Load wait time between note

.data:000000e6 12 dc moveb %a4@+,%a1@+ ; Get next note frequency byte 0, put in wave table increment register

.data:000000e8 12 dc moveb %a4@+,%a1@+ ; Get next note frequency byte 1, put in wave table increment register

.data:000000ea 12 dc moveb %a4@+,%a1@+ ; Get next note frequency byte 2, put in wave table increment register

.data:000000ec 12 dc moveb %a4@+,%a1@+ ; Get next note frequency byte 3, put in wave table increment register

.data:000000ee 58 49 addqw #4,%a1 ; Skip wave table phase register

.data:000000f0 53 43 subqw #1,%d3 ; Decrease number note remain



; Clear ASC register for wave tables

.data:000000f2 51 ca ff c4 dbf %d2,0x000000b8 ; Finish play sound yet?, D2 = -1?

.data:000000f6 47 eb fe 00 lea %a3@($fe00),%a3 : Set address back for wave table 0 (0xfe00 = -512)

.data:000000fa 4b ed e4 00 lea %a5@($e400),%a5 ; Reset VIA1 (0xe400 = -7168)

.data:000000fe 41 eb 08 14 lea %a3@($814),%a0 ; Address for increment wave table 0

.data:00000102 74 03 moveq #3,%d2 ; Count variable for 4 wave tables

.data:00000104 42 18 clrb %a0@+ ; ASC clear wave table increment byte 0

.data:00000106 42 18 clrb %a0@+ ; ASC clear wave table increment byte 1

.data:00000108 42 18 clrb %a0@+ ; ASC clear wave table increment byte 2

.data:0000010a 42 18 clrb %a0@+ ; ASC clear wave table increment byte 3

.data:0000010c 58 48 addqw #4,%a0 ; ASC skip phase

.data:0000010e 51 ca ff f4 dbf %d2,0x00000104 ; Finish clear 4 times yet?, D2 = -1?

.data:00000112 42 2b 08 01 clrb %a3@($801) ; ASC clear mode

.data:00000116 4e d6 jmp %fp@ ; Return to beep



; Boot Beep Data

.data:00000118 02 04 ; Volume -> 516

.data:0000011a 00 00 00 0d ; Step length -> 13

.data:0000011c 00 00 01 2c ; Time between notes -> (300/32768)*22257 = 9,155e-3 s

.data:00000120 00 00 75 30 ; Play time -> (30000/32768)*22257 = 0,916 s

.data:00000126 00 04 ; 4 note

.data:00000128 00 01 80 00 ; 0001 1|000 0000 0000 0000 -> 3*22257/512 = 130,412 Hz

.data:0000012c 00 02 00 00 ; 0010 0|000 0000 0000 0000 -> 4*22257/512 = 173,883 Hz

.data:00000130 00 01 81 79 ; 0001 1|000 0001 0111 1001 -> (3 + 377/32768)*22257/512 = 130,912 Hz

.data:00000134 00 03 00 00 ; 0011 0|000 0000 0000 0000 -> 6*22257/512 = 260,824 Hz


; Error Beep 0 Data

.data:00000138 06 07 ; Volume -> 1536

.data:0000013a 00 00 00 27 ; Step length -> 39

.data:0000013e 00 00 00 00 ; Time between notes -> (288/32768)*22257 = 0,000 s

.data:00000142 00 00 13 88 ; Play time -> (5000/32768)*22257 = 0,152 s

.data:00000146 00 04 ; 4 note

.data:00000148 00 00 c0 9c ; 0000 1|100 0000 1001 1100 -> (1 + 16528/32768)*22257/512 = 65,397 Hz

.data:0000014c 00 00 e0 b6 ; 0000 1|110 0000 1011 0110 -> (1 + 24752/32768)*22257/512 = 76,307 Hz

.data:00000150 00 01 20 ea ; 0001 0|010 0000 1110 1010 -> (2 + 8416/32768)*22257/512 = 98,106 Hz

.data:00000154 00 01 82 b1 ; 0001 1|000 0010 1011 0001 -> (3 + 688/32768)*22257/512 = 131,325 Hz



; Error Beep 1 Data

.data:00000158 05 06 ; Volume -> 1286

.data:0000015a 00 00 00 27 ; Step length -> 39

.data:0000015e 00 00 0b b8 ; Time between notes -> (3000/32768)*22257 = 0,0916 s

.data:00000162 00 00 4e 20 ; Play time -> (20000/32768)*22257 = 0,610 s

.data:00000166 00 01 ; 1 note

.data:0000016a 00 03 02 72 ; 0011 0|000 0010 1101 0010 -> (6 + 624/32768)*22257/512 = 261,652 Hz



; Error Beep 2 Data

.data:0000016c 05 06 ; Volume -> 1286

.data:0000016e 00 00 00 27 ; Step length -> 39

.data:00000172 00 00 0b b8 ; Time between notes -> (3000/32768)*22257 = 0,0916 s

.data:00000176 00 00 4e 20 ; Play time -> (20000/32768)*22257 = 0,610 s

.data:0000017a 00 02 ; 2 note

.data:0000017c 00 03 02 72 ; 0011 0|000 0010 1101 0010 -> (6 + 624/32768)*22257/512 = 261,652 Hz

.data:00000180 00 04 85 24 ; 0100 1|000 0101 0010 0100 -> (7 + 1312/32768)*22257/512 = 306,035 Hz



; Error Beep 3 Data

.data:00000184 06 07 ; Volume -> 1543

.data:00000186 00 00 00 2b ; Step length -> 43

.data:0000018a 00 00 0b b8 ; Time between notes -> (3000/32768)*22257 = 0,0916 s

.data:0000018e 00 00 61 a8 ; Play time -> (25000/32768)*22257 = 0,763 s

.data:00000192 00 04 ; 4 note

.data:00000194 00 01 43 ef ; 0001 0|100 0011 1110 1111 -> (2 + 17376/32768)*22257/512 = 109,993 Hz

.data:00000198 00 01 94 eb ; 0001 1|001 0100 1110 1011 -> (3 + 5344/32768)*22257/512 = 137,502 Hz

.data:0000019c 00 01 e5 e7 ; 0001 1|110 0101 1110 0111 -> (3 + 26080/32768)*22257/512 = 165,010 Hz

.data:000001a0 00 02 89 57 ; 0010 1|000 1001 0101 0111 -> (5 + 2384/32768)*22257/512 = 220,516 Hz

Whatever the case, there is no reason to obtain that sound since it is owned and copyrighted by Apple.

You cannot use it for any reason so obtaining it, is pointless.

Accepted Answer

/* C code for Macinitosh II start beep */

/* Mac_II.c */

/* Boot Beep Mac II */

/* 级三包 */

/* 2558/09/06 */



#include <stdio.h>



#define kNUMBER_SAMPLES 30000

#define kDELAY_NOTE 300

#define kWAVE_TABLE_VALUE 0x30013f10

#define kSAMPLE_RATE 22257 // Hz



void prepareWaveTable( unsigned short *waveTable, unsigned int value );

void upDateWaveTable( unsigned short *waveTable, unsigned short chiSo );

void saveSound( char *fileName, short *soundData, unsigned int numberFrames, unsigned int sampleRate );



int main () {


// ---- wave table

unsigned short waveTable[256];

// ---- sound data, stereo

short soundData[kNUMBER_SAMPLES << 1];

// ---- increment array (16/16 bit fix point integer)

int arrayIncrement[] = {3 << 16, 4 << 16, (3 << 16) + 0x2f2, 6 << 16};


// ---- prepare wave table

prepareWaveTable( waveTable, kWAVE_TABLE_VALUE );



// ---- array phase (16/16 bit fix point integer)

unsigned int arrayPhase[] = {0, 0, 0, 0}; // set all = 0



unsigned int sampleNumber = 0;

while( sampleNumber < kNUMBER_SAMPLES ) {



// ---- calculate sample

unsigned int channelLeft = 0;

unsigned int channelRight = 0;

unsigned char noteNumber = 0;

while ( noteNumber < 4 ) {

// ---- see if should update phase for note, only do if play note

if( sampleNumber >= noteNumber*kDELAY_NOTE ) {

// ---- up date phase before

arrayPhase[noteNumber] += arrayIncrement[noteNumber];

// ---- not let out of range [0; 255]

if( arrayPhase[noteNumber] > 0xff0000 ) // 0xff0000 == 255 << 16

arrayPhase[noteNumber] -= 0xff0000; // return to begin of wave table

}

unsigned short mauVat = waveTable[arrayPhase[noteNumber] >> 16];



// ---- add sound components

if( noteNumber < 2 ) // ---- first 2 notes left channel

channelLeft += mauVat;

else // ---- last 2 notes right channel

channelRight += mauVat;

// ---- next note

noteNumber++;

}

// ---- save left and right samples

soundData[sampleNumber << 1] = (channelLeft << 9) - 0x8000; // use << 1 for 16 bit

soundData[(sampleNumber << 1) + 1] = (channelRight << 9) - 0x8000; // use << 1 for 16 bit

upDateWaveTable( waveTable, sampleNumber & 0xff );

sampleNumber++;

}


// ---- save WAV file

saveSound( "Mac II.wav", soundData, sampleNumber << 1, kSAMPLE_RATE ); // multiply 2 because stereo



return 1;

}



void prepareWaveTable( unsigned short *waveTable, unsigned int value ) {



// ---- prepare wave table

unsigned short index = 0;

unsigned short waveTableValue = value & 0xff;

while( index < 64 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}



waveTableValue = (value >> 8) & 0xff;

while( index < 128 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}



waveTableValue = (value >> 16) & 0xff;

while( index < 192 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}


waveTableValue = (value >> 24) & 0xff;

while( index < 256 ) {

waveTable[index] = waveTableValue; // << 8; // for 16 bit

index++;

}

}



void upDateWaveTable( unsigned short *waveTable, unsigned short index ) {


// ---- get value from wave table

unsigned short value = waveTable[index];


// ---- calculate new value for wave table

if( index == 255 ) { // careful at last element of wave table

value += waveTable[0];

value = (value >> 1);

waveTable[0] = value;

}

else {

value += waveTable[index+1];

value = (value >> 1);

waveTable[index+1] = value;

}



}



#pragma mark ---- SAVE WAV

void saveHeader( FILE *fileName, unsigned int sampleRate );

void saveSoundDataInteger16bit( FILE *fileName, short *soundData, unsigned int numberSamples );



void saveSound( char *fileName, short *soundData, unsigned int numberFrames, unsigned int sampleRate ) {


// ---- open file

FILE *file = fopen( fileName, "wb" );


if( file ) {

// ---- "RIFF"

fprintf( file, "RIFF" );

// ---- length sound file - 8

unsigned int lengthSoundFile = 32;

lengthSoundFile += numberFrames << 1; // một không có một mẫu vạt cho kênh trái và phải

// ---- save file length

fputc( (lengthSoundFile) & 0xff, file );

fputc( (lengthSoundFile >> 8) & 0xff, file );

fputc( (lengthSoundFile >> 16) & 0xff, file );

fputc( (lengthSoundFile >> 24) & 0xff, file );

// ---- "WAVE"

fprintf( file, "WAVE" );

// ---- save header

saveHeader( file, sampleRate );

// ---- save sound data

saveSoundDataInteger16bit( file, soundData, numberFrames );

// ---- close file

fclose( file );

}

else {

printf( "Problem save file %s\n", fileName );

}

}



void saveHeader( FILE *file, unsigned int sampleRate ) {


// ---- name for header "fmt "

fprintf( file, "fmt " );


// ---- header length

fputc( 0x10, file ); // length 16 byte

fputc( 0x00, file );

fputc( 0x00, file );

fputc( 0x00, file );


// ---- method for encode, 16 bit PCM

fputc( 0x01 & 0xff, file );

fputc( (0x00 >> 8) & 0xff, file );


// ---- number channels (stereo)

fputc( 0x02, file );

fputc( 0x00, file );


// ---- sample rate (Hz)

fputc( sampleRate & 0xff, file );

fputc( (sampleRate >> 8) & 0xff, file );

fputc( (sampleRate >> 16) & 0xff, file );

fputc( (sampleRate >> 24) & 0xff, file );


// ---- number bytes/second

unsigned int numberBytesSecond = sampleRate << 2; // multiply 4 because short (2 byte) * 2 channel


fputc( numberBytesSecond & 0xff, file );

fputc( (numberBytesSecond >> 8) & 0xff, file );

fputc( (numberBytesSecond >> 16) & 0xff, file );

fputc( (numberBytesSecond >> 24) & 0xff, file );


// ---- byte cho một khung (nên = số lượng mẫu vật * số lượng kênh)

// ---- number bytes for sample

unsigned short bytesOneFrame = 4; // short (2 byte) * 2 channel

u

Source code for Macintosh II start beep
 
 
Q