
نوشته شده توسط
bidemajnoon
سوال:
چه جوری می شه به میکروفن وصل شد و ازش اطلاعات صوتی گرفت؟
گرچه یکمی دیره اما این سورس رو ببین :
/************************************************** **************************
** WARNING: You need at least a COMPACT memory model to run this. **
************************************************** ***************************
** Demonstration of recording a WAV file through the Sound Blaster **
** by Steven H Don **
** **
** For questions, feel free to e-mail me. **
** **
** shd@earthling.net **
** http://shd.cjb.net **
** **
************************************************** **************************/
//Include files
#include "ALLOC.H"
#include "DOS.H"
#include "MEM.H"
#include "CONIO.H"
#include "STDIO.H"
#define CD 2
#define Microphone 4
#define LineIn 5
//The simplest header a WAV file can have is this:
struct SimpleHeader {
long RIFF;
long NextChunkSize;
long WAVE;
long fmt;
long fmtDataLength;
short WaveType;
short Channels;
long SampleRate;
long BytesPerSecond;
short BlockAlignment;
short BitResolution;
long data;
long SoundLength;
} Header;
char Key;
unsigned int WBuffer; //Write Buffer indicator
unsigned char *DMABuffer; //Pointer to DMA Buffer
unsigned int DMA; //The DMA channel
unsigned int IRQ; //The IRQ level
unsigned int Base; //Sound Blaster base address, Word
//Pointers to old interrupt routines
#ifdef __cplusplus
void interrupt (*OldIRQ)(...);
#else
void interrupt (*OldIRQ)();
#endif
FILE *WAVFile; //Handle of the WAV file}
long Recorded; //Amount of samples recorded}
/************************************************** **************************
** Checks to see if a Sound Blaster exists at a given address, returns **
** true if Sound Blaster found, false if not. **
************************************************** **************************/
int ResetDSP(unsigned int Test)
{
//Reset the DSP
outportb (Test + 0x6, 1);
delay(10);
outportb (Test + 0x6, 0);
delay(10);
//Check if (reset was succesfull
if (((inportb(Test + 0xE) & 0x80) == 0x80) && (inportb(Test + 0xA) == 0xAA))
{
//DSP was found
Base = Test;
return (1);
}
else
//No DSP was found
return (0);
}
/************************************************** **************************
** Send a byte to the DSP (Digital Signal Processor) on the Sound Blaster **
************************************************** **************************/
void WriteDSP(unsigned char Value)
{
//Wait for the DSP to be ready to accept data
while ((inportb(Base + 0xC) & 0x80) == 0x80);
//Send byte
outportb (Base + 0xC, Value);
}
/************************************************** **************************
** Writes a value to the SB's mixer chip **
************************************************** **************************/
void WriteMixer (unsigned char R, unsigned char V)
{
outportb (Base + 4, R);
outportb (Base + 5, V);
}
/************************************************** **************************
** Selects the source device for recording. **
** Valid values are: Microphone, CD and LineIn **
************************************************** **************************/
void SelectSource (char Source)
{
//For older SB's
WriteMixer (0xC, Source);
//For newer SB's
{
//Disable right channel
WriteMixer (0x3E, 0);
//Record all sound through left channel
switch (Source) {
case Microphone : WriteMixer (0x3D, 1); break;
case CD : WriteMixer (0x3D, 6); break;
case LineIn : WriteMixer (0x3D, 24); break;
}
//Set volume of whatever is recording to full
switch (Source) {
case Microphone : WriteMixer (0x0A, 7); break;
case CD : WriteMixer (0x28, 255); break;
case LineIn : WriteMixer (0x2E, 255); break;
}
//Allow line and CD to be heard through speakers, but not microphone}
switch (Source) {
case Microphone : WriteMixer (0x3C, 0); break;
case CD : WriteMixer (0x3C, 6); break;
case LineIn : WriteMixer (0x3C, 24); break;
}
}
}
/************************************************** **************************
** Asks the user for a filename and prepares that file for recording. **
************************************************** **************************/
void PrepareFile ()
{
char FileName [255];
//Ask the user for a file name
printf ("Please give filename : ");
scanf ("%s", FileName);
//Open the file for output
WAVFile = fopen (FileName, "wb");
//Save a dummy header
fwrite (&Header, sizeof(Header), 1, WAVFile);
}
/************************************************** **************************
** Starts recording. The DMA controller is programmed with a block length **
** of 32K - the entire buffer. The DSP is instructed to play blocks of 16K **
** and then generate an interrupt (which allows the program to save the **
** parts that have already been recorded) **
************************************************** **************************/
void StartRecording ()
{
long LinearAddress;
unsigned int Page, OffSet;
//Nothing recorded yet
Recorded = 0;
WriteDSP (0xD3); //DSP-command D1h - Disable speaker, required
//on older SB's
WriteDSP (0x40); //DSP-command 40h - Set sample frequency
WriteDSP (165); //Write time constant
/*
The time constant is calculated as follows:
(65536 - (256000000 / frequency)) >> 8
*/
//Convert pointer to linear address
LinearAddress = FP_SEG (DMABuffer);
LinearAddress = (LinearAddress << 4) + FP_OFF (DMABuffer);
Page = LinearAddress >> 16; //Calculate page
OffSet = LinearAddress & 0xFFFF; //Calculate offset in the page
outportb (0x0A, 4 | DMA); //Mask DMA channel
outportb (0x0C, 0); //Clear byte pointer
outportb (0x0B, 0x54 | DMA); //Set mode
/*
The mode consists of the following:
0x54 + x = binary 01 01 01 xx
| | | |
| | | +- DMA channel
| | +---- Write operation (the DSP writes to memory)
| +------- Auto init mode
+---------- Block mode
*/
outportb (DMA << 1, OffSet & 0xFF); //Write the offset to the DMA controller
outportb (DMA << 1, OffSet >> 8);
if (DMA == 0) outportb (0x87, Page);
if (DMA == 1) outportb (0x83, Page);
if (DMA == 3) outportb (0x82, Page);
outportb ((DMA << 1) + 1, 0xFF); //Set the block length to 0x7FFF = 32 Kbyte
outportb ((DMA << 1) + 1, 0x7F);
outportb (0x0A, DMA); //Unmask DMA channel
WriteDSP (0x48); //DSP-command 48h - Set block length
WriteDSP (0xFF); //Set the block length to 0x3FFF = 16 Kbyte
WriteDSP (0x3F);
WriteDSP (0x2C); //DSP-command 2Ch - Start auto-init playback
}
/************************************************** **************************
** Saves one half of the DMA buffer to the file **
************************************************** **************************/
void SaveBuffer (unsigned int Buffer)
{
fwrite (DMABuffer + (Buffer << 14), 16384, 1, WAVFile);
Recorded += 16384;
}
/************************************************** **************************
** Saves the final part of the buffer and finalizes the WAV file **
************************************************** **************************/
void EndRecording ()
{
unsigned int Counter, OffSet, DMAPointer;
//Stops DMA-transfer
WriteDSP (0xD0);
WriteDSP (0xDA);
//Read DMA pointer from DMA controller
DMAPointer = inportb (1 + (DMA >> 1));
DMAPointer += (inportb (1 + (DMA >> 1)) << 8);
/*
DMAPointer contains amount that remains to be played.
This is converted to the offset of the current sample
*/
OffSet = 0x7FFF - DMAPointer;
//Save the last bit
fwrite (DMABuffer + (OffSet & 16384),
OffSet & 16383,
1, WAVFile);
//The total amount recorded is now available
Recorded += OffSet & 16383;
//Save the actual header
Header.RIFF = 0x46464952; //"RIFF"
Header.NextChunkSize = Recorded + 36; //Size of the WAVE chunk
Header.WAVE = 0x45564157; //"WAVE"
Header.fmt = 0x20746D66; //"fmt "
Header.fmtDataLength = 16; //length of fmt chunk
Header.WaveType = 1; //Standard uncompressed WAV file
Header.Channels = 1; //Mono
Header.SampleRate = 11025; //11KHz
Header.BytesPerSecond = Header.Channels * Header.SampleRate;
Header.BlockAlignment = 1; //1 for 8bit, 2 for 16bit
Header.BitResolution = 8; //8bit WAV file
Header.data = 0x61746164; //"data"
Header.SoundLength = Recorded;
//Save the actual header
fseek (WAVFile, 0, SEEK_SET);
fwrite (&Header, sizeof(Header), 1, WAVFile);
fclose (WAVFile);
}
/************************************************** **************************
** IRQ service routine - this is called when the DSP has finished playing **
** a block **
************************************************** **************************/
#ifdef __cplusplus
void interrupt ServiceIRQ (...)
#else
void interrupt ServiceIRQ ()
#endif
{
//Relieve DSP
inportb (0x22E);
//Acknowledge hardware interrupt
outportb (0x20, 0x20);
//Acknowledge cascade interrupt for IRQ 2 and 10
if (IRQ == 2 || IRQ == 10) outportb (0xA0, 0x20);
//Save buffer
SaveBuffer (WBuffer);
//Toggle between write buffers
WBuffer ^= 1;
}
/************************************************** **************************
** This procedure allocates 32K of memory to the DMA buffer and makes sure **
** that no page boundary is crossed **
************************************************** **************************/
void AssignBuffer ()
{
char *TempBuf; //Temporary pointer
long LinearAddress;
unsigned int Page1, Page2; //Words
//Assign 32K of memory
TempBuf = (char *)malloc(32768);
//Calculate linear address
LinearAddress = FP_SEG (TempBuf);
LinearAddress = (LinearAddress << 4) + FP_OFF (TempBuf);
//Calculate page at start of buffer
Page1 = LinearAddress >> 16;
//Calculate page at end of buffer}
Page2 = (LinearAddress + 32767) >> 16;
//Check to see if a page boundary is crossed
if (Page1 != Page2) {
//If so, assign another part of memory to the buffer
DMABuffer = (char *)malloc(32768);
free (TempBuf);
} else //otherwise, use the part we've already allocated
DMABuffer = TempBuf;
memset (DMABuffer, 128, 0x7FFF);
}
void FindSB ()
{
int Temp;
//Check for Sound Blaster, address: ports 220, 230, 240, 250, 260 or 280
for (Temp = 1; Temp < 9; Temp++) {
if (Temp != 7)
if (ResetDSP (0x200 + (Temp << 4))) {
break;
}
}
if (Temp == 9) {
//or none at all
printf ("No Sound Blaster found\n");
return;
} else printf ("Sound Blaster found at %Xh\n", Base);
}
void InitIRQandDMA ()
{
printf ("Please specify DMA channel : "); scanf("%d", &DMA);
printf ("Please specify IRQ level : "); scanf("%d", &IRQ);
//Save old IRQ vector
if (IRQ == 2 || IRQ == 10 || IRQ == 11) {
if (IRQ == 2) OldIRQ = getvect (0x71);
if (IRQ == 10) OldIRQ = getvect (0x72);
if (IRQ == 11) OldIRQ = getvect (0x73);
} else OldIRQ = getvect (8 + IRQ);
//Set new IRQ vector
if (IRQ == 2 || IRQ == 10 || IRQ == 11) {
if (IRQ == 2) setvect (0x71, ServiceIRQ);
if (IRQ == 10) setvect (0x72, ServiceIRQ);
if (IRQ == 11) setvect (0x73, ServiceIRQ);
} else setvect (8 + IRQ, ServiceIRQ);
//Enable IRQ
if (IRQ == 2 || IRQ == 10 || IRQ == 11) {
if (IRQ == 2) outportb (0xA1, inportb (0xA1) & 253);
if (IRQ == 10) outportb (0xA1, inportb (0xA1) & 251);
if (IRQ == 11) outportb (0xA1, inportb (0xA1) & 247);
outportb (0x21, inportb (0x21) & 251);
} else outportb (0x21, inportb (0x21) & !(1 << IRQ));
}
void ReleaseIRQandDMA ()
{
//Free interrupt vectors used to service IRQs
if (IRQ == 2 || IRQ == 10 || IRQ == 11) {
if (IRQ == 2) setvect (0x71, OldIRQ);
if (IRQ == 10) setvect (0x72, OldIRQ);
if (IRQ == 11) setvect (0x73, OldIRQ);
} else setvect (8 + IRQ, OldIRQ);
//Mask IRQs
if (IRQ == 2 || IRQ == 10 || IRQ == 11) {
if (IRQ == 2) outportb (0xA1, inportb (0xA1) | 2);
if (IRQ == 10) outportb (0xA1, inportb (0xA1) | 4);
if (IRQ == 11) outportb (0xA1, inportb (0xA1) | 8);
outportb (0x21, inportb (0x21) | 4);
} else outportb (0x21, inportb (0x21) | (1 << IRQ));
}
void main ()
{
//Clear screen
clrscr ();
printf ("Demonstration of recording samples using DMA - by Steven Don\n");
printf ("------------------------------------------------------------\n");
//Look for the Sound Blaster
FindSB ();
//Assign memory to the DMA Buffer
AssignBuffer ();
//Set write buffer to first buffer
WBuffer = 0;
//Select microphone as the source
SelectSource (Microphone);
//Ask the user for a filename and prepare the file for output
PrepareFile ();
//Ask the user for IRQ and DMA channels
InitIRQandDMA ();
//Start playback
StartRecording ();
//Wait until escape is pressed
do; while (getch () != 27);
//End the recording
EndRecording ();
//Free the memory allocated to the sound buffer
free (DMABuffer);
//Release the IRQ and DMA channels
ReleaseIRQandDMA ();
}