summaryrefslogtreecommitdiff
path: root/tutorials/sndkit/samples/singen.c
diff options
context:
space:
mode:
Diffstat (limited to 'tutorials/sndkit/samples/singen.c')
-rw-r--r--tutorials/sndkit/samples/singen.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/tutorials/sndkit/samples/singen.c b/tutorials/sndkit/samples/singen.c
new file mode 100644
index 0000000..a9db39a
--- /dev/null
+++ b/tutorials/sndkit/samples/singen.c
@@ -0,0 +1,195 @@
+/*
+ * Purpose: A simple audio playback program that plays continuous 1 kHz sine wave.
+ * Copyright (C) 4Front Technologies, 2002-2004. Released under GPLv2/CDDL.
+ *
+ * Description:
+ * This minimalistic program shows how to play udio with OSS. It outputs
+ * 1000 Hz sinewave signal (based on a 48 step lookup table).
+ *
+ * This is pretty much the simpliest possible audio playback program
+ * one can imagine. It could be possible to make it even simplier
+ * by removing all error checking but that is in no way recommended.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <soundcard.h>
+
+int fd_out;
+int sample_rate = 48000;
+
+static void
+write_sinewave (void)
+{
+/*
+ * This routine is a typical example of application routine that
+ * produces audio signal using synthesis. This is actually a very
+ * basic "wave table" algorithm (btw). It uses precomputed sine
+ * function values for a complete cycle of a sine function.
+ * This is much faster than calling the sin() function once for
+ * each sample.
+ *
+ * In other applications this routine can simply be replaced by
+ * whatever the application needs to do.
+ */
+
+ static unsigned int phase = 0; /* Phase of the sine wave */
+ unsigned int p;
+ int i;
+ short buf[1024]; /* 1024 samples/write is a safe choice */
+
+ int outsz = sizeof (buf) / 2;
+
+ static int sinebuf[48] = {
+
+ 0, 4276, 8480, 12539, 16383, 19947, 23169, 25995,
+ 28377, 30272, 31650, 32486, 32767, 32486, 31650, 30272,
+ 28377, 25995, 23169, 19947, 16383, 12539, 8480, 4276,
+ 0, -4276, -8480, -12539, -16383, -19947, -23169, -25995,
+ -28377, -30272, -31650, -32486, -32767, -32486, -31650, -30272,
+ -28377, -25995, -23169, -19947, -16383, -12539, -8480, -4276
+ };
+
+ for (i = 0; i < outsz; i++)
+ {
+/*
+ * The sinebuf[] table was computed for 48000 Hz. We will use simple
+ * sample rate compensation.
+ *
+ * {!notice We must prevent the phase variable from groving too large
+ * because that would cause cause arihmetic overflows after certain time.
+ * This kind of error posibilities must be identified when writing audio
+ * programs that could be running for hours or even months or years without
+ * interruption. When computing (say) 192000 samples each second the 32 bit
+ * integer range may get overflown very quickly. The number of samples
+ * played at 192 kHz will cause an overflow after about 6 hours.}
+ */
+
+ p = (phase * sample_rate) / 48000;
+
+ phase = (phase + 1) % 4800;
+ buf[i] = sinebuf[p % 48];
+ }
+
+/*
+ * Proper error checking must be done when using write. It's also
+ * important to reporte the error code returned by the system.
+ */
+
+ if (write (fd_out, buf, sizeof (buf)) != sizeof (buf))
+ {
+ perror ("Audio write");
+ exit (-1);
+ }
+}
+
+/*
+ * The open_audio_device opens the audio device and initializes it
+ * for the required mode.
+ */
+
+static int
+open_audio_device (char *name, int mode)
+{
+ int tmp, fd;
+
+ if ((fd = open (name, mode, 0)) == -1)
+ {
+ perror (name);
+ exit (-1);
+ }
+
+/*
+ * Setup the device. Note that it's important to set the
+ * sample format, number of channels and sample rate exactly in this order.
+ * Some devices depend on the order.
+ */
+
+/*
+ * Set the sample format
+ */
+ tmp = AFMT_S16_NE; /* Native 16 bits */
+ if (ioctl (fd, SNDCTL_DSP_SETFMT, &tmp) == -1)
+ {
+ perror ("SNDCTL_DSP_SETFMT");
+ exit (-1);
+ }
+
+ if (tmp != AFMT_S16_NE)
+ {
+ fprintf (stderr,
+ "The device doesn't support the 16 bit sample format.\n");
+ exit (-1);
+ }
+
+/*
+ * Set the number of channels
+ */
+ tmp = 1;
+ if (ioctl (fd, SNDCTL_DSP_CHANNELS, &tmp) == -1)
+ {
+ perror ("SNDCTL_DSP_CHANNELS");
+ exit (-1);
+ }
+
+ if (tmp != 1)
+ {
+ fprintf (stderr, "The device doesn't support mono mode.\n");
+ exit (-1);
+ }
+
+/*
+ * Set the sample rate
+ */
+ sample_rate = 48000;
+ if (ioctl (fd, SNDCTL_DSP_SPEED, &sample_rate) == -1)
+ {
+ perror ("SNDCTL_DSP_SPEED");
+ exit (-1);
+ }
+
+/*
+ * No need for error checking because we will automatically adjust the
+ * signal based on the actual sample rate. However most application must
+ * check the value of sample_rate and compare it to the requested rate.
+ *
+ * Small differences between the rates (10% or less) are normal and the
+ * applications should usually tolerate them. However larger differences may
+ * cause annoying pitch problems (Mickey Mouse).
+ */
+
+ return fd;
+}
+
+int
+main (int argc, char *argv[])
+{
+/*
+ * Use /dev/dsp as the default device because the system administrator
+ * may select the device using the {!xlink ossctl} program or some other
+ * methods
+ */
+ char *name_out = "/dev/dsp";
+
+/*
+ * It's recommended to provide some method for selecting some other
+ * device than the default. We use command line argument but in some cases
+ * an environment variable or some configuration file setting may be better.
+ */
+ if (argc > 1)
+ name_out = argv[1];
+
+/*
+ * It's mandatory to use O_WRONLY in programs that do only playback. Other
+ * modes may cause increased resource (memory) usage in the driver. It may
+ * also prevent other applications from using the same device for
+ * recording at the same time.
+ */
+ fd_out = open_audio_device (name_out, O_WRONLY);
+
+ while (1)
+ write_sinewave ();
+
+ exit (0);
+}