C++ read wav file, subchunk1size = 65536? - audio

I wrote a program that read information from a .wav file . I received the following results.
chunkId :RIFF
chunkSize :7828798
format :WAVE
Junk chunk :JUNK
Junk size :92
Format chunk :fmt
format chunk size :65536
Audioformat :1
numberofchanels :48000
samplerate :1996488704
Byterate :131073
BlockAlign :16
bitspersample :0
subchunk2Id :
subchunk2Size :0
I don't know why wav header like that. I use sox program to look header of this wav file .
And here is result
Input File : 'AUDIO00001.wav'
Channels : 1
Sample Rate : 48000
Precision : 16-bit
Duration : 00:01:17.28 = 3709621 samples ~ 5796.28 CDDA sectors
File Size : 7.83M
Bit Rate : 810k
Sample Encoding: 16-bit Signed Integer PCM
Why's my program wrong??
I update my question:
my wav header structure:
struct WAVHEADER
{
char chunkID[4];
unsigned int chunkSize;
char format[4];
char junkChunk[4];
int junkSize;
char junkData[92];
char bext[4];
unsigned int bextSize;
char bextData[602];
char subchunk1ID[4];
unsigned int subchunk1Size;
unsigned short audioFormat;
unsigned short numberOfChanels;
unsigned int sampleRate;
unsigned int byteRate;
unsigned short blockAlign;
unsigned short bitsPerSample;
char subchunk2ID[4];
unsigned int subchunk2Size;
};
wav class:
wav::wav(const char* filepath)
{
std::ifstream wavFile(filepath);
if(wavFile.is_open())
{
wavFile.read((char*)&wavHeader,sizeof(WAVHEADER));
}
}
My confusing is that when subChunk1ID is correct ("fmt") , why does subchunk1Size seem wrong ??

The compiler seems to insert 2 bytes of padding between subchunk1ID and subchunk1Size. This is my hypothesis because
what you are seeing is that the struct is shifted 2 bytes "to the left"
and when I tested this I noticed that sizeof(WAVHEADER) was 2 bytes larger than it should be.
I'm not a C++ compiler expert so I can't tell you why it does that except that certainly it's allowed to do so.
To show visually, what the struct should look like at that point is this:
...
subchunk1ID:
01100110
01101101
01110100
00100000
subchunk1Size:
00101000
00000000
00000000
00000000
audioFormat:
00000001
00000000
numberOfChanels:
00000001
00000000
...
But instead what you are getting is this:
...
subchunk1ID:
01100110
01101101
01110100
00100000
2 bytes of pad:
00101000
00000000
subchunk1Size:
00000000
00000000
00000001
00000000
audioFormat:
00000001
00000000
...
00000000 00000000 00000001 00000000 is the number 65536 in little endian byte order.
So really what you have found is that this struct casting is not a reliable way to read a file. You should read it "the hard way" instead (one number at a time). There are other pitfalls like this one such as:
Endianness.
Existence, size and ordering of particular subchunks is not consistent in a WAV file. There is no reason JUNK and bext need to appear in the file, nor do they need to be sizes known at compile time of the program.

Related

How to control the order of sections in MSVC x86 compiled binaries?

For some very low level application I require to have the entry point as the lowest/first item in the binary.
To do this I've done the following:
Placed the entry point in "function_ordering.txt" and passed it to the /ORDER linker option.
Generated a map file to see the following sections exist:
Preferred load address is 00040000
Start Length Name Class
0001:00000000 000210fdH .text$di CODE
0001:00021100 002d7b0cH .text$mn CODE
0001:002f8c10 00027874H .text$x CODE
0001:00320490 0000830fH .text$yd CODE
0002:00000000 000005d8H .idata$5 DATA
0002:000005d8 00000004H .CRT$XCA DATA
0002:000005dc 00000004H .CRT$XCAA DATA
0002:000005e0 00000004H .CRT$XCL DATA
0002:000005e4 00001554H .CRT$XCU DATA
0002:00001b38 00000004H .CRT$XCZ DATA
0002:00001b3c 00000004H .CRT$XIA DATA
0002:00001b40 00000004H .CRT$XIAA DATA
0002:00001b44 00000004H .CRT$XIC DATA
0002:00001b48 00000004H .CRT$XIY DATA
0002:00001b4c 00000004H .CRT$XIZ DATA
0002:00001b50 00057fb8H .rdata DATA
And that WinMain was AFTER this data. So I figured I need to put the function in its own section to make it "first".
So I put it in its own section:
#pragma code_seg("test")
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
But this put the function even further away! This is because my test section appeared after the other sections.
So then I did this:
#pragma code_seg(".text$di")
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
Which resulted in:
Address Publics by Value Rva+Base Lib:Object
0000:00000000 ___guard_fids_count 00000000 <absolute>
0000:00000000 ___guard_flags 00000000 <absolute>
0000:00000000 ___guard_fids_table 00000000 <absolute>
0000:00000000 __except_list 00000000 <absolute>
0000:00000ec7 ___safe_se_handler_count 00000ec7 <absolute>
0000:00009876 __ldused 00009876 <absolute>
0000:00009876 __fltused 00009876 <absolute>
0000:00000000 ___ImageBase 00040000 <linker-defined>
0001:00000000 _WinMain#16 00041000 f lol.obj
BOOM it worked. But this seems very much like a nasty hack.
So the question is.. is there a "supported" or "documented" way to get my section to appear first?

Noise in Merging two pcm files

I am merging two pcm data and the resultant pcm is having additional noise of grrrrrrrrrr. My code is :
int main(void)
{
FILE *rCAudio;
FILE *raudio;
FILE *wtest;
rCAudio=fopen("Audio1.pcm","rb"); //Reading first pcm file
if(rCAudio==NULL)
cout<<"Errr";
raudio=fopen("Audio2.pcm","rb"); //Reading second pcm file
if(raudio==NULL)
cout<<"Errr";
fopen_s(&wtest,"AudioMerge.pcm","ab"); // Writing final pcm file
short* first= new short[1792];;
short* second= new short[1792];;
short* merge = new short[1792];
short sample1,sample2;
while(1)
{
fread(first,2,1792,rCAudio);
fread(second,2,1792,raudio);
for(int j=0;j<1792;j++)
{
sample1 = first[j];
sample2 = second[j];
int mixedi=(int)sample1 + (int)sample2;
if (mixedi>32767) mixedi=32767;
if (mixedi<-32768) mixedi=-32768;
merge[j] =(short)mixedi;
}
fwrite(merge,2,1972,wtest);
}
}
I got the solution , the problem was:
I have written Audio1.pcm with 4096 bytes at a time in BYTE and Audio2.pcm with 4096 bytes at a time in BYTE. But i was reading 1972 bytes at a time in short.
So i corrected it by reading 4096 bytes at a time in BYTE and save by third merge file with 4096 bytes at a time in BYTE.

Reading boot sector of a FAT32 file system

I am writing a program and I need to access some information in the boot sector about the FAT32 file system that I have mounted.
Here is what I did, fully commented.
int main (void) {
unsigned short *i; //2 byte unsigned integer pointer
char tmp[1024]; //buffer
int fd; //file descriptor from opening device
fd = open("/dev/sdf", O_RDONLY); //open the device file
lseek(fd, 14, SEEK_SET); //set offset to 14 (0x0E), i.e. storing "no. of reserved sectors" of the FAT32 system
read(fd, tmp, 2); //read off 2 bytes, "no. of reserved sectors" is represented by 2 bytes
i = &tmp; //point j at those 2 bytes
printf("*j: %d\n", *j); //print *j out
close(fd); //close device
return 0;
}
The output of *i is 38, which is nonsense. I formatted the file system with mkfs.vfat. I set the "no. of reserved sectors" to 32.
What I have tried:
i = (unsigned short *) &tmp, do a casting, this removes the warning when I compile, but doesn't help
read(fd, tmp, 512), load the whole boot sector (512 bytes) into tmp, then read from the buffer, but doesn't help, result still 38 though.
fiddle with the offset, i.e. change 14 to 13 or 15, in case I get the index wrong. It prints out 9744 for 13 and 512 for 15 respectively, so doesn't work.
I'm not sure whether I'm doing it the right way. Can someone please point me in the right direction?
Thanks in advance,
Felastine.
Try running:
$ dd if=/dev/sdf of=/tmp/x.bin bs=512 count=1
And then:
$ hd /tmp/x.bin
Or
$ od -tx2 /tmp/x.bin
And post the first lines.
Chances are that your fattools are adding 6 extra reserved sectors of their own. And then they substract them before showing the data.
unsigned short *i; //2 byte unsigned integer pointer
char tmp[1024];
[...]
i = &tmp; //point j at those 2 bytes
tmp is char[], &tmp something of order char**.
Think again, you don't want the & here.

Accessing external bus in kernel space on an ARM based board

I'm trying to write an LCD display driver on an ARM based board.
The LCD controller is plugged on the external memory bus.
So I try to convert the physical address of registers of the controller to the virtual one.
I use the following pieces of code to do that :
#define AT91_VA_BASE_CS2 phys_to_virt(0x50000000)
static inline unsigned char at91_CS2_read(unsigned int reg)
{
void __iomem *CS2_base = (void __iomem *)AT91_VA_BASE_CS2;
return __raw_readb(CS2_base + reg);
}
static inline void at91_CS2_write(unsigned int reg, unsigned char value)
{
void __iomem *CS2_base = (void __iomem *)AT91_VA_BASE_CS2;
__raw_writeb(value, CS2_base + reg);
}
void write_lcd_port (int mode, unsigned char cmd_dat)
{
while ((read_lcd_port() & 0x03) != 0x03) {
/* wait while LCD is busy!!! */
} /* endwhile */
/* Send Command */
if (mode == 1)
{
at91_CS2_write(4, cmd_dat);
}
/* Send Data */
if (mode == 0)
{
at91_CS2_write(0, cmd_dat);
}
}
I get the following message :
Unable to handle kernel paging request at virtual address 4f000004
pgd = c39bc000
[4f000004] *pgd=00000000
Internal error: Oops: 5 [#1]
Modules linked in: module_complet dm9000 at91_wdt vfat fat jffs2 nls_iso8859_1 nls_cp437 nls_base usb_storage sd_mod sg scsie
CPU: 0
PC is at read_lcd_port+0x1c/0x38 [module_complet]
LR is at 0x1
pc : [<bf0a21b8>] lr : [<00000001>] Tainted: P
sp : c380bf1c ip : 60000093 fp : c380bf2c
r10: 0003a804 r9 : c380a000 r8 : c001de64
r7 : 00000000 r6 : fefff000 r5 : 0000009c r4 : 00000001
r3 : 4f000000 r2 : 00000000 r1 : 00001438 r0 : bf0a25cc
Flags: nZCv IRQs on FIQs on Mode SVC_32 Segment user
Control: C000717F Table: 239BC000 DAC: 00000015
Process insmod (pid: 903, stack limit = 0xc380a198)
Stack: (0xc380bf1c to 0xc380c000)
bf00: 00000001
bf20: c380bf44 c380bf30 bf0a21f4 bf0a21ac 00000000 fefa0000 c380bf54 c380bf48
bf40: bf0a2288 bf0a21e4 c380bf64 c380bf58 bf0a246c bf0a2280 c380bf84 c380bf68
bf60: bf0a4058 bf0a2464 40017000 c01c89a0 bf0a2d80 c01c8990 c380bfa4 c380bf88
bf80: c004cd20 bf0a4010 00000003 00000000 0000000c 00000080 00000000 c380bfa8
bfa0: c001dcc0 c004cbc8 00000000 0000000c 00900080 40017000 0000162e 00041050
bfc0: 00000003 00000000 0000000c bea0fde4 bea0fec4 00000002 0003a804 00000000
bfe0: bea0fd10 bea0fd04 0001b290 400d1d20 60000010 00900080 20002031 20002431
Backtrace:
[<bf0a219c>] (read_lcd_port+0x0/0x38 [module_complet]) from [<bf0a21f4>] (write_lcd_port+0x20/0x80 [module_complet])
r4 = 00000001
[<bf0a21d4>] (write_lcd_port+0x0/0x80 [module_complet]) from [<bf0a2288>] (wr_cmd+0x18/0x1c [module_complet])
r5 = FEFA0000 r4 = 00000000
[<bf0a2270>] (wr_cmd+0x0/0x1c [module_complet]) from [<bf0a246c>] (lcd_init+0x18/0x80 [module_complet])
[<bf0a2454>] (lcd_init+0x0/0x80 [module_complet]) from [<bf0a4058>] (mon_module_init+0x58/0xcc [module_complet])
[<bf0a4000>] (mon_module_init+0x0/0xcc [module_complet]) from [<c004cd20>] (sys_init_module+0x168/0x2c8)
r6 = C01C8990 r5 = BF0A2D80 r4 = C01C89A0
[<c004cbb8>] (sys_init_module+0x0/0x2c8) from [<c001dcc0>] (ret_fast_syscall+0x0/0x2c)
r7 = 00000080 r6 = 0000000C r5 = 00000000 r4 = 00000003
Code: e59f001c eb3e43c2 e3a0344f e59f0014 (e5d34004)
Segmentation fault
Note that this method works for internal peripherals (such as timers).
So in some cases, phys_to_virt works.
I think that no page is allocated at the address 0x50000000. How can I allocate a page at this specific address ?
I found functions like kmap but it seems to be very complicated and I don't know how to use it.
The best way to access memory-mapped peripherals is with the kernel's ioremap and friends.
First, declare that you want to use a specific region of memory for your peripheral:
struct resource *res = request_mem_region(0x50000000, region_size, "at91");
When you unload your driver, you will want to free that memory region.
release_mem_region(0x50000000, region_size);
Now, you can remap the I/O region before use.
void *ptr = ioremap(0x50000000, region_size);
If you want to prevent caching of these registers, use ioremap_nocache instead. You can also only remap a subregion of your device's memory space if you're only using that part.
Now that you have the iomapped region, you can do I/O on that memory.
iowrite8(value, (char *)ptr + reg);
unsigned int val = ioread8((char *)ptr + reg);
Once you're done reading from and writing to that region of memory, you can unmap it.
iounmap(ptr);
I hope this helps. I would recommend reading (or at least using as a reference) Linux Device Drivers, 3rd Edition, which can be read online for free.

Why can't I register edge triggered interrupts in Linux 2.6.26?

First time poster, so please excuse any stupidity.
I'm working on porting a custom CPLD driver on a linux kernel built for an MPC83xx from 2.6.22 to 2.6.26, and am receiving an unexpected Oops. The driver works fine for the .22 kernel, but the .26 kernel chokes on my call to request_irq. Does anybody know why there was a change in behavior, or better yet, what I need to do to resolve it?
I've tracked down the source of the Oops to a call to kernel/irq/manage.c, where desc->chip->enable(irq) is called in setup_irq(), and it looks like the function pointer to enable is being cleared in a call to ipic_set_irq_type() in arch/powerpc/sysdev/ipic.c. Unfortunately, I have no clue why.
I've included both the Oops and a sample kernel modules that replicates the issue.
Oops -
Unable to handle kernel paging request for instruction fetch
Faulting instruction address: 0x00000000
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT SCPA-G2
Modules linked in: cpld(+)
NIP: 00000000 LR: c004b930 CTR: 00000000
REGS: df8b5df0 TRAP: 0400 Not tainted (2.6.26-twacs-100.0.0)
MSR: 20001032 <ME,IR,DR> CR: 24022422 XER: 20000000
TASK = dfbcfc00[488] 'insmod' THREAD: df8b4000
GPR00: 00000000 df8b5ea0 dfbcfc00 00000017 00000001 00000001 00000000 c02d1fb4
GPR08: 00002268 00000000 00000000 00000000 44022484 10073f68 1ffcb000 007ffeb0
GPR16: 00000000 00000000 00800000 00000000 bffff7f0 00000000 1006e3dc 00000000
GPR24: 00000002 00000000 00000000 00009032 df9d04c0 00000017 df8b4000 c02d40e4
NIP [00000000] 0x0
LR [c004b930] setup_irq+0x404/0x430
Call Trace:
[df8b5ea0] [c004b8ec] setup_irq+0x3c0/0x430 (unreliable)
[df8b5ed0] [c004bbd8] request_irq+0xe0/0x130
[df8b5f00] [e1078054] cpld_init+0x54/0xd0 [cpld]
[df8b5f10] [c0048ba0] sys_init_module+0x14c/0x1d8
[df8b5f40] [c0010008] ret_from_syscall+0x0/0x38
--- Exception: c01 at 0xff27bb0
LR = 0x10019ca8
Instruction dump:
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
Kernel panic - not syncing: Fatal exception
Module -
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
static unsigned int cpld_virq = NO_IRQ;
unsigned value = 0xdeadbeef;
static irqreturn_t cpld_isr(int irq, void *dev_id) {
return IRQ_HANDLED;
}
void __exit cpld_cleanup(void) {
free_irq(cpld_interrupt, &value);
irq_dispose_mapping(cpld_virq);
return;
}
int __init cpld_init(void) {
int retval;
unsigned long cpld_interrupt = 23;
cpld_virq = irq_create_mapping(NULL, cpld_interrupt);
if (cpld_virq == NO_IRQ) {
return -EBUSY;
}
retval = request_irq(cpld_virq, cpld_isr,
IRQF_DISABLED | IRQF_SHARED | IRQF_TRIGGER_FALLING,
"CPLD", &value);
if (retval) {
irq_dispose_mapping(cpld_virq);
return retval;
}
return 0;
}
module_init(cpld_init);
module_exit(cpld_cleanup);
MODULE_LICENSE("Dual BSD/GPL");
Thanks for the help. I've been beating my head on this for several days now, and am open to any suggestions.
My copy of the 2.6.26 kernel's ipic_set_irq_type() doesn't do anything with the enable() pointer. It does, however, have the following comments that were not in 2.6.22:
/* ipic only supports low assertion and high-to-low change senses
*/
and
/* ipic supports only edge mode on external interrupts */
It looks like what you were doing on 2.6.22 was not supported by the hardware.
Aaah. Sounds like JayM was close, though not for the reason he thought. I just saw a patch go across the linuxppc-dev mailing list stating that edge supported interrupts were broken.
http://lkml.org/lkml/2010/5/3/363
This may not be the root cause, but is indicative of a problem I'm not going to fix.

Resources