From: http://blog.163.com/tongfangyuan0000@126/blog/static/43041855200921272753720/
1) view the sound card:
Tong @ tfylaptop :~ /Documents/Robot dance/Program/MIT/Linux/tapping3 (new) $ arecord-l
* *** List of capture hardware devices ****
Card 0: Intel [hda intel], device 0: stac92xx analog [stac92xx analog]
Subdevices: 3/3
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Or:
View the sound card driver installation status:
Tong @ tfylaptop :~ /Documents/Robot dance/Program/MIT/Linux/tapping3 (new) $ CAT/dev/sndstat
Sound DRIVER: 3.8.1a-980706 (ALSA v1.0.16 emulation code)
Kernel: Linux tfylaptop 2.6.24-16-generic #1 SMP Thu Apr 10 13:23:42 UTC 2008 i686
Config options: 0
Installed drivers:
Type 10: ALSA emulation
Card config:
Hda intel at 0xfe9fc000 IRQ 20
Audio Devices:
0: stac92xx anplex (Duplex)
Synth devices: not enabled in config
MIDI devices: not enabled in config
Timers:
7: system timer
Mixers:
0: sigmatel stac9228
The default OSS security directory is/usr/lib/OSS.
2)recording (the duration is 10 seconds, the recording file is 0.wav, and plughw: 0 indicates the first sound card)
Tong @ tfylaptop :~ /Documents/Robot dance/Program/MIT/Linux/tapping3 (new) $ arecord-D 10-D plughw: 0 0.wav
Recording wave '0.wav ': Unsigned 8 bit, rate 8000Hz, Mono
3)
Recording in Linux:
In Linux, audio input and output are performed through the/dev/DSP device, but the processing of these audio signals is done through the/dev/mixer device.
Some variables used for operations on Mixer files
You can read the Linux/Soundcard. h file to obtain these variables. Here we will list some basic common variables.
Sound_mixer_write_volume = 0xc0044d00
Sound_mixer_write_bass = 0xc0044d01
Sound_mixer_write_pcm = 0xc0044d04
Sound_mixer_write_line = 0xc0044d06
Sound_mixer_write_mic = 0xc0044d07
Sound_mixer_write_recsrc = 0xc0044dff
Sound_mixer_line = 7
Sound_mask_line = 64
These variable names are all in Soundcard. as can be found in H, we can see its purpose through the name. The subsequent values are not defined in this header file, but returned by calling some functions, the address corresponding to the sound card. In applications, you can assign values to these variables through IOCTL (FD, CMD, ARG. FD is a file pointer for opening/dev/mixer. CMD is the variable volume listed above. Arg is the struct or variable to be assigned to these variables.
Reference: http://www.cndw.com/tech/server/2006040534091.asp
6.3 yc2440 recording and releasing hardware and software configuration
The following development and running environments are all in C (utu-Linux operating system on the yc2440 Board. The selected cross compiler is armv4l-unknown-linux-gcc.
6.3.1 recording hardware (uda1341 sound card)
Uda1341 is a sound card chip widely used in the market. It supports PCM hardware encoding, sound recording, and sound recording. Uda1341 supports the IIS bus data format. It uses bit-element Stream Conversion Technology for signal processing and provides Programmable Gain Amplifier (PGA) and digital automatic gain controller (AGC ). Uda1341 provides two sets of audio signal input interfaces, each of which includes two sound channels. Because IIS bus only processes audio data, uda1341 also has a built-in L3 bus interface for transmitting control signals. The L3 interface is equivalent to the mixer control interface, which can control the bass and volume of the input/output audio signal. In addition, these functions can be well implemented by calling the upper-layer interface functions provided by utu-Linux through a program, and more easily supporting the recording and release of specific requirements.
6.3.2 softwAre platfoRm (utu-Linux)
The utulinux Operating System is an embedded Linux operating system provided by yc2440, whose kernel is 2.6.13. In this way, programming and development can be directly based on the Linux operating system, without having to spend too much time considering the working mechanism of the underlying hardware, which greatly improves the work efficiency. One of the advantages of Linux operating systems is that programs compiled on PC Linux can basically pass the test on the on-board Linux. In addition, most of the technologies based on Linux systems are open-source projects, which can be used to learn from others' achievements. Therefore, we have selected utulinux instead of wince.
6.3.3 sound card drive
There are two types of sound card drivers on Linux: OSS and ALSA.
ALSA (short for advanced Linux sound architecture) is a Linux kernel component that provides drivers for sound cards. Some of the purposes are to support the automatic configuration of sound cards and the perfect processing system of multiple sound devices, most of which have been achieved. Another sound framework Jack uses ALSA to provide low-latency Professional-level audio editing and mixing capabilities. ALSA is a fully open-source audio driver assembly and fully compatible with OSS.
OSS (Open Sound System) is a unified audio interface on the Linux platform. That is, as long as the audio processing application is compiled according to the oss api, you only need to re-compile. It is worth noting that the OSS is only partially open-source.
Both ALSA and OSS are used to abstract the sound card into a unified device for Linux programmers. The OSS series we used in the preliminary test.
6.3.3.2 install the Sound Card Driver
The driver source program uses the uda1341.c file attached to the vendor.
A. Place the file in the sound/OSS/directory. Put bitfield. h In include/ASM-arm/plat-yc24xx/directory
B. Add:
OBJ-$ (config_yc2440_uda1341) + = yc2440_uda1341.o
So that you can choose to compile the file.
C. Add the header of the kconfig file in this directory:
Config yc2410_snd_uda1341
Tristate "yc2440 uda1341 Driver (yc2440 )"
Depends on sound_prime & Sound & arch_yc2440
Help
The uda1341 can be found in Samsung's yc24xx
Platforms. If you have a board based on one
Of these. Say y or nhere.
If unsure, say n.
In this way, you can select this sound card when using menuconfig.
D. Add the ISS platform_device to the ARCH/ARM/mach-yc2440/mach-smdk2440.c file (default already available)
Static struct platform_device * smdk2440_devices [] _ initdata = {
....
....
& Amp; cloud_device_iis,
....
....
};
E. Choose driver-> sound-> OSS-> uda1341 for make menuconfig and select sound card support. After compilation, download to the yc2440 Development Board and use madplay to play MP3 files.
6.3.3.3 test whether the sound card driver is successfully installed
In Linux, It is very convenient to test whether the sound card is normal. You can use two simple commands:
CAT/dev/DSP> test.wav recording the sound as PCM Data
Cat test.wav>/dev/DSP play PCM Data
6.4 yc2440 Development Board recording Implementation Mechanism
General process of recording implementation:
A. test whether the sound card works properly.
B. Adjust the volume and effects of sound card Input and Output Using mixer (important)
C. Open the default/dev/DSP directory for the sound card device.
D. Open the sound file.
E. Read the wav header information into the audio file.
F. Read PCM data from the DSP sound card device.
G. Close the device and save the sound file.
The pseudocode of the general process is given in two parts. One part is based on Mixer programming, which is specifically responsible for adjusting the sound card Recording effect. The second part is the recording program.
Mixer Mixing Programming
6.4.1.1 introduction to Common commands
The sound card mixer consists of multiple sound mixing channels, which can be programmed through the device file/dev/mixer provided by the driver. Operations on the mixer are performed by calling the ioctl system, and all control commands start with sound_mixer or mixer. Table 1 lists several commonly used control commands for the mixer:
Name used
Sound_mixer_volume main volume adjustment
Sound_mixer_bass Control
Sound_mixer_treble tweeter Control
Sound_mixer_synth FM Synthesizer
Sound_mixer_pcm primary D/A converter
Sound_mixer_speaker PC speaker
Sound_mixer_line audio frequency line Input
Sound_mixer_mic Input
Sound_mixer_cd Input
Sound_mixer_imix playback volume
Sound_mixer_altpcm from D/A converter
Sound_mixer_reclev audio volume
Sound_mixer_igain input gain
Sound_mixer_ogain output gain
Sound_mixer_line1 sound card 1st Input
Sound_mixer_line2 sound card 2nd Input
Sound_mixer_line3 sound card 3rd Input
6.4.1.2 recording Programming
The mixer section is relatively simple. Now the code and comments are included:
# Include <unistd. h>
# Include <stdlib. h>
# Include <stdio. h>
# Include <sys/IOCTL. h>
# Include <fcntl. h>
# Include <Linux/Soundcard. h>
/* Name of all available mixing devices */
Const char * sound_device_names [] = sound_device_names;
Int FD;/* file descriptor corresponding to the mixing device */
Int devmask, stereodevs;/* bitmap mask corresponding to mixer information */
Char * Name;
/* Display command usage and all available mixing devices */
Void usage ()
{
Int I;
Fprintf (stderr, "Usage: % S <device> <left-gain %> <right-gain %> \ n"
"% S <device> <gain %> \ n"
"Where <device> is one of: \ n", name, name );
For (I = 0; I <sound_mixer_nrdevices; I ++)
If (1 <I) & devmask)/* only display valid mixing devices */
Fprintf (stderr, "% s", sound_device_names [I]);
Fprintf (stderr, "\ n ");
Exit (1 );
}
Int main (INT argc, char * argv [])
{
Int left, right, level;/* gain setting */
Int status;/* returned values of system calls */
Int device;/* audio mixing device */
Char * dev;/* audio mixing device name */
Int I;
Name = argv [0];
/* Open the audio mixing device in read-only mode */
FD = open ("/dev/mixer", o_rdonly );
If (FD =-1 ){
Perror ("unable to open/dev/mixer ");
Exit (1 );
}
/* Obtain the required information */
Status = IOCTL (FD, sound_mixer_read_devmask, & devmask );
If (status =-1)
Perror ("sound_mixer_read_devmask IOCTL failed ");
Status = IOCTL (FD, sound_mixer_read_stereodevs, & stereodevs );
If (status =-1)
Perror ("sound_mixer_read_stereodevs IOCTL failed ");
/* Check user input */
If (argc! = 3 & argc! = 4)
Usage ();
/* Save the mixed speaker name entered by the user */
Dev = argv [1];
/* Determine the mixing device to be used */
For (I = 0; I <sound_mixer_nrdevices; I ++)
If (1 <I) & devmask )&&! Strcmp (Dev, sound_device_names [I])
Break;
If (I = sound_mixer_nrdevices) {/* No matching item found */
Fprintf (stderr, "% s is not a valid mixer device \ n", Dev );
Usage ();
}
/* Find a valid Mixing Device */
Device = I;
/* Get the increment value */
If (argc = 4 ){
/* Left and Right audio channels are specified */
Left = atoi (argv [2]);
Right = atoi (argv [3]);
} Else {
/* Set the left and right channels to equal */
Left = atoi (argv [2]);
Right = atoi (argv [2]);
}
/* Warn non-stereo devices */
If (left! = Right )&&! (1 <I) & stereodevs )){
Fprintf (stderr, "Warning: % s is not a stereo device \ n", Dev );
}
/* Merge the values of two channels into the same variable */
Level = (right <8) + left;
/* Set the gain */
Status = IOCTL (FD, mixer_write (device), & level );
If (status =-1 ){
Perror ("mixer_write IOCTL failed ");
Exit (1 );
}
/* Obtain the gain of the left and right channels returned from the driver */
Left = level & 0xff;
Right = (Level & 0xff00)> 8;
/* Display the actually set gain */
Fprintf (stderr, "% s gain set to % d %/% d % \ n", Dev, left, right );
/* Disable the sound mixing device */
Close (FD );
Return 0;
}
Use mixer to adjust sound effects when sound card inputs and outputs
After compiling the above program with the armv4l-unknown-linux-gcc, download to yc2440 development edition, first without any parameters to execute it again, it will list all the available sound channel on the Sound Card:
[Nnliubin @ localhost sound] $./Mixer
Usage:./mixer <device> <left-gain %> <right-gain %>
./Mixer <device> <gain %>
Where <device> is one:
Vol PCM speaker line mic CD igain line1 dolphin video
Then you can easily set the gain of each sound mixing channel. For example, the following command can set the gain of the left and right audio channels entered by the microphone to 80% and 90% respectively:
[Nnliubin @ localhost sound] $./mixer mic 80 90
CD Gain set to 80%/90%
6.4.2 recording storage
Because some recording programs are relatively long, some code and text will be used to describe and the recorded formats are WAV.
Before the program, let's clarify the basic things. The basic framework of the DSP device on the Sound Card for sound recording and playback. Its function is to record audio data for several seconds, store it in the memory buffer, and then play back the data, all of its functions are implemented through reading/writing/dev/DSP device files. (For details, refer to the core code)
In this way, the recording program is completed. The recording time is set to 30 seconds for 8-bit sampling at 8000Hz, and the ioctl interface of OSS is called.
Run the following command to check the effect
CD directory name
Armv4l-unknown-linux-gcc-O soundrec sound. c
Download the soundrec file to yc2440 Development Board
Run./soundrec to go to the recording page.
6.5 yc2440 implementation mechanism of sound recording on the development board 6.5.1 sound recording Programming
To better check the correctness and effect of our recording data, we decided to write a console player dedicated to playing wav files. In fact, after the recording function is implemented,
The playing function can be implemented by analogy, but the specific process is reversed as follows:
A. Read the header of the wav file and save the parameters of each part.
B sets parameters through IOCTL
C. Read PCM data into/dev/DSP
After completing the above functions, you can play any audio file in WAV format on the Development Board. The following is the reduced version code (some parts are omitted when the recording is equivalent)
Compile the program into a binary executable file using a cross compiler and download it to the yc2440 development edition to enjoy the program.
6.6 core code 1. PCM to WAV
// 8 k Hz, quantize 16 bit (or 8 bit), single channel
// Header file
# Include <iostream>
# Include <string>
# Include <iostream>
# Include <fstream>
# Include "stdio. H"
Using namespace STD; // unsigned long = DWORD, unsigned short = word
// The structure of the wav header is as follows:
// Riff chunk
Typedef struct {/* as mentioned above, skipped here */
} Header;
// FMT sub-chunk
Typedef struct {/* content omitted here */
} FMT;
// "Data" sub-chunk
Typedef struct {/* content omitted */
} Data;
Int main ()
{
// Supplement 2008.8.8 to process the ima adpcm and convert the data into binary storage status
// Open the input and output files
Ifstream fin;
Fin. Open ("adpcm16.txt", IOS: Binary );
Ofstream fout;
Fout. Open ("adpcm.txt", IOS: Binary );
Char adpcm16 [2];
Int two_adpcm_byte // put the 4-bit high and 4-bit low in one byte,
Adpcm1 and adpcm2; // stores high bytes and low bytes respectively;
Int I = 0;
// Input 10-digit data into binary storage. The conversion algorithm is as follows:
While (Fin> adpcm16 [1]> adpcm16 [2])
{
If (INT) adpcm16 [1]> 81) // It Is A, B, C, D, E, F
Adpcm1 = int (adpcm16 [1])-87;
Else
Adpcm1 = int (adpcm16 [1])-int ('0 ');
If (INT) adpcm16 [2]> 81) // It Is A, B, C, D, E, F
Adpcm2 = int (adpcm16 [2])-87;
Else
Adpcm2 = int (adpcm16 [2])-int ('0 ');
Two_adpcm_byte = adpcm1 * 16 + adpcm2;
Fout. Write (char *) (& two_adpcm_byte), 1 );
}
Fin. Close ();
Fout. Close ();*/
// Add the header program 2008.7.17
Header pcmheader;
FMT pcmfmt;
Data pcmdata;
// Unsigned short m_pcmdata;
Char m_pcmdata;
File * FP/* Open the PCM file */, * fpcpy/* Open the output file */;
// Header part;
Strcpy (pcmheader. fccid, "riff ");
Strcpy (pcmheader. fcctype, "wave ");
If (fseek (fpcpy, sizeof (header), seek_set) // skip the header length so that the following data is written into the wav file;
Exit (0 );
// Initialize the FMT member data and write it to the output file;
Strcpy (pcmfmt. fccid, "FMT ");
Fwrite (& pcmfmt, sizeof (FMT), 1, fpcpy );
// Data section;
Strcpy (pcmdata. fccid, "data ");
// Skip the Data Length, start to write the PCM Data part, and calculate the data size;
Fseek (fpcpy, sizeof (data), 1 );
// Note: each time a PCM data is read (we use 16 bits, that is, 2 bytes)
Fread (& m_pcmdata, sizeof (unsigned short), 1, FP); // read data from. PCM
// When sampling 8 bits:
// Fread (& m_pcmdata, sizeof (char), 1, FP); // read data from. PCM
Pcmdata. dwsize = 0;
// Read and store data
While (! Feof (FP ))
{
Pcmdata. dwsize + = 2; // The length of the calculated data. 2 is added for each read data;
// Reference: size_t fread (void * buffer, size_t size, size_t count, file * stream );
Fwrite (& m_pcmdata, sizeof (unsigned short), 1, fpcpy );
Fread (& m_pcmdata, sizeof (unsigned short), 1, FP );
// When the audio sample size is 8 bit
// Pcmdata. dwsize + = 1;
// Fwrite (& m_pcmdata, sizeof (char), 1, fpcpy );
// Fread (& m_pcmdata, sizeof (char), 1, FP );
}
Fclose (FP); // close the file
Pcmheader. dwsize = 36 + pcmdata. dwsize;
Rewind (fpcpy); // convert fpcpyto A. wav header to facilitate writing headers and data;
Fwrite (& pcmheader, sizeof (header), 1, fpcpy); // write Header
Fseek (fpcpy, sizeof (FMT), 1); // skip FMT because FMT has been written
Fwrite (& pcmdata, sizeof (data), 1, fpcpy); // write data;
Fclose (fpcpy); // close the file
Return 0;
2. recording on the yc2440 Development Board
# Include <unistd. h>
# Include <fcntl. h>
# Include <sys/types. h>
# Include <sys/IOCTL. h>
# Include <stdlib. h>
# Include <stdio. h>
# Include <Linux/Soundcard. h>
# Include <string. h>
# Define length 30/* recording time */
# Define rate 8000/* sampling frequency */
# Define size 8/* Number of sampling digits */
# Define Channels 1/* Number of audio channels */
/* Memory buffer used to save Digital Audio Data */
Unsigned char Buf [length * rate * size/8];
Typedef struct {/* the following code has been omitted */
// Use this structure to save the first 10 bytes in the wav Header
} Header;
// FMT part
Typedef struct {/* the following code has been omitted */
// Use this structure to save the FMT block in the wav Header
} FMT;
Typedef struct {/* the following code has been omitted */
// Use this structure to store data blocks in the wav Header
} Data;
Int main ()
{
Int FD;/* file descriptor of the sound device */
Int ARG;/* parameters used for IOCTL call */
Int status;/* returned values of system calls */
File * out;/* output audio file */
Int savesize = length * rate * size/8;/* data size */
Header pcmheader;
FMT pcmfmt;
Data pcmdata;
// Unsigned short m_pcmdata;
Char m_pcmdata;
/* Enable the sound device */
FD = open ("/dev/DSP", o_rdwr );
If (FD <0 ){
Perror ("open of/dev/DSP failed ");
Exit (1 );
}
/* Set the quantified number of digits during sampling */
Arg = size;
Status = IOCTL (FD, sound_pcm_write_bits, & Arg );
// Printf ("mic gain is at % d % \ n", vol );
If (status =-1)
Perror ("sound_pcm_write_bits IOCTL failed :");
If (Arg! = Size)
Perror ("unable to set sample size ");
/* Set the number of channels for sampling */
Arg = channels;
Status = IOCTL (FD, sound_pcm_write_channels, & Arg );
If (status =-1)
Perror ("sound_pcm_write_channels IOCTL failed ");
If (Arg! = Channels)
Perror ("unable to set number of channels ");
/* Set the sampling frequency during sampling */
Arg = rate;
Status = IOCTL (FD, sound_pcm_write_rate, & Arg );
If (status =-1)
Perror ("sound_pcm_write_write IOCTL failed ");
Printf ("Say something: \ n ");
Status = read (FD, Buf, sizeof (BUF);/* read data into the buffer */
If (status! = Sizeof (BUF ))
Perror ("read wrong number of bytes ");
Printf ("Save As test.wav: \ n ");
If (out = fopen ("./test.wav", "WB") = NULL)
{Printf ("cannot open OUTFILE \ n ");}
// Initialize the header
/* Skip this part of code */
If (fseek (Out, sizeof (header), seek_set ))
Exit (0 );
// Initialize the FMT part
/* This part of code has been omitted */
// Write FMT to the wav file
Fwrite (& pcmfmt, sizeof (FMT), 1, out );
// Data Initialization
/* This part of code has been omitted */
Fwrite (BUF, sizeof (char), savesize, out);/* Save to WAV */
Rewind (out);/* locate the file pointer to the file header */
Fwrite (& pcmheader, sizeof (header), 1, out);/* write the header part */
Fseek (Out, sizeof (FMT), 1 );
Fwrite (& pcmdata, sizeof (data), 1, out);/* write data */
Fclose (out );
Close (FD);/* close the recording of the device */
}
3 yc2440 Development Board
# Include <fcntl. h>
# Include <sys/types. h>
# Include <sys/IOCTL. h>
# Include <stdlib. h>
# Include <stdio. h>
# Include <stdint. h>
# Include <Linux/Soundcard. h>
# Define bufsize 512 // define the buffer size
/* Define the header and FMT data structures like the recording.
Save the wav header information */
Int main (INT argc, char * argv [])
{
/* The variables required for definition are similar to those for recording */
Struct riff_header;
Struct chunk_header fmt_chunk, data_chunk;
Struct wave_format wavfmt;
Char Buf [bufsize];
File * fwave;
// Define various sound parameters like recordings
Int sndfd, status, ARG, readbytes, writebytes, writed;
If (argc <2) {// If the command line parameter is not included, an error is returned.
Fprintf (stderr, "Usage: wavplay <FILENAME> \ n ");
Exit (-1 );
}
Fwave = fopen (argv [1], "R"); // open the audio file contained in the command line parameters in write mode
If (fwave = NULL ){
Fprintf (stderr, "can't open file % s \ n", argv [1]);
Exit (-1 );
}
Fread (& riff_header, 1, sizeof (struct riff_header), fwave );
If (strncmp (riff_header.riff_id, "riff", 4) | strncmp (riff_header.riff_format, "wave", 4 )) {if the standard definition of wav files is not met, the unidentifiable file format is displayed here.
Fprintf (stderr, "unknown file format. \ n ");
Exit (-1 );
}
Sndfd = open ("/dev/DSP", o_rdwr );
If (sndfd <0) {// enable the sound device in read/write mode
Perror ("open of/dev/DSP failed ");
Exit (-1 );
}
Fread (& fmt_chunk, 1, sizeof (struct chunk_header), fwave );
If (! Strncmp (fmt_chunk.chunk_id, "FMT", 4 )){
// Read and save some FMT chunk Parameters
/* This part of code is omitted because it is similar to the recording */
} Else {// if the format is not standard, an error is returned.
Fprintf (stderr, "can't find FMT Chunk. \ n ");
Exit (-1 );
}
While (fread (& data_chunk, 1, sizeof (struct chunk_header), fwave )! = 0)
If (! Strncmp (data_chunk.chunk_id, "data", 4 )){
// Read the PCM Data in the wav file
Printf ("begin play \ n ");
/* Data chunk */
Writed = 0;
While (writed <data_chunk.chunk_size ){
// Continue processing when PCM data is not processed
Readbytes = fread (BUF, 1, bufsize, fwave); // read data from audio files
Writebytes = write (sndfd, Buf, readbytes); // write data to the sndfd sound card device for sound playing
If (writebytes! = Readbytes)
Perror ("wrote wrong number of bytes ");
Writed + = readbytes;
}
} Else {
/* Incorrect format */
Fseek (fwave, data_chunk.chunk_size + fmt_chunk.chunk_size % 2, seek_cur );
}
Fclose (fwave); // close each device
Close (sndfd );
Return 0;
}
}