20111031

pics

.

当你说不行时,你应该说些什么:以Android播放midi为例

中国好几年前都对能对美国说"不",软件工程师也经常要对用户和同事说"不"。但是别人经常还要在你说不以后继续喋喋不休,为什么呢?
据说男生说不的时候,就是不的意思;据说女生说不的时候,是请再继续表现的意思。这坑害了很多猥琐男。因为,只有她希望你继续表现的时候,那时"不"的意思才是请继续表现,否则,"不"的意思就是"不"。一些女生假设对方能够理解这一显然的事实:即,你是否是被欢迎继续表现的。
而这个世界上没有显然的事情。继续表现的,多是猥琐男,被希望继续表现的,通常很快就引退了。
关于如何说是,咱们今天不讨论;今天单讨论一下如何明确地说不。
会发生上述误会,盖因东方民族隐晦含蓄的表达方式传统。看过一个日本片子。某个提了个什么主意,女主角坐在那里,低头着头,很坚毅地说:"虽说很好。"
你不要以为还有下文,她说到这里就戛然而止了。日本人就是这样说话的。她发出的声音是"虽说很好",但实际想传达的是后面所有没说的内容。
在工程中,用户和同事也经常会误解。那么如何准确地传达"不"的信息呢?
1. 对用户
这个简单。
除了告诉他不以外,还要告诉他 技术上完全可以,但是...然后开始罗列代价:时间(工期)、经费等等。
然后他就自动引退了。这在女生说不的场景中,类似于,女生说完不以后,再补充,"其实呢,也不是不行,但是需要加些条件。我想要的很简单:一座大大的露台,上面有个秋千……"
明确的回绝,就是 不行 + 你不具备"行"的理由。
2. 对同事
明确告诉同事,尤其是分配给你任务的那个人,"你的想法很猪头" 的方法是,告诉他,他的想法不可行的原因。
并且,为了交流简洁起见,把他所有可能的提问,所有可能修正的主意都罗列出来,然后一一否定。写文档或报告的时候,不要期待交互,不要期待他问你答,用答案堵住他所有可能下嘴的地方。
不恃敌所不攻也,恃吾有以待也。
以下是一个实例故事。这也我们为什么要训练写实验报告的原因,它记录了过程和数据,以此支持你的看法。没有人会像科幻电影里的总统啥的那样,因为你琼瑶般喊"你们相信我吧,地球真的要毁灭啦"就相信你。
我们应该做的是:告诉小伙不行,然后对他淡定地笑笑,然后准确清晰完整地说出他不行的原因。
背景:
我请牛同学做Android下的一个程序原理,播放音乐合弦,比如大三度。意思是,同时把do,re,mi的声音发出来。
技术方案之一是用PCM混音,之二是在MIDI中同时播放这几个音。牛同学分别试了。
牛同学试了一段时间以后,说终于找到一个生成midi文件的方法。
我提出新的要求,不要把midi文件写到文件系统(internal
storage)中,而是用java的stream,在内存(RAM)中直接发给MediaPlayer播放。
牛同学说:不行。
故事开始了。
你说不行,我当然不能因为是你说的,然后就信了。要有事实。
所以牛同学发来他的代码,我学习了一段,发现真的不行。然后写了下面这封信。略有修改。
----信的正文由此开始----
下面提到的"应该"是指 建议给你的
报告的写法.有了这些你"应该"提供的资料,我才能了解你研究了哪些必要的方法.这是用以证明你研究的路线是正确的方法.或者换种说法,如果以下报告中的"应该"部分你已经告诉我,我就不必看你的代码了.
1. 你应该提供我MidiFile的出处,以便我参考,因为MidiFile不是你写的,且不是java/android的一部分;
2. 你是否参考了此邮件后面网址的实现?[http://kevinboone.net/javamidi.html]
3. 我提到的不必向文件系统中写出midi文件,原计划的路线是这样的:通过重写 writeToFile
实现,把这个方法中的写到文件系统中转为对Stream赋值,也可以把midi的内容放在 vector<byte>中;
4. 然后设置MediaPlayer.SetDataSource()的参数为这个vector或者Stream.
下面是我寻找解决方案的路线。
4.1 MediaPlayer需要FileDescriptor
[http://developer.android.com/reference/android/media/MediaPlayer.html#pubmethods]MediaPlayer.setDataSource(FileDescriptor
fd)Sets the data source (FileDescriptor) to use.
4.2 FileDescriptor可以由FileInputStream/FileOutputStream建立
[http://developer.android.com/reference/java/io/FileDescriptor.html]It's
possible to get the file descriptor used by some classes (such
asFileInputStream, FileOutputStream, and RandomAccessFile), and
thencreate new streams that point to the same file descriptor.
[http://developer.android.com/reference/java/io/FileOutputStream.html]FileInputStream.getFD()public
final FileDescriptor getFD ()Returns the underlying file descriptor.
4.4 到这里,我的思路走不下去了。因为FileInputStream的构造函数要求存储在FLASH中的文件。
你应该列出以下方法,并说明MediaPlayer没有其他的方法 setDataSource.
void setDataSource(String path)Sets the data source (file-path or
http/rtsp URL) to use.void setDataSource(FileDescriptor fd, long
offset, long length)Sets the data source (FileDescriptor) to use.void
setDataSource(FileDescriptor fd)Sets the data source (FileDescriptor)
to use.void setDataSource(Context context, Uri uri, Map<String,
String> headers)Sets the data source as a content Uri.void
setDataSource(Context context, Uri uri)Sets the data source as a
content Uri.

4.5 然后我开始查是否有其他的办法。因为利用stream而不通过文件系统,这实在应该是个非常通用的方案,android sdk没有理由不支持啊。
[http://developer.android.com/reference/android/content/Context.html#getCacheDir()]讨论了这一问题,播放内存中,而不是flash(internal
storage)中的midi文件。
4.6 下面这个方法我同意[http://code.google.com/p/android/issues/detail?id=739]
: Comment 7 by steveold...@gmail.com, Aug 19, 2008: From the ReadMe
included with 0.9 SDK.: : Unfortunately, the ability to play audio
streams from memory (such as via an : InputStream or Reader) will not
be possible in Android 1.0.  As a workaround, we : recommend that
developers save media content to SD card and use MediaPlayer to play :
from a file URI, or embed a small HTTP server and play from a URI on
localhost (such : as http://127.0.0.1:4242/something
杨注:但是第二天一早,我又意识到这是不行的。因为读http必然要求那个midi文件已经存在了。这与我原计划不希望写入文件系统相违背。
同一贴子有人提到
: Comment 12 by seeingwi...@gmail.com, May 19, 2009: Issue now
resolved with AudioTrack in Android 1.5 (Cupcake)
这是我们以前提到过的方法,在[http://developer.android.com/reference/android/media/AudioTrack.html]
里提到,不过需要PCM作为buffer而不能用midi作为buffer.
正如同一贴子的人回答道:
: Comment 22 by sam.clegg, Sep 13, 2011: Is there really still no
streaming audio support in android?: : AudioTrack doesn't help as it
only works for PCM samples, not encoded files.
4.7 至此,我提出的从stream中写入midi,然后从stream中构造MediaPlayer,这一方案可以得出结论 不行.
我们不能因为谁说不行就认定不行,而只能根据以上的分析.
4.8 我们仍然可以用PCM的方法合成和弦.我建议还是试回这个方法.
杨注:然后第二天一早,我又反悔了,因为PCM的尺寸会比MIDI大很多,这不是我们希望的。
请用MATLAB做这样的试验:
杨注:所以下面的实验我就在此省略了。