home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / drivers / drv_alsa.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  7.0 KB  |  291 lines

  1. /*    MikMod sound library
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  4.     This library is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU Library General Public License as
  6.     published by the Free Software Foundation; either version 2 of
  7.     the License, or (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU Library General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU Library General Public
  15.     License along with this library; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: drv_alsa.c,v 1.12 1998/12/07 06:01:38 miod Exp $
  22.  
  23.   MikMod driver for Advanced Linux Sound Architecture (ALSA)
  24.  
  25. ==============================================================================*/
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30.  
  31. #ifdef HAVE_UNISTD_H
  32. #include <unistd.h>
  33. #endif
  34. #include <stdlib.h>
  35. #include <string.h>
  36.  
  37. #include <sys/asoundlib.h>
  38.  
  39. #include <mikmod_internals.h>
  40.  
  41. #define DEFAULT_NUMFRAGS 4
  42.  
  43. static    void* pcm_h=NULL;
  44. static    int fragmentsize,numfrags=DEFAULT_NUMFRAGS;
  45. static    SBYTE *audiobuffer=NULL;
  46.  
  47. static BOOL ALSA_IsThere(void)
  48. {
  49.     return (snd_cards_mask())?1:0;
  50. }
  51.  
  52. static BOOL ALSA_Init(void)
  53. {
  54.     snd_pcm_format_t pformat;
  55.     int mask,card;
  56.     int cardmin=0,cardmax=SND_CARDS;
  57.     int device=-1;
  58.  
  59.     /* adjust user-configurable settings */
  60.     if(getenv("MM_NUMFRAGS")) {
  61.         numfrags=atoi(getenv("MM_NUMFRAGS"));
  62.         if ((numfrags<2)||(numfrags>16)) numfrags=DEFAULT_NUMFRAGS;
  63.     }
  64.     if(getenv("ALSA_CARD")) {
  65.         cardmin=atoi(getenv("ALSA_CARD"));
  66.         cardmax=cardmin+1;
  67.         if(getenv("ALSA_PCM"))
  68.             device=atoi(getenv("ALSA_PCM"));
  69.     }
  70.  
  71.     /* setup playback format structure */
  72.     memset(&pformat,0,sizeof(pformat));
  73.     pformat.format=(md_mode&DMODE_16BITS)?SND_PCM_SFMT_S16_LE:SND_PCM_SFMT_U8;
  74.     pformat.channels=(md_mode&DMODE_STEREO)?2:1;
  75.     pformat.rate=md_mixfreq;
  76.  
  77.     /* scan for appropriate sound card */
  78.     mask=snd_cards_mask();
  79.     _mm_errno=MMERR_OPENING_AUDIO;
  80.     for (card=cardmin;card<cardmax;card++) {
  81.         struct snd_ctl_hw_info info;
  82.         void *ctl_h;
  83.         int dev,devmin,devmax;
  84.  
  85.         /* no card here, onto the next */
  86.         if (!(mask&(1<<card))) continue;
  87.  
  88.         /* try to open the card in query mode */
  89.         if(snd_ctl_open(&ctl_h,card)<0) {
  90. #ifdef MIKMOD_DEBUG
  91.             fprintf(stderr,"\rfailed to query card %d\n",card);
  92. #endif
  93.             continue;
  94.         }
  95.  
  96.         /* get hardware information */
  97.         if(snd_ctl_hw_info(ctl_h,&info)<0) {
  98. #ifdef MIKMOD_DEBUG
  99.             fprintf(stderr,"\rfailed to get hardware information for card %d\n",card);
  100. #endif
  101.             snd_ctl_close(ctl_h);
  102.             continue;
  103.         }
  104.  
  105.         /* scan subdevices */
  106.         if(device==-1) {
  107.             devmin=0;devmax=info.pcmdevs;
  108.         } else
  109.             devmin=devmax=device;
  110.         for(dev=devmin;dev<devmax;dev++) {
  111.             snd_pcm_info_t pcminfo;
  112.             snd_pcm_playback_info_t ctlinfo;
  113.             struct snd_pcm_playback_info pinfo;
  114.             struct snd_pcm_playback_params pparams;
  115.             int size,bps;
  116.  
  117.             /* get PCM capabilities */
  118.             if(snd_ctl_pcm_info(ctl_h,dev,&pcminfo)<0) {
  119. #ifdef MIKMOD_DEBUG
  120.                 fprintf(stderr,"\rfailed to get pcm caps for card %d, device %d\n",card,dev);
  121. #endif
  122.                 continue;
  123.             }
  124.  
  125.             /* look for playback capability */
  126.             if(!(pcminfo.flags&SND_PCM_INFO_PLAYBACK)) {
  127. #ifdef MIKMOD_DEBUG
  128.                 fprintf(stderr,"\rno playback capability for card %d, device %d\n",card,dev);
  129. #endif
  130.                 continue;
  131.             }
  132.  
  133.             /* get playback information */
  134.             if(snd_ctl_pcm_playback_info(ctl_h,dev,&ctlinfo)<0) {
  135. #ifdef MIKMOD_DEBUG
  136.                 fprintf(stderr,"\rfailed to get playback information for card %d, device %d\n",card,dev);
  137. #endif
  138.                 continue;
  139.             }
  140.  
  141.     /*
  142.        If control goes here, we have found a sound device able to play PCM data.
  143.        Let's open in in playback mode and see if we have compatible playback
  144.        settings.
  145.     */
  146.  
  147.             if (snd_pcm_open(&pcm_h,card,dev,SND_PCM_OPEN_PLAYBACK)<0) {
  148. #ifdef MIKMOD_DEBUG
  149.                 fprintf(stderr,"\rfailed to open card %d, device %d\n",card,dev);
  150. #endif
  151.                 continue;
  152.             }
  153.  
  154.             if (snd_pcm_playback_info(pcm_h,&pinfo)<0) {
  155. #ifdef MIKMOD_DEBUG
  156.                 fprintf(stderr,"\rfailed to get pcm playback information for card %d, device %d\n",card,dev);
  157. #endif
  158.                 snd_pcm_close(pcm_h);
  159.                 pcm_h=NULL;
  160.                 continue;
  161.             }
  162.  
  163.             /* check we have compatible settings */
  164.             if((pinfo.min_rate>pformat.rate)||(pinfo.max_rate<pformat.rate)||
  165.                (!(pinfo.formats&(1<<pformat.format)))) {
  166. #ifdef MIKMOD_DEBUG
  167.                 fprintf(stderr,"\rincompatible settings for card %d, device %d\n",card,dev);
  168. #endif
  169.                 snd_pcm_close(pcm_h);
  170.                 pcm_h=NULL;
  171.                 continue;
  172.             }
  173.  
  174.             fragmentsize=pinfo.buffer_size/numfrags;
  175. #ifdef MIKMOD_DEBUG
  176.             if ((fragmentsize<512)||(fragmentsize>16777216L))
  177.                 fprintf(stderr,"\rweird pinfo.buffer_size:%d\n",pinfo.buffer_size);
  178. #endif
  179.  
  180.             snd_pcm_flush_playback(pcm_h);
  181.  
  182.             /* set new parameters */
  183.             if(snd_pcm_playback_format(pcm_h,&pformat)<0) {
  184. #ifdef MIKMOD_DEBUG
  185.                 fprintf(stderr,"\rfailed to set pcm format for card %d, device %d\n",card,dev);
  186. #endif
  187.                 snd_pcm_close(pcm_h);
  188.                 pcm_h=NULL;
  189.                 continue;
  190.             }
  191.  
  192.             /* compute a fragmentsize hint
  193.                each fragment should be shorter than, but close to, half a
  194.                second of playback */
  195.             bps=(pformat.rate*pformat.channels*(md_mode&DMODE_16BITS?2:1))>>1;
  196.             size=fragmentsize;while (size>bps) size>>=1;
  197. #ifdef MIKMOD_DEBUG
  198.             if (size<16) {
  199.                 fprintf(stderr,"\rweird hint result:%d from %d, bps=%d\n",size,fragmentsize,bps);
  200.                 size=16;
  201.             }
  202. #endif
  203.  
  204.             memset(&pparams,0,sizeof(pparams));
  205.             pparams.fragment_size=size;
  206.             pparams.fragments_max=-1; /* choose the best */
  207.             pparams.fragments_room=-1;
  208.             if(snd_pcm_playback_params(pcm_h,&pparams)<0) {
  209. #ifdef MIKMOD_DEBUG
  210.                 fprintf(stderr,"\rfailed to set playback parameters for card %d, device %d\n",card,dev);
  211. #endif
  212.                 snd_pcm_close(pcm_h);
  213.                 pcm_h=NULL;
  214.                 continue;
  215.             }
  216.  
  217.             if (!(audiobuffer=(SBYTE*)_mm_malloc(fragmentsize))) {
  218.                 snd_ctl_close(ctl_h);
  219.                 return 1;
  220.             }
  221.  
  222.             /* sound device is ready to work */
  223.             if (VC_Init()) {
  224.                 snd_ctl_close(ctl_h);
  225.                 return 1;
  226.             } else
  227.               return 0;
  228.         }
  229.  
  230.         snd_ctl_close(ctl_h);
  231.     }
  232.     return 1;
  233. }
  234.  
  235. static void ALSA_Exit(void)
  236. {
  237.     VC_Exit();
  238.     if (pcm_h) {
  239.         snd_pcm_close(pcm_h);
  240.         pcm_h=NULL;
  241.     }
  242.     if (audiobuffer) {
  243.         free(audiobuffer);
  244.         audiobuffer=NULL;
  245.     }
  246. }
  247.  
  248. static void ALSA_Update(void)
  249. {
  250.     snd_pcm_playback_status_t status;
  251.  
  252.     if(snd_pcm_playback_status(pcm_h,&status)>=0) {
  253.         if(status.count>fragmentsize) status.count=fragmentsize;
  254.         snd_pcm_write(pcm_h,audiobuffer,
  255.               VC_WriteBytes(audiobuffer,status.count));
  256.     }
  257. }
  258.  
  259. static BOOL ALSA_Reset(void)
  260. {
  261.     ALSA_Exit();
  262.     return ALSA_Init();
  263. }
  264.  
  265. MDRIVER drv_alsa={
  266.     NULL,
  267.     "ALSA",
  268.     "Advanced Linux Sound Architecture (ALSA) driver v0.2.0-pre8",
  269.     0,255,
  270.     ALSA_IsThere,
  271.     VC_SampleLoad,
  272.     VC_SampleUnload,
  273.     VC_SampleSpace,
  274.     VC_SampleLength,
  275.     ALSA_Init,
  276.     ALSA_Exit,
  277.     ALSA_Reset,
  278.     VC_SetNumVoices,
  279.     VC_PlayStart,
  280.     VC_PlayStop,
  281.     ALSA_Update,
  282.     VC_VoiceSetVolume,
  283.     VC_VoiceSetFrequency,
  284.     VC_VoiceSetPanning,
  285.     VC_VoicePlay,
  286.     VC_VoiceStop,
  287.     VC_VoiceStopped,
  288.     VC_VoiceGetPosition,
  289.     VC_VoiceRealVolume
  290. };
  291.