Developer support recently released the source for the audio CD player that we ship with the BeOS. Unfortunately, if all you're interested in is how to make driver calls to perform the audio functions, you'll have to pore over a lot of UI fluff code to get to the interesting nuggets. The point of this article is to describe the driver calls available for playing, scanning, and saving CD audio, and to point you to some simple sample code that exercises all the available functions.
With DR9, the BeOS supports both SCSI and ATAPI (IDE) CD drives; both types of devices are serviced by the same set of driver ioctl calls for audio access.
A number of the calls described below use a positioning type called MSF, which stands for minute, second, frame. A minute is 60 seconds (duh), a second is 75 frames, and a frame is one 2352-byte sector, which contains 588 samples of 16-bit stereo audio. I recommend you get either the ANSI SCSI standard or the ATAPI standard for more detailed descriptions of a number of data structures that are used.
Before any audio functions can be performed, a device needs to be
located. To do this, scan the DR9 /dev/mountable
directory and make
B_GET_GEOMETRY
ioctl calls to all the drivers. Test the "device_type"
field against the B_CD
constant. Drivers with the type B_CD
will
support the calls described below.
Now that you have a device and have popped a disc in, you'll probably
want to list the contents of the disc—the SCSI_GET_TOC
call will do
the trick:
ioctl
(device
,SCSI_GET_TOC
, &toc
);
toc
is a pointer to a scsi_toc data structure. This structure is
described in the ANSI SCSI spec
and the ATAPI spec. The structure
contains a four-byte header followed by an eight-byte TOC descriptor for
each track. The header contains the starting and ending track number and
the length of the TOC data. Each TOC descriptor contains the track
number, the starting location for the track (in MSF format), and flags
that you use to determine whether the track contains audio or data
information.
Now that you've located an audio track you'll want to play it; unless, of course, you've popped in a Grateful Dead CD. The simplest way to play a track is to tell the driver to play from a starting track number to an ending track number:
ioctl
(device
,SCSI_PLAY_TRACK
, &track
);
track
is a data structure used to specify the starting and ending track,
along with a starting and ending index (in most cases 1).
To get a bit more control about where to start and end, use the following call:
ioctl
(device
,SCSI_PLAY_POSITION
, &position
);
position
is a data structure that specifies the starting MSF and the
ending MSF.
To pause, resume, and stop audio playback, you use these calls:
ioctl
(device
,SCSI_PAUSE_AUDIO
);ioctl
(device
,SCSI_RESUME_AUDIO
);ioctl
(device
,SCSI_STOP_AUDIO
);
Ejecting a disc is simple and satisfying:
ioctl
(device
,SCSI_EJECT
);
Too soft? Crank it up:
ioctl
(device
,SCSI_GET_VOLUME
, &volume
);ioctl
(device
,SCSI_SET_VOLUME
, &volume
);
volume
is a pointer to a scsi_volume data structure. The data structure
contains a channel and volume field for each port (four ports, maximum).
For each port the volume range is from 0 (muted) to 255. To set the
volume or channel for a particular port, you must also set the change
flag bit for each field (this allows changing individual fields without
affecting the other fields).
To get the current play status and position, use the following call:
ioctl
(device
,SCSI_GET_POSTITION
, &position
);
position
is a pointer to a scsi_position data structure. Once again this
structure is described in detail in the ANSI and
ATAPI specs; briefly, it
contains a flag byte that indicates whether play is in progress, paused,
completed, or "errored" and what are the current track, index, absolute
MSF, and track-relative MSF position.
To scan (fast forward, fast reverse) there is the following call:
ioctl
(device
,SCSI_SCAN
, &scan
);
The scan data structure specifies the direction (+ = forward, - = reverse, and 0 = stop scanning) and the speed (0 = normal scanning, 1 = high-speed scanning) at which to scan. (Not all devices support high-speed scanning.) To stop scanning, you must use the same call again with a direction of 0.
The last command described is the one for reading audio data to memory:
ioctl
(device
,SCSI_READ_CD
, &read
);
The read structure specifies the starting position (in MSF format), length (also in MSF format), buffer_length, buffer address, and a flag indicating whether to play the audio at the same time it's being read (not all devices support this). The format of the data read is 16-bit stereo, left channel followed by right channel. One last point to keep in mind: You'll need to byte-swap the audio data you read from the media before playing it back on the BeOS.
With the recent rerelease of the Star Wars trilogy here in the United States, I find myself once again contemplating life and its reflection in visual media. I am now convinced that Jabba the Hutt was a programmer in his earlier career and chose a path of management.
I see the evidence in myself. When I started programming, oh so many years ago, I was thin, in good shape, and ready to take over the world. As the years roll on, as does my office chair, my bottom line keeps expanding. Unable to move, I delegate. Then along comes the BeOS. Something new and exciting to challenge and thrill. Suddenly I'm jumping up out of my seat and yelling YES!! whenever I can do something that I couldn't do before.
One of my pet programming things is to do graphics. That is, graphics libraries on the sly. It's never been my profession, but it's always been my obsession. When the BeBox™ first hit the streets, I created a thing called the YAGS library. Of course this stands for Yasmin Adams' Graphics System, or for those who are more UNIXY, Yet Another Graphics System. The purpose of YAGS is to support much of the higher level graphics found in the BView class, but to do it on an arbitrary frame buffer. That means the screen, through the Game Kit, or a BBitmap.
To that end, YAGS has primitives to draw lines, ellipses, rectangles, triangles, and bezier curves. I twiddled with 3D a bit, but not enough. I ported it to DR8 and let it languish. So here it is:
ftp://ftp.be.com/pub/contrib/gfx/lib/yags.tgz
There's a simple demo program you can run to see how fast your little machine can really go. You can choose to either use the software-only routines or the Game Kit routines that will use hardware acceleration (if available).
As for some cleanup, last week we put out the vidview package, which allows you to write apps to the Hauppauge video digitizer board. Thanks to Kevin Hendrickson, a long- standing bug has been squashed.
In the vidview.cpp file you would find:
voidVideoView
::WaitForStop
() ..kill
(drawer_id
,SIGINT
);
Change this to:
voidVideoView
::WaitForStop
() ..kill_thread
(drawer_id
);
You'll find that the application closes down more reliably more often. I've made this change to the sample code and added sliders for hue and saturation. You can download the revised package from:
ftp://ftp.be.com/pub/Samples/vidview.tgz
The DR9 man approacheth, and as that inevitable date draws near, we'll all become antsy with anticipation. Font system changes, file system changes, archiving, the Tracker, Unicode. That's a lot of change. What we'll do is to provide all the application samples that we included with DR8, but in a more timely manner. That way everyone will be able to compare new stuff to old stuff and see what's changed. We'll try to get these samples out much sooner than before to help you upgrade.
I may feel like a Hutt at times, but the BeOS is keeping me on my toes and at least exercising my mind—if not my whole body.
The last few days have brought very good news for the net. Older media giants loose oodles of money on their sites, Netcom buys full-page ads to announce a price increase, and Dell chalks up more than a million dollars a day in sales revenue from their Web site.
I'll leave the first item alone: We should be grateful to our well-heeled elders for exploring the new math on our behalf—and on their nickel. And it's nice to see Dell showing both muscle and flexibility in using the new medium, once again cashing in on the benefits of their reputation for good customer service. "Too bad they don't make Mac clones," sighed an unnamed Be wag.
Today, Netcom places large ads congratulating their employees for a great job and proudly announcing a new product. On closer inspection, the new product is a new price structure for all-you-can-eat net connections, with new "Fair Use" guidelines. Netcom, one of the early net access companies in the Valley, is taking the lead in trying to institute classes of service among their customers. As many politically incorrect observers predicted (led by Jack Rickard, the editor-in-chief of Boardwatch magazine), the all-you-can-eat buffet doesn't lead anywhere. It creates perverse reactions among users and ends up frustrating everyone, starting with the people owning shares in the restaurants.
At first the flat rate attracts customers. As the customers grow in numbers, some diseconomies of scale manifest themselves. There are phases in the growth of the system where adding more customers costs more, because some subsystems run out of capacity and grafting on bigger ones sends ripples through the whole thing, including your P/L. On the surface of things, ten subscribers per modem looks like a good number. But beyond a certain number of modems, you need big, expensive iron to aggregate the traffic. Beyond a certain size, the computers themselves have to be jettisoned, and further complications—and costs—occur when they have to be clustered.
Some have equated the problem of flat-rate ISPs to the all- you-can eat restaurant whose owner watches two buses of sumo wrestlers pull in. The metaphor needs a little tweaking. What in fact happens is the number of subscribers per port increases. As a result, quality of service—access when needed, in this case—degrades. Seeing this, customers stay connected once they gain access, whether they need the service or not. Other customers stay at the door. The ISP sees this and disconnects inactive users. The anxious customers get little utilities that fake activity. And so on. Why disconnect if it doesn't cost more and you can't reconnect? That's the vicious circle Netcom and other ISPs are trying to defeat when pledging allegiance to the Fair Use Initiative and trying to move to a tiered pricing system. The Fair Use Initiative addresses many more issues than just "hogging" a connection, but it essentially tries to promote the concept of moderation in a system that discourages it. We'll watch as they, and others, negotiate the transition to a more rational pricing structure. Especially when competitors might try to undercut them, only to raise prices later once they've caused enough concentration.
The rationale invoked for flat pricing is the phone companies' alleged flat costs for long distance. The legend is that AT&T once considered flat pricing. All you can talk for a flat monthly fee. But people would have kept phone lines open for hours. Ask any parent owning or operating a teenager. Metered service is good. It doesn't have to be as greedy as the cellular providers rounding up to the next minute. Just raise the pricing slope a little, and the self- defeating hogging of connections will disappear without making the Internet much more expensive.
BeDevTalk is an unmonitored discussion group in which technical information is shared by Be developers and interested parties. In this column, we summarize some of the active threads, listed by their subject lines as they appear, verbatim, in the mail.
To subscribe to BeDevTalk, visit the mailing list page on our web site: http://www.be.com/aboutbe/mailinglists.html.
More feature requests for DR9. This week: Stability. Is it possible to be absolutely crash-proof? Most folks think not. However, some listeners wrote in to request that the UI (at least) be perfectly safe. Giving the user an "uncrashable" OS is a worthy ideal, but, as Osma Ahvenlampi pointed out...
“If you wanted to make a really secure OS, it would also be a really slow OS... If the OS is stable enough to stay running without a need to reboot it for 30 days on average... it's easily stable enough for most users to never see a crash.”
Just as important as stability is integrity: If an app crashes (or otherwise misbehaves), it shouldn't damage critical files and resources such that the OS crashes or, worse, needs to be reinstalled.
More asynchronous send()
talk:
Is the memcpy()
in an asynchronous send()
implementation cheap
enough that you don't have to worry about it?
If you run up a huge thread bill while multithreading synchronous
send()
calls, will the accumulated stack space be prohibitive?
How do TCP communication and connection errors get reported back
to an asynchronous send()
'er?
A request from Chris Dunphy:
“One UI feature I haven't seen called for yet is mouse blanking. When I start typing, I want the mouse pointer to vanish and get out of my way, only appearing again when I actually touch the mouse.”
A few listeners wrote in to point out that some applications (Edit, in particular) exhibit exactly this behavior. The request was then modified for scope: Can mouse blanking be a system-wide setting? Many votes in favor, but perhaps, thinks Brian Stern, global enforcement is too much:
“It isn't always appropriate to obscure the cursor for every keydown...
All that's missing is a line in the human interface guidelines saying
that this [calling ObscureCursor()
within appropriate apps] is the
right thing to do.”
Will the "file selector" (or "Open panel") be smarter in DR9? In particular, will it support [from Steve Klingsporn and others]...
A "favorite folders" pop-up menu
View mode options (icon, small icon, list mode, and so on)
Special display of the selected file (SK: "You could have an icon showing the selected file in the left corner, or a list view of currently selected files...")
The ability to define and install your own panels
Drag-and-drop into the open panel
Easy Rename (as opposed to clunky Save As)
Howard Shere (and others) proposed a "panel-less" system of saving/opening files, based on the idea that "standard" panels (and this applies to almost all modern GUI OS's) give you a redundant view of the world. Mr. Shere...
“Save: An icon on the title bar of the window... can be dragged to the Tracker to save the file. You can save anywhere in this fashion. Spring loaded folder type action can allow you to drag into any folder in the system without releasing the mouse button. Open could open a small 'drop box' window which documents can be dropped on to open them. Since this would not be modal, this could be opened all the time. It would have to float about all of the windows for this to work.”
An objection to this system (paraphrasing Mike Manzano): The Open/Save panel is compact. When you use the Tracker to look for a file or folder, you get a window for each level of hierarchy. The Open/Save panel is much neater in this respect. Also, relying on the Tracker for these operations can lead to the "obscured target window" effect.
Relatedly, Jon Watte would like notification when a file is dragged to the trash:
“[W]hen a file is dragged to the trash, the application having it open should close the file in question. Right now, there is no good way of finding out when and if a file is in the trash.”
Reaction to Dominic Giampaolo's Newsletter article on good programming practice. It was pointed out that Be's example source apps don't always adhere to the principles Dominic advised, particularly with regard to checking errors.
A few misconceptions were cleared up: It was thought that recycling resource IDs could create race conditions. Dominic pointed out that resource IDs (thread_id, sem_id, and so on) are NOT quickly recycled. The IDs are incremented to the maximum value before the incrementor turns over. After the turnover, moreover, only "free" slots are used.
There was also some thought that resources weren't reclaimed properly. Not so: The structures and address space-specific data that support an app's threads, semaphores, ports, images, teams, and areas ARE reclaimed when the app dies. The actual memory behind a shared area or add-on or library image is reclaimed when all apps that refer to that memory are dead.
BObject is going away in DR9. Is this a shame? There were some tears shed, but not many. Most folks think that mix-ins (and multiple inheritance in general) are a better means of sharing protocol.
Dominic Giampaolo, idraulico di sistema cartellina, published some impressive DR9 file system performance numbers.