PDA

View Full Version : چطور جریان داده برای پخش صدا ارسال کنم؟



ali zi zeperto
جمعه 23 بهمن 1388, 20:28 عصر
سلام
چه عنوان تاپیکی زدم:لبخند:
من دارم روی یه وروژه کار می کنم که باید یه فایل wav رو از طریق برنامه ام پخش کنم.اولین باریه که با چنین موردی برخورد دارم و تقریبا هیچی در این مورد نمی دونم.بدون شک کوچکترین راهنمایی دوستان مفید خواهد بود.اگر تجربه اینچنین هم دارند که چه بهتر.لازمه که اضافه کنم که اینکار رو jترجیحا توی لینوکس می خوام انجام بدم. اگر در مورد ویندوز هم نظری بود ممنون.

amin1softco
جمعه 23 بهمن 1388, 21:20 عصر
کتابخانه هایی وجود دارند که فایل های wave را پخش می کنند و کلا پخش فایل های صوتی کار زیاد سختی نیست در لینوکس هم باید چنین کتابخانه (منظور همون api ها و فایل های dll) باشه اما اگر بخواهید مستقل عمل کنید که خودتون یک فایل صوتی رو پخش کنید این لینک ها خیلی بدرد می خوره یعنی با توربو سی می تونید ویو پخش کنید:

http://www.shdon.com/dos/sound

https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

http://en.wikipedia.org/wiki/WAV


نکته اول کامپایل کنید بعد خارج از محیط توربو سی اجراش کنید کار میده


اینم کد پخشش هست:



/************************************************** **************************
** WARNING: You need at least a COMPACT memory model to run this. **
************************************************** ***************************
** Demonstration of playing a single wave file using DMA **
** 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"

struct WaveData {
unsigned int SoundLength;
unsigned char *Sample;
};

char Key;
unsigned int CBuffer; //Clear Buffer indicator
unsigned char *DMABuffer; //Pointer to DMA Buffer
struct WaveData VoiceData[4]; //Pointers to Wave files
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

/************************************************** **************************
** 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);
}

/************************************************** **************************
** Starts playback of the buffer. The DMA controller is programmed with **
** a block length of 32K - the entire buffer. The DSP is instructed to **
** play blocks of 8K and then generate an interrupt (which allows the **
** program to clear the parts that have already been played) **
************************************************** **************************/
void StartPlayBack ()
{
long LinearAddress;
unsigned int Page, OffSet;

WriteDSP (0xD1); //DSP-command D1h - Enable speaker, required
//on older SB's
WriteDSP (0x40); //DSP-command 40h - Set sample frequency
WriteDSP (165); //Write time constant

//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, 0x58 | DMA); //Set mode
/*
The mode consists of the following:
0x58 + x = binary 01 00 10 xx
| | | |
| | | +- DMA channel
| | +---- Read operation (the DSP reads from memory)
| +------- Single cycle 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 0x1FFF = 8 Kbyte
WriteDSP (0x1F);
WriteDSP (0x1C); //DSP-command 1Ch - Start auto-init playback
}

/************************************************** **************************
** Clears an 8K part of the DMA buffer **
************************************************** **************************/
void ClearBuffer(unsigned int Buffer)
{
char *Address;
//Fill an 8K block in the DMA buffer with 128's - silence
Address = (char *)MK_FP (FP_SEG (DMABuffer), FP_OFF (DMABuffer) + (Buffer << 13));
memset (Address, 128, 8192);
}

/************************************************** **************************
** Mixes a sample with the contents of the DMA buffer **
************************************************** **************************/
void MixVoice (struct WaveData *Voice)
{
unsigned int Counter, OffSet, DMAPointer;

//Read DMA pointer from DMA controller
DMAPointer = inportb (1 + (DMA << 1));
DMAPointer = DMAPointer + (inportb (1 + (DMA << 1)) << 8);

/*
DMAPointer contains amount that remains to be played.
This is convert to the offset of the current sample
*/

DMAPointer = 0x7FFF - DMAPointer;

OffSet = DMAPointer;

for (Counter = 0; Counter <= Voice->SoundLength; Counter++) {
//Mix byte
DMABuffer [OffSet++] += Voice->Sample [Counter];
OffSet &= 0x7FFF; //Move on to next byte and keep it in the 32K range
}
}

/************************************************** **************************
** Loads a wave file into memory. This procedure treats any file as a **
** standard 11025Hz, 8bit, mono .WAV file. It doesn't perform any error **
** checking. **
************************************************** **************************/
void LoadVoice (struct WaveData *Voice, char *FileName)
{
FILE *WAVFile;

//If it can't be opened...
WAVFile = fopen(FileName, "rb");
if (WAVFile == NULL) {
//..display error message
printf ("Unable to open wave file\n");
return;
}

//Return length of file for sound length minus 48 bytes for .WAV header
fseek(WAVFile, 0L, SEEK_END);
Voice->SoundLength = ftell (WAVFile) - 48;
fseek(WAVFile, 0L, SEEK_SET);

Voice->Sample = (char *)malloc(Voice->SoundLength + 2); //Assign memory
fseek(WAVFile, 46L, SEEK_SET); //Skip the header

//Load the sample data
fread(Voice->Sample, Voice->SoundLength + 2, 1, WAVFile);

fclose(WAVFile); //Close the file
}

/************************************************** **************************
** Converts a wave file so it can be mixed easily **
************************************************** **************************/
void ConvertVoice (struct WaveData *Voice)
{
unsigned int OffSet;

//for each sample, decrease sample value to avoid overflow

for (OffSet = 0; OffSet <= Voice->SoundLength; OffSet++) {
Voice->Sample [OffSet] >>= 2;
Voice->Sample [OffSet] -= 32;
}
}

/************************************************** **************************
** 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 (Base + 0xE);
//Acknowledge hardware interrupt
outportb (0x20, 0x20);
//Acknowledge cascade interrupt for IRQ 2, 10 and 11
if (IRQ == 2 || IRQ == 10 || IRQ == 11) outportb (0xA0, 0x20);
//Increase pointer to clear buffer and keep it in the range 0..3
CBuffer++;
CBuffer &= 3;
//Clear buffer
ClearBuffer (CBuffer);
}

/************************************************** **************************
** 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 main ()
{
int Temp;
//Clear screen
clrscr ();

printf ("Demonstration of mixing samples using DMA - by Steven Don\n");
printf ("---------------------------------------------------------\n");

//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);

printf ("Please specify DMA channel : "); scanf("%d", &DMA);
printf ("Please specify IRQ level : "); scanf("%d", &IRQ);

//Assign memory to the DMA Buffer
AssignBuffer ();

//Load wave files and convert
LoadVoice (&VoiceData[0], "1.wav"); ConvertVoice (&VoiceData[0]);
LoadVoice (&VoiceData[1], "2.wav"); ConvertVoice (&VoiceData[1]);
LoadVoice (&VoiceData[2], "3.wav"); ConvertVoice (&VoiceData[2]);
LoadVoice (&VoiceData[3], "4.wav"); ConvertVoice (&VoiceData[3]);

//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));

//Set clear buffer to last buffer
CBuffer = 3;

//Start playback
StartPlayBack ();

//Display message
printf ("\nPress 1..4 to hear the different sounds.\nESC to quit...");

do
{
if (kbhit()) Key = getch();
else Key = 0;

if (Key == '1') MixVoice (&VoiceData[0]);
if (Key == '2') MixVoice (&VoiceData[1]);
if (Key == '3') MixVoice (&VoiceData[2]);
if (Key == '4') MixVoice (&VoiceData[3]);
}
while (Key != 27); //escape is pressed

//Stops DMA-transfer
WriteDSP (0xD0);
WriteDSP (0xDA);

//Free the memory allocated to the sound buffer
free (DMABuffer);

//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));

return;
}