文章列表
 
2010-08-08 11:16

随笔:关于开发语言

cheungmine

写这样的一个大的论题,对于我的水平而言,实在有些过了。因此,我只能把个人体会表达 出来。因为工作的原因,实在没多少时间写博客,这种完全出于公益的目的,不但会使我的项目经理不满足于我的绩效,也使自己不安于无法答复每一个读者提出的 问题。好像一切都是敷衍了事。因此我的文章(如果还能称为文章的话)不会有很多的篇幅介绍原理,描述实现细节。

当然会导致部分人的不满,而且我自己也是个愤青,常常会因为看不惯周围的事物而发牢 骚。但我想,我不是为了适合读者而存在的。如果有一部分读者适合我,我就感觉到欣慰了。作为程序员,最重要的职责是编写高效率的代码,不会为了注释而注 释。因为,优秀的代码,本身就是一种注释。就如同阅读古文,难道还需要白话问注释么。

最近一直喜欢看史记、通鉴之类的古籍,偶尔也看聊斋,当然都必须是古文的。细细读下 去,居然还读懂了,而且,突然发现古代文学家的智慧,透过现代激光打印的文字,跃然纸上,纵横捭阖,喜怒哀乐,悲欢离合,才子佳人,风花雪月。以前觉得高 中学古文没什么用处,不就是为了考大学么,一个学理工的。现在才恍然,人届中年,突然对故纸堆里的东西敢兴趣了。就如同北京的老头老太太看京戏一样,总有 一天我也会步入这个队伍。

写程序多年,虽然不是高手,倒也写出不少可圈可点的软件。用过Delphi、VB、 VC、Java、C#。当然最后选择的还是C/C++。大学里学C语言,基本没学明白,也不知道这东西除了写写数学公式,还能做什么。工作了,朋友推荐学 习Delphi2.0,好像贵州农村的孩子突然到了上海,被眼前华丽的景象惊呆了。当然,最后,这个贵州的孩子发现,外表美丽堂皇的上海,其实角角落落里 也是污秽不堪。哪里比得上家乡的山山水水啊。当然这是个比喻,我也不是贵州的。

人早晚要返璞归真的,从哪里来到哪里去。而对于计算机这么学问,我相信,永远没有止 境。工具不断变化,界面更加华丽。开发日趋简单。然而,真正不变的核心还是存在的——算法。虽然写一个数据库查询软件,只要会拖控件,就可以了。内存不需 要知道如何分配,更无需了解释放了。现代工业文明就是制造富士康流水线上的机器人。软件行业也是一样。软件行业最低端的程序员,无非是流水线上的一个普通 员工,是谁造成了这个行业的目前这个局面,是微软?是IBM?是Sun?如今,太多的程序员为Java、C#、Ruby叫好,实不知,这些语言的就是流水 线,生产这些流水线的公司,以它在工业领域的超凡的领导能力,在一批一批地制造IT民工。当然有利于这些设施,最后成功登上职业金子塔的顶端,比如马云、 史玉柱。这些人更多意义上是商人,不是技术员。

软件行业注重开发效率。我承认这句话的正确性。但是,如果仅仅为了效率,那么有了 Java之后,为什么还要开发出C#呢?重复发明的车轮,并未证明比最初的好。其实,都是工具。包括你、我,都是别人的工具。这样一来,使用什么工具变得 不那么重要了。于是就有了C#、Java等妄图主宰一切,写的好好的C算法,非要用这些类似脚本的语言实现一遍。

这个世界是对象的么?面向对象的传道者危言耸听地告诉我们,世界一切都是对象的。然 而,直到今天,我还不能说,如何为我儿子养的一乌龟创建一个对象模型。对象如同对象本身一样复杂,基本上是不可以描述清楚的。为了创建乌龟这个对象,我还 必须了解嘴巴这个对象,乌龟的嘴巴也许可以继承人的嘴巴这个对象,但是在是否刷牙的问题上我有陷入了困境。因此,世界本身就是未知的,复杂的。对象的目的 无非是解决问题,那么没有对象的时候,我们就不能解决问题了么?

如果我的自行车坏了,我会把工具箱打开,取出工具修车。但我其实并不需要工具箱这个对 象。其实,我没有工具箱的时候,它们工作的也很好。为了修车,我不会专门买一个工具箱,然后买齐全各种扳手、螺丝、胶皮。我只是最初的时候有一只螺丝刀, 然后有一天买了一个打气筒,后来还买了挫胶皮的锉和胶水。虽然我一直没机会自己补胎。但是,我始终不知道我最终要买什么来填充这个工具箱。似乎这个工具箱 永远不会满。突然有一天,我宣告我的工具箱对象终于架构完成了。可是,我突然发现我的自行车已经老化的不能再骑了。

如果上班的公司和家的距离在2km之内,我想没有谁会开车去上班,除非那些不花自己钱的人。因此,选择工具的时候,不是越完美越好、越强大越好。实用加适用。

如果今天让我来写OS或DBMS,我仍然会选择C来实现核心。如果写个界面,可以有100种以上的选择。

用什么,是个一个人的自由,也决定的这个人的自由。

不要改变自己的信仰,让信仰改变我们自己。

Original: http://blog.csdn.net/cheungmine/archive/2010/07/02/5709222.aspx
 
2010-08-08 11:04

When Andrew Hume presented the Usenix Lifetime Achievement Award in San Diego in June, he managed to say exactly two words -- "Richard Stevens" -- before a standing ovation drowned him out. "I sat next to Richard's family at the presentation," says Tom Christiansen, a well-known figure in the Perl programming community who had known Stevens on and off for years. "It was stunning. I don't know if his family did, but I sure noticed a lot of the audience in tears."

"Usenix," (a word coined to get around trademark restrictions on the word "Unix") is the Advanced Computing Systems Association. W. Richard Stevens is the author of "TCP/IP Illustrated" and "Unix Network Programming," each of which runs to three volumes, and "Advanced Programming in the Unix Environment." Their influence among Unix users is hard to overstate. Thousands of programmers all over the world consider Stevens a guru and his works essential to their jobs.

"It blew my mind," says his sister, Claire Stevens. "I knew he wrote those books, but it never made a dent. I had absolutely no idea that all these people knew and were touched by him." Claire and Richard's wife, Sally, accepted the award on Stevens' behalf. Stevens died on Sept. 1, 1999. He was 48 years old.

His death hit the close-knit Unix community hard. Fiercely intelligent and deeply private, Stevens set an example for everyone in the Unix world. What he didn't know, he determined to find out; what he did know, he strove to pass on to anyone who was interested. A year after his death, memories of one of the Unix community's most beloved experts are still fresh and vital.

Christiansen's recollection is typical. The two were casual acquaintances from the academic conference circuit. "I remember I was doodling around on the piano, and Richard came over and said, 'I heard you doing that at some other conference and it inspired me to take up the piano again,'" Christiansen says. "On subsequent meetings he would tell me all about his progress. As with everything he talked about that he really loved, his eyes just kind of sparkled."

With Christiansen, Stevens talked about music. With cryptographer Greg Rose, a fellow pilot, he talked about flying. With Dave Hanson, who sat on the committee to assess his doctoral thesis, Stevens talked about yet another shared passion, skiing. To everyone who knew him, it seemed he cared about the things that mattered most to them.

"He was a very good listener and he knew something about every subject," says Claire. "He could always contribute something, or at least sound intelligent."

Yet Stevens was also an extraordinarily private man. Christiansen, Rose and Hanson all knew him for years, yet none felt that they knew him well. "I wouldn't say he was complex, but because of his intelligence he could come across that way," Claire admits.

He brought the full force of his intellect to bear on his work, and it showed. Stevens' books are regarded as models of the genre. "I remember he shocked me, because I ran into him at some conference and he said, 'I wish I'd brought the 'Perl Cookbook' so I could have had you autograph it for me,'" says Christiansen. "I don't consider my books to be in anywhere near the same league of serious, hard work as his. That he would say to me 'I should have got your autograph' was like Dennis [Ritchie, one of the original authors of Unix] saying it."

"He gave extremely cogent explanations of what's going on," says Rose. "His books are so much more readable than most computer books. A lot of authors look at the documentation and rewrite it with little or no interpretation. He took the time to understand."

His perseverance was an artifact of an apparently ferocious curiosity. "When I hit something that I don't understand, I take a detour and learn something new," said Stevens in an interview two years before his death. "This often makes my books late by a few months, but I think accuracy and completeness are essential."

It may have been Stevens' sense of himself as an outsider that inspired this level of dedication. He and his brother and sister were copper-mining brats, born in Africa to a metallurgical engineer; they divided their childhood among northern Rhodesia (now Zambia), Utah, New Mexico, Washington and South Africa. Stevens didn't start out in computer science at all, but in aerospace. It just happened that he graduated in 1973, when Boeing was laying off thousands of aerospace engineers. Programming, like piano, was a late acquisition that took.

"I really believe that my background is fundamental to the success of 'Unix Network Programming' and my other books," he said. "That is, I was not one of the developers at Berkeley or AT&T, so the writing of UNP was not a 'memory dump.' Everything that is in the book I had to dig out of somewhere and understand myself."

In fact, Stevens belonged to the generation of Unix geeks who pored over not-exactly-legal copies of John Lions' legendary commentary on the Unix source code. Lions firmly believed that no one could understand the theory of computer science without concrete examples, ideally embodied in C programs. Stevens seems to have agreed.

"Certainly his books do that. He tends to walk you through the code," says Hanson, who led the graduate seminars at the University of Arizona where Stevens discovered the Lions books. "It's not like you can read this stuff while you're sitting in front of the television. It's a particular style of learning about software that requires a very heavy investment upfront. But it pays off."

It's not as easy, or as obvious, as it sounds. Publishing code legibly is hard work, and calls for stubborn authors who insist on the best tools for the job. Stevens greatly admired and strove to emulate Donald Knuth, who wrote "The Art of Computer Programming," and Brian Kernighan, "The C Programming Language," whose books are as beautifully laid out as they are brilliantly written.

For his own work, he insisted on a text-formatting tool even more venerable and revered than Knuth's Tex. "Rich had told me that he gets to send 'troff,'" says Christiansen in awed tones, referring to a fairly archaic layout program. "He still used all the cool old tools, and he prepared camera-ready copy for the publisher. It's very, very rare that authors aren't forced to use Microsoft Word or unadorned SGML." Controlling his own means of production allowed Stevens to explain difficult concepts visually as well as verbally -- hence the apparently perverse theme of "TCP/IP Illustrated." Visualizing a protocol? It sounds crazy, but it works.

His books are so good that they have come to symbolize intelligence. In "Wayne's World II," Garth's girlfriend carries a copy of "Unix Network Programming." Stevens discovered this when he took his 13-year-old son to see the film. His son grabbed his arm and said, "Dad, that's your book!"

"I couldn't believe it," he told programmer Trent Hein. "My book was used to define the ultimate geek, and suddenly my son thinks I'm really cool."

His son was right.

Original: http://www.salon.com/technology/feature/2000/09/01/rich_stevens

 
2010-02-20 18:46


Well I won't make you tell me
What I've come to understand
You're a certain kind of woman
I'm a different kind of man
I've tried to make you love me
You've tried to find a spark of the flame that burned but
Somehow turned to smoke rings in the dark
The loneliness within me
Takes a heavy toll
'Cause it burns as slow as whiskey through an empty aching soul
And the night is like a dagger
Long and cold and sharp
As I sit here on the front steps  
Blowing smoke rings in the dark
I- I- I know I must be going
'Cause loves already gone  
And all I'm taking with me are the pieces of my heart
And all I'll leave are smoke rings in the dark
The rain falls where it wants to
The wind blows where it will
Everything on earth goes somewhere  
But I swear we're standin' still
So I'm not going to wake you    
I'll go easy on your heart  
I'll just touch your face and drift away  
Like smoke rings in the dark
I- I- I know I must be going
'Cause loves already gone
And all I'm taking with me are the pieces of my heart and
All I'll leave are smoke rings in the dark
------------------------------------------------Gary Allan----Smoke Rings In The Dark

很久没有在这里写些东西,好像从前年进单位后就再也不能回到过去,总在想是世界改变了我还是我改变了我?年前拿起了5年没有动过的吉他,接下来的每晚都像是得到新玩具的孩子,简单,快乐,悲伤,或者自私,贪婪...是不是应该像以前一样...

把背景音乐换成了了Gary Allan的Somke Rings In The Dark,希望来的朋友能听到并喜欢,并允许我说一声:新年快乐.

 
2009-09-20 19:37

I do not hover. Something I just could not let it go. I believe in faith.  I believe I would be paid the same as what I paid for it. I believe there would be a way to heaven. I believe we could find the way to heaven. I do not hover. I just cannot let you go.
 
2008-11-27 16:40

http://eng.edu-edu.com.cn/audio/Don'tloveyounomore.mp3
Please click the link above to download this mp3, THX
.......
Rain outside my window pouring down
What now, your gone, my fault, I'm sorry
Feeling like a fool cause I let you down
Now it's, too late, to turn it around
I'm sorry for the tears I made you cry
I guess this time it really is goodbye
You made it clear when you said
I just don't love you no more
......
-----------------------------------------------------------Don't Love U No More(I'm Sorry)------Craig David

不知道什么时候,人人谈得都是金融危机,也难怪,一个系70个毕业生只有2个签了合同,其他都在砸墙。想当年hisense号称是我们的后花园,今年花园变大使馆了,不能随便进了;一个被称作海尔的公司都过来忽悠,号称自己是变革者。算了,认了,忙活了半天,嘴唇一直都是微笑的,眼睛又结膜炎,终于争取到过几天去lucent实习,唯一问题就是不知道啥时侯能给个合同签签。算了,像同学所说:现在就你能一个月赚2ooo块........回家一趟拿材料,结果被暖气片子上的金属银粉给差点弄死,半夜被憋起来,呼吸困难,眼睛流泪不断,怕妨碍他们二老睡觉,自己只能打开窗睡了一晚...坚决打击各种不合格装修材料及各种油漆,真会出人命!听厌了indie和metal,偶尔听一听Craig David的口水歌,想起第一次听westlife口水的感觉,发现累的时候只想想听一些口水歌,有点小时候吃酸梅粉的味道。突然插播一段搞笑时频,由月月提供:

天津河北区邮电局搞笑舞:

 
2008-11-21 12:56

引图:据说牛老师就是被这个苹果树上的苹果给砸了脑子......以下原文有sougou比尔盖子原创!

3月28号是牛顿的忌日,但是知道的人很少,我们毕竟更关心沈殿霞和张国荣。其实牛顿老师在科学圈里曾经很有权势,被女王封了爵位成了贵族,官至皇家造币局局长兼皇家学会会长。如果阿尔伯特没有辞了以色列总统的话和他有一拼。说他有权势并不仅是官大,主要是贡献大。如果17世纪就有诺贝尔奖的话,牛顿老师至少能连续垄断4届物理学奖(分光计;力学体系的构建;反射望远镜;万有引力),同时为了表彰他在炼金方面的造诣,再奉送他一届化学奖。而且这孙子鼓捣出了流数术,所以菲尔兹数学奖也要给他。要知道,他的这些发现基本都是在26岁以前获得的,30岁以后牛顿就开始玩票了,成天琢磨上帝和炼金,以及怎样把莱布尼茨搞臭,捎带手的把以前的发现整理成书。所以你能想象到他在当时的欧洲是如何的一呼万应,敢跟他叫板的只有莱布尼茨和大主教贝克莱。牛老师死的时候,全英国的名流以给他扶柩为荣,全欧洲的名流蜂拥伦敦。来自法国的傻逼文科生伏尔泰在国葬现场大受刺激,回去就写了首诗,嫉妒之情溢于言表。
  牛顿老师的一生是天才的一生,战斗的一生,也是孤独的一生。一辈子没有朋友,也没有结过婚,很可能到死都是处男,关于牛顿是否处男的问题,由于篇幅过长,我将在另一篇文中论证。当然他肯定不会孤独,因为科学的世界里乐趣无限,快感连连。出乎世俗想象的是,科学其实远比任何娘们儿都风骚,玩科学比玩女人爽得多,得到一个成果所获得的高潮强烈而持久,不仅有快感,更有巨大的自我认同感,远胜于那几秒寒战之后无边的空虚与落寞。所以陈景润其实是沉溺于美色不能自拔,身体弱架不住高潮过度被爽死了。
  牛顿老师茕茕孑立,形影相吊的原因是多方面的。首先他生性孤傲,自恃高才,瞅谁都是傻逼,当然不会真心跟傻逼交朋友。同时在他眼里人是不分男女的,只有傻逼和巨傻逼两种,所以他对女色没兴趣也就可以理解了。有婚介中心给他介绍过几个名媛,拾掇拾掇都是当王妃的坯子,但一见面就受不了牛顿的牛逼烘烘和不知所云。比如有次相亲,他把姑娘的手指头塞进了烟斗。
  另一方面是外在的,不光他不愿意交朋友,也没有人真正想跟牛顿当朋友,结交他的人都是有目的的。人们对他只有敬畏和仰慕,并不真的喜欢他。这道理其实很浅显,绝大部分人都热衷于跟比自己傻的人待着,很少有人愿意在人精的身边衬托自己的二逼。所以好多人都喜欢小动物和小孩子,就是因为这些东西够傻。不少姑娘一见到小猫小狗小人儿都会迫不及待的搂抱,接踵而至的就是很嗲的说好可爱欧~,听得我阴毛都竖起来了。有时候可爱和憨态可掬的潜台词就是弱智。小猴子也很好玩,喜欢的人就少多了,因为猴子机灵到能戏弄人,那些人没有驾驭猴子的自信。同理,喜欢小孩的都是喜欢他们的单纯与缺心眼,在他们眼里,小孩跟小动物没有本质区别,也都是四条腿走路,露着屁眼随时拉撒。如果遇到一个小天才,3岁就会心算三位数乘法或者知道傻逼二字的正确写法,她们一定会骇破了胆。所以那些喜欢养猫狗的女士们别再标榜自己有爱心了,你们其实比谁都缺德。我从不喜欢猫狗,这是因为我敬畏大自然的生灵而不忍戏弄它们;我也不喜欢小孩,因为我把他们当作一个大写的人而不是小畜生看待。
  大家不喜欢牛顿的另一个原因是他性格暴戾乖张。长年在他身边的人回忆说,牛顿在人前只笑过两回,其中一次还是嘲笑:有人问他,欧几里得的《几何原本》那么老朽,不知道还有什么价值。牛顿闻听放声大笑。而且他人品太差,跟谁都打架。众所周知他从小就有校园暴力的记录,胖子同学不小心踩了他的风车,他抬手就把胖子打哭了,我们的教科书居然说这是他有志气的表现。长大了不以拳脚论高下,他就雇用枪手大骂莱布尼茨,甚至不惜化名亲自去骂,人品至此真是无以复加。莱布尼茨若不是脸皮厚早就跟纳什一样疯了,而且牛顿老师肯定会拍个片子叫《丑陋心灵》继续恶心人家。
  关于牛顿的另一个谎言是他的谦虚,证据就是牛顿老师说过两段著名的话,一段是站在巨人肩膀上,另一段是海边捡石头子。这确实很有迷惑性,我第一次听到后感动的直冒鼻涕泡。但任何话语都是有语境的,巨人肩膀那一句的语境是这样的:胡克其实早就发现了万有引力定律并推导出了正确的公式,但由于数学不好,他只能勉强解释行星绕日的圆周运动,而且他没有认识到支配天体运行的力量其实是普遍存在的,是“万有”的。第谷早在100年前就发现了行星的公转其实是椭圆运动,开普勒甚至提出了行星运动三定律。所以科学界对胡克的成果不太重视。后来数学小狂人牛顿用微积分极其圆满的解决了这个问题并把他提出的力学三条基本定律成功推广到了星系空间,改变了自从亚里士多德以来公认的天地不一的旧观点,被科学界奉为伟大的发现。于是胡克大怒,指责牛顿剽窃了自己的成果。牛顿尖酸刻薄的回敬道:是啊,我他妈还真是站在巨人的肩膀上呢!这本是一句反语,至少不是真的想客气一下。几百年后罗永浩说自己只是站在巨人的肩膀上也是这意思。但后人出于塑造完人的目的,只保留了孤立的原话而去掉了语境,变成了一句彻头彻尾的谦辞。
  牛顿老师人品差,不谦虚,没朋友,按现在的说法这是典型的高智商低情商,事业不会成功。但我们也发现,当智商高到一定程度的时候是可以取代情商的。所以那些说自己情商低的所谓天才们,你们没成功只是他妈的还不够聪明而已,怨不着人家情商。要知道牛顿是个遗腹子和早产儿,出生时体重不到5斤,没吃过DHA和RHA配方的奶粉。亲娘改嫁后跟文盲姥姥度过无聊的童年,没有任何的早期智力开发和学前启蒙,7岁上学以前脑子里空空如也,牛妈妈对他的期望仅仅是认识点字然后回家务农。但是牛顿上中学后已经熟练掌握了拉丁语希腊语西班牙语和英语,然后被推荐进了剑桥,20出头就当了卢卡斯教席的终身教授。
  晚年的牛顿除了升官发财再无其他骄傲之处,而且官迷心窍,没退休一直干到85岁寿终。当然他并没闲着,写了150万字的神学著作,同时一心扑在化学事业上,在家里盖了窑子,拿出年轻时搞物理的劲头玩命试验。但这次他的出发点就错了,总是希望从黄铜和煤渣中提炼出黄金。要知道化学反应只改变分子并不能改变原子,能给原子做变性手术的只能是核反应。他违背了物质不灭的化学定律,所以虾米了。
最后,说两段悼词。一段是他的墓志铭:伊萨克牛顿爵士,安葬在这里。他以超乎常人的智力,第一个证明了行星的运动与形状;彗星轨道与海洋的潮汐。他孜孜不倦地研究,光线的各种不同的折射角,颜色所产生的种种性质。让人类欢呼,曾经存在过这样一位,伟大的人类之光。另一段是英国诗人写的:自然和自然的规律隐藏在茫茫黑夜之中。上帝说:让牛顿降生吧。于是一片光明。
  不知道为什么,一想到这里,我总是有点感动。
 
2008-11-20 22:04

/* The Reflection Test Class used to realize the functions of
   java.lang.reflect, referrenced by Corejava Volume I
   Display the fields, constructors, and methods, as well as annotations
   and exceptions respectively
   by kingmmxtj Nov 20, 2008
  
http://hi.baidu.com/kingmmxtj
*/

import java.util.*;
import java.lang.reflect.*;
import java.text.*;
import java.lang.annotation.Annotation; // pay attention to differ the java.text.annotation

public class ClassAnalyzer
{
    public static void main(String[] args)
    {
         // read the class u input
         String name;
         if(args.length > 0)
                name = args[0];
         else
         {
                System.out.println("Enter one class naem(e.g. java.uitl.Date): ");
                Scanner in = new Scanner(System.in);
                name = in.next();
         }
  
    try
    {
           // print class name and super class name
           Class cl = Class.forName(name);
           Class supercl = cl.getSuperclass();
           System.out.print("Class " + name);
           if(supercl != null) // if(supercl != null && supercl != Object.class)
           System.out.print(" extends " + supercl.getName());
           System.out.print("\n{\n");
          // leave 4 blank at the beginning
           System.out.println("    ****** Fields of the Class ******");
            printFields(cl);
           System.out.println();
           System.out.println("    ****** Constructors of the Class ******");
            printConstructors(cl);
           System.out.println();
          System.out.println("    ****** Methods of the Class ******");
            printMethods(cl);
           System.out.println("}");
     }
     catch(ClassNotFoundException e)
      {
              e.printStackTrace();
     }
   }
   
/* print all fields in the class
   @param cl a class
*/
     public static void printFields(Class cl)
     {
               Field[] fields = cl.getDeclaredFields();
     
               for(Field f : fields)
              {
                       Class type = f.getType();
                       String name = f.getName();
                       System.out.print("    " + Modifier.toString(f.getModifiers()));
                        System.out.println(" " + type.getName() + " " + name + ";");
                      // print all the annotations in the field
                       Annotation[] annote = f.getDeclaredAnnotations();
                        for(int i = 0; i < annote.length; i++)
                       {
                                 System.out.println("    // " + annote[i].toString());
                       }
                }
      }
    
/* print all constructors in the class
   @param cl a class
*/
    public static void printConstructors(Class cl)
     {
                 Constructor[] constructors = cl.getDeclaredConstructors();
     
               for(Constructor c : constructors)
               {
                        String name = c.getName();
                        System.out.print("    " + Modifier.toString(c.getModifiers()));
                        System.out.print(" " + name + "(");
       
                        // print parameter types
                        Class[] paramTypes = c.getParameterTypes();
                        for(int j = 0; j < paramTypes.length; j++)
                        {
                                 if(j > 0)
                                         System.out.print(", ");
                                 System.out.print(paramTypes[j].getName());
                         }
                        System.out.print(")");
                        // print the Exceptions in the constructor
                         Class[] ex = c.getExceptionTypes();
                        if(ex.length == 0)
                                      System.out.println(";");
                         else
                       {
                                   System.out.print(" throws ");
                                   for(int j = 0; j < ex.length; j++)
                                  {
                                               if(j > 0)
                                                         System.out.print(", ");
                                                System.out.print(ex[j].getName());
                                 }
                                  System.out.println(";");
                       }
                       // print all the annotations in the constructor
                      Annotation[] annote = c.getDeclaredAnnotations();
                        for(int i = 0; i < annote.length; i++)
                       {
                               System.out.println("    // " + annote[i].toString());
                       }
                 }
     }
    
/* print all methods in the class
   @param cl a class
*/
      public static void printMethods(Class cl)
      {
                Method[] methods = cl.getDeclaredMethods();
      
                for(Method m : methods)
               {
                         Class retType = m.getReturnType();
                         String name = m.getName();
       
                       // print modifiers, return value and method name
                        System.out.print("    " + Modifier.toString(m.getModifiers()));
                        System.out.print(" " + retType.getName() + " " + name + "(");
       
                       // print parameter types
                       Class[] paramTypes = m.getParameterTypes();
                        for(int j = 0; j < paramTypes.length; j++)
                       {
                               if(j > 0)
                                        System.out.print(", ");
                               System.out.print(paramTypes[j].getName());
                     }
                       System.out.print(")");
                      // print the Exceptions in the method
                       Class[] ex = m.getExceptionTypes();
                      if(ex.length == 0)
                                     System.out.println(";");
                        else
                     {
                                   System.out.print(" throws ");
                                   for(int j = 0; j < ex.length; j++)
                                  {
                                            if(j > 0)
                                                      System.out.print(", ");
                                            System.out.print(ex[j].getName());
                                    }
                                     System.out.println(";");
                     }
                    // print all the annotations in the method
                     Annotation[] annote = m.getDeclaredAnnotations();
                      for(int i = 0; i < annote.length; i++)
                   {
                              System.out.println("    // " + annote[i].toString());
                     }
             }
      }
}  

 
2008-11-18 15:34

刚开始学习ss7,看了IEC的在线免费文档(http://www.iec.org/online/tutorials/ss7/index.asp)(向入门ss7的强烈推荐,英文不难,最重要的是文档最后还有20道课后题,附带答案,可以自我检测一下)而比较全面的介绍请参考cisco出版的Signaling System No. 7 (SS7/C7) - Protocol, Architecture and Services (Full Book) (免费在线网址http://www.ss7-training.net/)最后转贴一篇比较OSISS7的一篇文章(http://www.kenneyjacob.com/2007/06/05/ss7-backbone-of-mobile-networks/):

SS7, the backbone of mobile networks. It is the protocol and makes mobile telephony work. SS7 is the protocol that makes communication between network entities possible. SS7 network structure is very much similar to the TCP/IP network structure. As you can see from the picture protocol is also derived from OSI model and has got all the 7 different layers.

In TCP/IP you have Ethernet card as your hardware and in SS7 you have SS7 signalling cards. For TCP/IP you have IP addresses that gives a logical structure to the network. In you have point codes.

All the network elements like HLR, VLR, MSC, SMSC etc are connected to the network and has got point codes assigned to them. Its almost like having a database server, a web server, an ftp server etc connected to the internet.

You can create your own SMSC, MSC, VLR, HLR or any SS7 network element by using an signalling card and writing the appropriate software for it. Its like using TCP/IP to create your own web server or FTP server.

 
2008-11-14 20:53

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/sampled-overview.html

文件格式(File Formats

文件格式描绘了声音文件的结构,不仅包括了文件中原始音频数据的格式,也包括了可以存储进文件的其他信息。声音文件有多种格式,像WAVE(也称为WAV,通常在PC上常见)、AIFF(通常在Mac机器上)、AU(通常在UNIX系统上)。不同的声音文件类型有着不同的结构。例如,可能对文件“头部里的数据有不同的排放。头部包含了在文件实际音频采样之前的描述性信息。也有一些文件格式允许包含有描述性信息和音频数据的连续“块”(chunks)。头部包含了对数据格式的详细描述,数据格式说明了在声音文件中音频的存储方式。任何一种声音文件类型(file types)都可以包含多种数据格式(data formats)(虽然通常在一个给定文件里只有一种数据格式),而某些数据格式可以应用在具有不同文件格式的文件中。

Java Sound API中,一个文件格式有一个AudioFileFormat对象表示,包含有:

l         文件类型(file types)(WAVAIFF,等等)

l         文件的字节长度

l         文件中音频数据的长度(用帧来衡量)

l         一个AudioFormat对象,描绘了文件中音频数据的数据格式

AudioSystem类提供了在不同文件格式中读取写入的方法,和在不同数据格式中转换的方法。其中一些方法可以让你通过一种叫做的AudioInputStream流来访问一个文件的内容。AudioInputStreamInputStream类的子类,InputStream类把一系列字节封装来提供连续读取。相对于其父类,AudioInputStream类增加了对音频数据格式字节的深入(由一个AudioFormat对象来表示)。通过把一个声音文件当作AudioInputStream来读取,你可以直接访问采样点,而不需要区关心声音文件的结构(头部信息,块,等等)一个单一方法调用就可以给你所需要的关于数据格式和文件类型的所有信息。

什么是混频器(mixer)?

许多针对声音的应用程序编程接口(APIs)都使用音频设备(device)这个概念。所谓设备通常是一个物理输入/输出设备的软件接口。例如,一个声音输入设备可能代表一个声卡的输入功能,包括了一个麦克风输入、一个线路电平(line-level)模拟输入、或者可能会有一个数字音频输入。

Java Sound API中,设备由Mixer对象来表示,混频器的作用是处理一个或多个音频输入流和一个或多个音频输出流。在典型应用中,混频器实际上把多路输入流混成一个输出流。一个Mixer对象代表了物理设备的混频能力,像一个声卡可能会把从电脑上的各种输入混音,或者把来自应用程序并且需要输出的声音混音。

另一方面,一个Mixer对象也可以单边一个没有继承任何物理设备接口,完全由软件来实现的设备的声音混频功能。

Java Sound API中,像麦克风输入或者声卡等组件自身不被当作是设备,即不被当作是混频器(mixer),而是被当作混频器的输入或者输出端口(port)。一个端口通常提供混频器输入或输出的一个流(流可以多信道(multichannel),像立体声(stero))。混频器可以有多个端口。例如,代表一个声卡输出功能的混频器可能把多个音频流混在一起,然后把该混合信号送到连接该混频器的某个或这所有输出端口。这些输出端口可以是(举例)一个耳机插孔(headphone jack)、一个内置喇叭、或者一个线路级(line-level)输出。

理解Java Sound API中混频器的概念可以帮助我们视觉化一个真正的物理混频器控制台,像在现场音乐会和录音工作室里用的那些混频器。

一个物理混频控制台

一个物理混频器有许多的“路”(strips or slices),每一路代表一个音频信号进入混频器进行处理的路径。每一路有许多旋钮和其他可以控制该路信号音量和缩放(pan)(在立体图像stereo image中应用)(Panning解释:Panning is the spread of a monaural signal in a stereo or multi-channel sound field. A typical pan control is constant power. At one extreme, the sound appears in only one channel. In the middle, the sound is decreased in that channel by 3 dB, and the other channel is brought up to the same level, so that the overall sound power level is always constant.[1]――wikipedia)。混频器也有一条控制声音效果的总线,像混响(reverb),该总线可以连接到内置或者外置的混响单元。每条线路都有一个电压计来控制该条线路信号进入混响混合(reverbertated mix)的量。然后已混响混合(湿的“wet”)和来自线路“干的“(dry)信号进行混合。最后混频器把最终的混合信号发送到输出总线,通常是发送到录音器(或者是硬盘上的录音系统)或者是扬声器。

设想一个正在用立体声录音的现场音乐会。从许多麦克风连出来的电线(或者是无线连接)和台上的电子乐器都被接入混音控制台的输入端口。每一路输入都进入一条独立的strip中,如上所述。音响工程师决定了增益(gain),缩放(pan),和混响(reverb)的控制设置。所有strips和混响单元的输出被混合在一起进入2个声道。这2个声道直通混频器的2个输出,进入音乐会立体声录音器的输入。或者该2个声道通过放大器接到大厅的扬声器,这取决于音乐的类型和演奏厅的大小。

再设想一个录音工作室。在这里,每一种乐器或者人声被多轨录音机(multitrack tape recorder)录制到独立的轨道(track)上。在所有乐器和人声录音完成后,录音工程师开始“mixdown”来把录制的所有轨道的声音混合成一个2声道(立体声)录音,这种录音就是CD格式。在这种情况下,混频器的各路strip输入不在是一个麦克风,而是多轨录音中的一轨。同样,工程师可以使用strips上的控制按钮来决定每轨的音量(volume)、缩放(pan)、和混响(reverb)量。混频器的输出再次接入一个立体声录音机和一个立体声扬声器,与现场音乐会的例子差不多。

以上2个例子描绘了2种不同的使用混频器的情况:捕捉多输入声道信号,混合为较少的轨,保存混合声音,或者回放多轨录音的同时进行混频至较少的音轨。

Java Sound API种,一个混频器同样可以用来处理输入(捕捉音频)和输出(回放音频)。在输入的情况下,从混频器得到的要混频的音频源(source)是一个或多个端口(ports)。混频器把捕捉到的和混合的音频流送至目标(target)输出,目标通常为带有缓冲的对象,而从该对象中应用程序可以取回混频的音频数据。在音频输出的情况下,情况正好反过来。混频器的音频源是含有缓冲的一个或多个对象,而一个或多个应用程序可以把各自的音频数据写入到这些对象中;而混频器的目标输出将是一个或多个输出端口。

 
2008-11-08 18:39

http://www.manfengmusic.com/download/Kotaro%20Oshio_Wings%20you_are_the_hero.wma一首不错的原声吉他。感觉过了好久,似乎是等待把时间拉长。嘴上的口子从来没有停止微笑,眼疾又犯了,很久没抽烟了,也很久没有喝酒、没有回家。总想拽住时间的衣角,让她慢点,让我静静的看看我的身旁。

XPH和她的姐姐在陶宝开店了http://shop36616078.taobao.com/主营非违法非男性物品。恭喜她们,我像她们一样期待着月收入2W。话说这个店名一开始叫麦麦- -!在陶宝一搜有257个,然后被改名为夏朵-12个。然后XPH询问我的意见,咱2话不说直接来了一个红烧肉,经陶宝一搜只有一个!遗憾未被采用。经过几百脑细胞的over,咱提出了爱吃五花肉的兔子(成熟版),并针对成熟版提出了卡哇依版-爱吃五花肉的兔兔!总是钦佩自己的智商,可惜世间良缘每多波折.......

混沌告诉我们不要相信24小时之后的天气预报,那是扯淡。可总要抓住点什么。等待五花肉的兔子是幸福的,等待胡萝卜的兔子是正常的,等待!@#$%^&*的兔子.......好吧,也是正常的......

 
2008-11-08 15:14

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/sampled-overview.html

Sampled包综述

javax.sound.sampled包主要关注于音频传输,另一方面,Java Sound API关注于回放和捕捉。Java Sound API要处理的核心任务是如何吧某种格式的音频文件输入和输出系统。该核心任务包括打开输入和输出设备、管理充满实时(real-time)声音数据的缓冲区,也可以包括把多种音频流进行混频成一种流(无论是输入还是输出)。当用户需要对声音流进行播放、暂停、继续、或者停止时,声音输入或输出系统的传输问题需要正确处理。

为了支持基本音频的输入和输出,Java Sound API提供了各种方法,包括在多种音频数据格式间转换、读取和写入常用声音格式文件。但是API并不是一个易于理解和使用的针对所有音乐文件的工具包。针对Java Sound API的某种具体实现不需要支持某些额外的文件集或者数据格式转换。第三方服务提供者可以提供“插件”给现有的系统来实现支持额外的文件和格式转换。

Java Sound API可以处理流化缓存形式(streamingbuffered fashion)和内存的非缓存形式(in-memoryunbuffered fashion)的音频传输。本文的“流化”(streaming)主要是指对某种音频格式的实时处理。用另一句话说,一个音频流是差不多以相同速度到达的一段连续的将被处理(播放、录制等等)的音频字节。在所有数据到达之前,已经开始对这些音频字节进行处理。在流体模型中,特别是在音频输入而不是音频输出的情况下,你不必提前知道声音有多长或者数据是否完全到达。你只需要一次处理一个缓存区的音频数据,除非操所别终止。在音频输出的情况下(回放),如果你需要播放的声音数据太大,不能一次装入内存中,你仍然需要缓冲数据。用另一句话说,你把你的音频字节用块的形式传输个音频机器,由音频机器来关注准确的播放每一个采样。这种机制可以很容易确定每个块中有多少数据。

仅仅在回放的情况下,Java Sound API也允许非缓冲传输,前提是你已经把要处理的数据全部准备好而且这些数据可以一次在内存中放下。在这种情况下,不再需要应用程序来缓冲音频,虽然仍然可以使用缓冲的实时方法。用另一句话说,整个声音能一次提前载入内存来进行连续回放。因为所有声音被提前载入,回放可以立即开始,例如从用户按下开始按钮的一瞬间。相对于缓冲模型的回放需要等待缓冲区的第一次装满,上述的特性是非缓冲模型的一个优点。另外,内存缓冲模型轻易的使声音循环(loopcycled)或者从数据的某个任意特定位置来进行播放。

Java Sound API来进行播放和捕捉声音,你至少需要3样东西:格式化音频数据(formatted audio data)、一个混频器(mixer)、一条线路(line)。下面将综述这些概念。

什么是格式化音频数据(formatted audio data)?

格式化音频数据指任一种标准格式的声音。Java Sound API主要区分数据格式(data formats)和文件格式(file formats)。

数据格式(data formats

数据格式规定了如何解释原始”(raw)采样音频数据的一系列字节。原始采样音频数据包括从一个声音文件读取的数据、从麦克风输入捕捉的采样。例如,你可能需要知道一个采样由多少个位(bit)组成(声音最小单元的表示),或者你也需要知道声音的采样频率(每2个采样点之间的时间间隔)。当设置回放或捕捉时,你必须描述你要播放或捕捉的声音的数据格式。

Java Sound API中,数据格式由AudioFormat对象来表示,包括了以下几个属性:

l         编码技术,通常是脉冲编码调制(PCM

l         信道的数量(1代表单声道(mono),2代表立体声(stero)等等)

l         采样频率(每秒每个信道的采样点数)

l         每个采样点的比特数(每信道)

l         帧速率

l         帧的字节大小

l         字节顺序(大端(big-endian)还是小段(little-endian))

PCM是一种声音波形编码技术。Java Sound API包括2PCM编码:使用幅度线性量化(liner quantization of amplitude)和有符号或无符号整数值(signed or unsigned integer value)。线性量化意味着每个采样点存储的数值与该时刻原始声音的强度直接成比例(不包括噪声的影响),同样也与该时刻扬声器和耳膜的振动成相似的比例。例如,CD使用线性PCM编码音频。Mu-law编码和a-law编码是常用的非线性编码技术,这两种技术都提供了对音频数据的高压缩版本,主要用在电话技术和语音记录里。非线性编码通过非线性函数把原始声音幅度映射为一个存储的值,而该非线性被设计成相对与强信号可以提供给弱信号更多的幅度表示。

一个帧包含了一个特定时间所有信道所包含的数据。对于PCM编码的数据,帧就是所有信道里某个时间同步采样的集合,没有其他任何附加信息。在这种情况下,帧的速率相当于采样频率,而帧的字节长度相当与信道的数量乘以每个采样点的比特数除以一个字节所包含的比特数(8)。

对于其他的编码技术,一个帧可能包含除了采样点外的其他信息,而帧的速率可能与采样频率完全不同。例如,MP3编码技术(MPEG1 Audio Layer 3),虽然在现在的Java Sound API版本中没有提及,但是可以被Java Sound API的实现或者第三方服务提供者来支持。在MP3里,每一个帧包含一系列采样点的一捆压缩数据,而不仅仅是每个信道一个采样点。因为每一个帧都封装了一整段采样点,所以帧的速率比采样速率要慢。MP3帧还包含帧头(header)。除了头部,MP3帧的字节长度比包含相同采样点信息的PCM帧(不止一个帧)的字节长度要短。(毕竟,MP3的目的是取得比PCM数据压缩率更高的数据)对于MP3这种编码,其采样频率和采样点大小将参考PCM数据,即在被传输进入数模转换器(DAC)之前,编码数据实际上要先被转换为PCM数据。

 
2008-11-08 10:57

原文地址http://egust.spaces.live.com/blog/cns!98563909D0913C04!218.entry

逆波兰表达式又称后缀式,是波兰逻辑学家J.Lukasiewicz于1929提出的一种后缀表达运算式的方法。区别于我们所熟悉的中缀式,后缀式的特点就是运算量在前,运算符在后,如a+b表达为ab+。这种后缀表达式非常方便去掉运算符优先级的影响与括号,甚至是单目运算符:

1. a*b+c*(d+e) => ab*cde+*+
2. -a+-b*+c => a!b!c#*+ (注:为区别与减法运算与加法运算,这里用!表示负号,#表示正号)
那么计算机怎样通过后缀式来进行运算呢?这里首先假设读取分析表达式的准备工作都已经做好了,那么首先需要做的是把表达式转换成后缀式,也就是逆波兰表达式的构建过程。
构建器由两个主要组件组成,一个是目标表达式的存储器,另一个是一个符号栈。与源表达式的扫描顺序一样,存储器是从左向右储存数据的,而符号栈则遵守后进先出的原则:
* 读入一个数据
1. 如果是单目运算符,直接入符号栈;
2. 如果是运输量,则直接写入存储器;检查符号栈顶是否有单目运算符,有的话则全部出栈,并写入存储器;
3. 如果是左括号"(",则直接入符号栈;
4. 如果是右括号")",则弹出符号栈数据,写入存储器,直到左括号弹出;
5. 如果是普通运算符,则与栈顶符号比较优先级,弱大于栈顶优先级,则入栈;否则弹出栈顶符号并写入存储器,直到栈顶符号的运算优先级较小为止;
6. 如果是结束符(表示表达式已全部读完),则符号栈全部弹出并写入存储器,否则读取数据进入下个过程。
此外还有一些处理的技巧,比如定义一个优先级最低的运算符作为表达式结束的标志,在符号栈里首先加入一个结束标志,那么表达式读完时则自动弹出栈中所有符号,并写入存储器结尾表示成功。
下面用一个表格表示构建的过程:
Token Expression Dest Data LIFO stack Description
a*b+c*(d+-e)# # # is Ending Sign
a *b+c*(d+-e)# a # Value -> Data
* b+c*(d+-e)# a #* * > #
b +c*(d+-e)# ab #* Value -> Data
+ c*(d+-e)# ab* # + < *
c*(d+-e)# ab* #+ + > #
c *(d+-e)# ab*c #+ Value -> Data
* (d+-e)# ab*c #+* * > +
( d+-e)# ab*c #+* LPar( -> Stack
d +-e)# ab*cd #+*( Value -> Data
+ -e)# ab*cd #+*(+ + > (
! e)# ab*cd #+*(+! ! -> Stack
e )# ab*cde! #+*(+ Value -> Data, Pop !
) # ab*cde!+ #+* RPar) -> Pop Until (
# ab*cde!+*+# # -> Pop Until #
接下来是计算的过程。计算的时候除了刚才构建的数据外,还需要另外一个数据栈。首先是从左至右扫描数据段,如果读出的是数据则压入数据栈,遇到符号时从数据栈中弹出相应的数据进行运算,再把结果压回数据栈。依然拿上面的结果做表格列示:
Token Expression Data Stack Compute Description
ab*cde!+*+#
a b*cde!+*+# a Value -> Stack
b *cde!+*+# ab Value -> Stack
* cde!+*+# a*b Pop a, b
cde!+*+# m set m = a*b
c de!+*+# mc Value -> Stack
d e!+*+# mcd Value -> Stack
e !+*+# mcde Value -> Stack
! +*+# mcd !e Pop e
+*+# mcdn set n = !e
+ *+# mc d+n Pop d, n
*+# mco set o = c+n
* +# m c*o Pop c, o
+# mp set p = c*o
+ # m+p Pop m, p
# r set r = m+p
# r check Accept!
这样,返回结果就是栈中唯一的数据,我们完成了逆波兰表达式的全部计算过程。
此外还要注意处理的一些过程中的问题包括:
构建时,保存上次的数据类型,在得到数据时与上次数据进行对比,例如当读入运算量时如果上次数据也是运算量就出错了,例如这样的表达式“a b+”如果不注意处理的话则会“合法 ”压入数据栈并得到运算结果。
计算时,要注意检查数据栈中的数据数量,如果数量不对则中断计算过程并报错。
 
2008-11-05 18:32

(1)创建jar包
   jar cf hello.jar hello   利用test目录生成hello.jar包,如hello.jar存在,则覆盖

(2)创建并显示打包过程
jar cvf hello.jar hello     利用hello目录创建hello.jar包,并显示创建过程
例:E:\\>jar cvf hello.jar hello
标明清单(manifest)
增加:hello/(读入= 0) (写出= 0)(存储了 0%)
增加:hello/TestServlet2.class(读入= 1497) (写出= 818)(压缩了 45%)
增加:hello/HelloServlet.class(读入= 1344) (写出= 736)(压缩了 45%)
增加:hello/TestServlet1.class(读入= 2037) (写出= 1118)(压缩了 45%)

(3)显示jar包
jar tvf hello.jar   查看hello.jar包的内容
指定的jar包必须真实存在,否则会发生FileNoutFoundException。

(4)解压jar包
jar xvf hello.jar   解压hello.jar至当前目录

(5)jar中添加文件
jar uf hello.jar HelloWorld.java     将HelloWorld.java添加到hello.jar包中

(6)创建不压缩内容jar包
jar cvf0 hello.jar *.class      利用当前目录中所有的.class文件生成一个不压缩jar包

(7)创建带manifest.mf文件的jar包
jar cvfm hello.jar manifest.mf hello
创建的jar包多了一个META-INF目录,META-INF止录下多了一个manifest.mf文件,至于manifest.mf的作用,后面会提到.

(8)忽略manifest.mf文件
jar cvfM hello.jar hello    生成的jar包中不包括META-INF目录及manifest.mf文件

(9)加-C应用
jar cvfm hello.jar mymanifest.mf -C hello/
表示在切换到hello目录下然后再执行jar命令

(10)-i为jar文件生成索引列表
当一个jar包中的内容很好的时候,你可以给它生成一个索引文件,这样看起来很省事。
jar i hello.jar     执行完这条命令后,它会在hello.jar包的META-INF文件夹下生成一个名为INDEX.LIST的索引文件,它会生成一个列表,最上边为jar包名。

(11)导出解压列表
jar tvf hello.jar >hello.txt   如果你想查看解压一个jar的详细过程,而这个jar包又很大,屏幕信息会一闪而过,这时你可以把列表输出到一个文件中,慢慢欣赏!

(12)jar -cvf hello.jar hello/*
   例如原目录结构如下:
   hello
     |---com
     |---org

你本想只把com目录和org目录打包,而这时jar命令会连同hello目洋也一块打包进。这点大家要注意。jar命令生成的压缩文件会包含它后边出的目录。我们应该进入到hello目录再执行jar命令。 注意:manifest.mf这个文件名,用户可以任指定,但jar命令只认识Manifest.mf,它会对用户指定的文件名进行相应在的转换,这不需用户担心。

 
2008-11-05 17:03

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/index.html

什么是MIDI

javax.sound.midi包包含传输和序列化MIDI事件的APIs,及从以上事件合成的APIs

相对于采样音频是其声音自身的一种直接描述,MIDI数据可以被认为是产生声音,特别是乐器声音的方法。MIDI数据,不像音频数据,不对声音进行直接描述。相反,MIDI数据描绘的是事件(events),这些事件影响了由支持MIDI的设备或乐器(像合成器)所产生的声音(或者动作)。MIDI数据与一个图形用户接口键盘或者鼠标事件相似。在MIDI里,事件可以被理解为对音乐键盘的各种动作,包括对该乐器设备上踏板的踩踏(pedal)、弦的滑动、开关打开关闭、按钮的旋转。这些事件不必需要相应的硬件设备来相应;他们可以有软件来模拟然后被存储在MIDI文件里。一个能创建、编辑、播放上述文件的程序称为序列器(sequencer)。许多电脑声卡包含MIDI控制音乐合成器芯片,而序列器将把MIDI事件发送给这些芯片。合成器也可以由软件完全实现。合成器解释他们收到的MIDI事件并产生音频输出。通常从MIDI数据中合成的声音是乐器声音(例如相对于语音信号)。MIDI合成器也能产生各种声音效果。

某些声卡包含MIDI输入和输出端口,通过这些端口外部的MIDI硬件设备可以连接(像键盘合成器或其他乐器)。从一个MIDI输入端口,一个应用程序可以接受外部MIDI音乐设备产生的事件。该程序可能用电脑内部的合成器来播放该乐器的演奏、把该事件保存为MIDI文件放在磁盘上、或者作为音乐注释文件来传递。一个应用程序可能会实用一个MIDI输出端口来播放外部乐器,或者控制其他外部设备,像录音设备。

下图描绘了基于Java Sound API下,某个可能的MIDI配置中,各个主要组件的功能关系。(与音频相似,Java Sound API允许不同的MIDI软件设备安装和连接,该图所示的系统仅仅是一个假想情景。)箭头表示了组件之间数据的流向。数据可以来自一个标准文件格式、或者(由右下角的key图所标识),来自音频、原始MIDI字节、或者时间标记的MIDI信息。

一个可能的MIDI配置

在该例中,应用程序通过加载存储在硬盘上的标准MIDI文件作为一个音乐记录来准备该乐器演奏(图左处)。标准MIDI文件包含了多轨(track),每一轨是一个时间标记MIDI事件的列表。大部分事件代表这乐曲的注释(调子和节奏)。该MIDI文件被读取,然后被软件序列器所“演奏”。序列器通过发送MIDI信息给其他设备来演奏曲目,像内部或外部的合成器。合成器自己可能会读取一个包含仿真某种乐器音色指令的音色库(soundbank)文件。如果没有读取,合成器将用任意已加载的音色指令来播放MIDI文件中的乐曲注释。

如上所述,MIDI事件在被送到MIDI输出端口的外部MIDI乐器之前必须转化为原始(非时间标记)MIDI。同样,从外部MIDI源(如图中的一个键盘乐器)进入电脑的原始MIDI数据必须被转化为时间标记MIDI信息,该信息进而能控制合成器,或者被序列器存储以背后用。

服务提供者接口(Service Provider Interfaces

javax.sound.sampled.spijavax.sound.midi.spi包包含了让软件开发者创建信音频或者MIDI源的APIs,而这些新的音频和MIDI源可以作为一个已存在的Java Sound API实现的“插件”(plugged in)而被单独提供。这里有一些添加服务(源)途径的例子:

l         一个音频混频器

l         一个MIDI合成器

l         一个能读取或写如一种新的音频格式文件或者MIDI文件的文件分析器

l         一个能转换不同声音数据格式的转换器

在某些情况下,服务是软件接口针对硬件设备功能的,像声卡,所以服务的提供者可能就是硬件设备厂商。在另外一些情况下, 服务纯粹以软件存在。例如,一个合成器或者混频器可以是针对声卡上芯片的接口,或者不依赖任何硬件支持来实现。

一个Java Sound API实现包含了基本服务集,然而SPI包允许第三方来创建新的服务。这些第三方的服务像内置服务一样被集成进系统。AudioSystem类和MidiSystem类扮演协调者的角色,使应用程序能显式或隐式的访问服务。通常现存的服务对于实用他们的应用程序来时是完全透明的。这种服务提供机制为建立基于Java Sound API的应用程序开发者提供益处,因为新的特性可以被加入到程序而不需要一个新版本的JDK或者JRE,而且,在多数情况下,甚至不需要重新编译该应用程序本身。

 
2008-11-05 16:51

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/index.html

Sound开始

Java Sound API是一种低级的API,用来处理和控制声音媒体的输入和输出。声音媒体包括了音频数据和乐器数字化接口数据(MIDI)。Java Sound API针对声音输入和输出通常所要求的性能提供了显式控制,并提供了一种提高扩展性和灵活性的框架。

Java Sound API实现了应用程序开发者的广泛需求。可能的应用程序领域包括:

l         通信架构程序,例如会议和电话技术

l         最终用户数据传递系统,例如媒体播放器和使用流格式的音乐

l         互动性的应用程序,例如游戏和使用动态内容的网站

l         数据流创造和编辑

l         开发工具,工具包,和实用程序

Java Sound API提供Java平台下最底层的声音支持,它提供应用程序大量针对声音操作的控制,并且这都是可以扩展的。例如,Java Sound API提供安装、访问、和操控系统资源的各种机制,像音频混频器(mixer)、MIDI合成器(synthesizer),或者其他的音频和MIDI设备、文件读取器(reader)、文件写入器(writer)、声音格式转换器(converter)。Java Sound API不包括复杂的声音编辑器或者图形化工具,但是它提供了建立这些应用的能力。Java Sound API强调的是大部分最终用户都所期望的对声音的底层控制。

Java Sound API包括了对数字音频和MIDI数据的支持。这2个主要模块的功能在以下独立的包内:

l         javax.sound.sampled

该包详细描绘了对数字(采样)音频的捕捉(capture)、混音(mixing),回放(playback)的各种接口。

l         javax.sound.midi

该包提供了MIDI合成(synthesis),序列化(sequencing),事件传输(event transport)等接口。

另外2个包允许服务提供者(service providers)(与应用程序开发者相对而言)创建自定义的软件组件,来扩展某种Java Sound API具体实现的功能:

l         javax.sound.sampled.spi

l         javax.sound.midi.spi

本页介绍了采样音频系统、MIDI系统,SPI包。每一个包将在后续章节中进行详细介绍。

―――――――――――――――――――――――――――――――――――――――

注意:Java平台的某些APIs也有与声音相关的。Java Media Framework API (JMF)是一种高级API,现在作为Java平台的一种标准扩展。JMF详细描绘了一个统一的架构、消息协议、和捕捉、回放以时间为基准的媒体的编程接口。 JMF提供了一种针对基本媒体播放器应用程序的简单解决方案, 同样也允许不同媒体类型之间的同步,如音频和时频的同步。另一方面,集中于声音处理的程序可以从Java Sound API中获得便利,特别是那些需要更多高级特性的程序,像微调控制缓存音频回放的能力或者直接操控一台MIDI合成器。其他与声音相关的Java APIs包括Java 3D、电话技术和语音的APIs。所有上述的这些与声音相关的APIs的某种实现都可能在其内部用到某个Java Sound API的实现,但这不是必须的。

―――――――――――――――――――――――――――――――――――――――

什么是采样音频?

javax.sound.sampled包处理数字音频数据,这种数据在Java Sound API里即为采样音频。采样是对一个信号的连续快照(snapshots)。对音频而言,信号就是一段声波。麦克风把原始的信号转化为相关的模拟电信号,然后AD转换器把该模拟信号转化为一种采样的数字信号。下图为声音录制中的一小段时间。

一段采样的音频波形

该图在纵轴上画出了声波的幅度,水平轴为时间。该模拟声波的幅度在某个频率下等间隔的被测量,最后形成的离散采样点(图中的红色数据点)组成了数字音频信号。图中中间的水平线代表幅度为0;线上的点为正值采样点,线下的为负值。数字信号逼近某个模拟信号的精度取决于其在时间上的分辨率(采样频率)和其量化标准(幅度上的分辨率,每个采样点用几位数字来表示)。作为一个例子,CD上存储的音频数据是每秒采样44100个点、用16位的数字来表示每个采样点的数值。

“采样音频”(sampled audio)这个术语在这里比较宽泛。一个声波可以按照一个离散间隔来采样但仍然保留其模拟信号的形式。然而在Java Sound API里,“采样音频”的意思就是“数字音频”(digital audio)。

特别需要注意的是,电脑上的采样音频来自于声音录制,但是相应的声音也可以由各种其他声音信号合成的(例如合成一个拨号电话的声音)。“采样音频”在这儿指的就是这种合成性的声音,而不是原始的声音信号。

Java Sound API并不针对某种音频硬件配置;它被设计成允许不同音频组件安装在系统上并且都可以被API访问。Java Sound API支持常用的功能,像声卡的输入和输出(例如声音文件的录制和回放)及多种音频流的混响。下图是典型音频系统架构示意图:

  

一个典型音频系统架构

在这个图中,像声卡这种设备有许多的输入和输出端口,而混响则由软件提供。混频器可能通过读取一个文件、网络上的流,应用程序产生的数据、及MIDI合成器产生的文件来接收数据。混频器把音频输入的各种信号组合成一个单一的流,该流可以被送到输出设备进行输出。

 
   
 
 
文章存档
 
     
 
最新文章评论
  

x=-pi:0.05:pi; plot(x,sin(x)*cos(x),'o');
 

请大神指教
 

m=1:255; k=-500:500; w=(pi/500)*k; R=k/500; r0=0.9141; r2=r(257:511); X=r2*cos(
 

 

>> a=[2,3,-1;8,2,3;45,3,9]; >> b=[2,4,23]; >> x=inv(a)*b Error using * Inner ma
   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu