Commits

J.A. Roberts Tunney committed 0c30de3

Rewritten to support new audiohooks API to keep Asterisk devs happy.
This makes the voice changer work *with* DIAL rather than replacing it
so you can take advantage of features offered by Asterisk and DIAL all
while using the Voice Changer. Certain features such as DTMF deltas
removed temporarily until I have time to add them back in.

Comments (0)

Files changed (9)

AUTHORS

-J.A. Roberts Tunney <jtunney@lobstertech.com>
-2006-07-01  J.A. Roberts Tunney  <jtunney@lobstertech.com>
+2009-06-08  J.A. Roberts Tunney  <jtunney@lobstertech.com>
+
+	* voicechanger 0.7
+
+2009-06-08  J.A. Roberts Tunney  <jtunney@lobstertech.com>
+
+	* app_voicechangedial.c: Rewritten to support new audiohooks API
+	  to keep Asterisk devs happy.  Certain features such as DTMF deltas
+	  removed temporarilly until I have time to add them back in.
+
+2007-07-01  J.A. Roberts Tunney  <jtunney@lobstertech.com>
 
 	* voicechanger 0.6
 
 	* app_voicechangedial.c: (wait_for_answer): Fixed ringing bug.
 	  Before peer is answered, audio from peer is passed to caller.
 	  This allows them to hear the rings (or an obnoxious hook from a
-	  rap song) as generated by the telco.  I also got rid of the 'r'
-	  option.
-	  
+	  rap song) as generated by the telco.
+
 	  (initiate_call): Fixed CallerID passing problem.  This problem
 	  was caused be me not testing and Asterisk having a poor
 	  architecture.  You can thank Peter Ericksen for kindly informing
 
 	* voicechanger 0.4
 
-Copyright (c) 2005-2007 J.A. Roberts Tunney
+Copyright (c) 2005-2009 Lobstertech, Inc.
 Copying and distribution of this file, with or without modification, are
 permitted provided the copyright notice and this notice are preserved.

INSTALL

-              .--.                              .--.
-            .'(`                               /  ..\
-         __.>\ '.  _.---,._,'             ____.'  _o/
-       /.--.  : |/' _.--.<                '--.     |.__
-    _..-'    `\     /'     `'             _.-'     /--'
-     >_.-``-. `Y  /' _.---._____     _.--'        /
-    '` .-''. \|:  \.'   ___, .-'`   ~'--....___.-'
-     .'--._ `-:  \/   /'    \\
-         /.'`\ :;    /'       `-.
-        -`    |     |
-              :.; : |             Asterisk Voice Changer
-              |:    |                  Version o.5.1
-              |     |
-              :. :  |   Copyright (c) 2005-2007 J.A. Roberts Tunney
-            .jgs    ;            Keep it open source pigs
-            /:::.    `\
-----------------------------------------------------------------------
-
-J.A. Roberts Tunney <jtunney@lobstertech.com>
-http://www.lobstertech.com/code/voicechanger/
-
-----------------------------------------------------------------------
-REQUIREMENTS
-----------------------------------------------------------------------
-
- - Asterisk 1.2 or 1.4
- - Asterisk Development Package (If you installed Asterisk with a
-   package manager like apt-get)
- - SoundTouch >= 1.3.0
- - libsoundtouch4c
-
-----------------------------------------------------------------------
-INSTALLATION
-----------------------------------------------------------------------
-
-Run the following commands while inside the source directory for this
-program.
-
-	make clean
-	make
-	make install
-
-If that worked, the module should now be loaded in to Asterisk next
-time it is restarted.  If you want to load the Jukebox application in
-to a running instance of Asterisk without restart, then issue this
-command:
-
-	make start
-
-If you make a change any of the code, you can recompile, intall, and
-reload all the modules in to Asterisk with one command:
-
-	make restart
-
-To unload the modules:
-
-	make stop
-
-----------------------------------------------------------------------
-
-               __                          ___           _aaa
-              d8888a,_                  a8888888a  __a8888888b
-             d8P   `88ba.               8P'~~~~Y88888P""~~~~88b
-            d8P     ~"Y88a____aaaa_____aP        88         Y88
-           d8P         ~Y88"8~~~~~~88888          8g         88
-          d8P                         88     ____ 88y__      88b
-          88                         a88   _a88~888"8M88a____888
-          88                         88P   88  a8"     `88888888b_
-          8P                         88    88 a88        88b    Y8,
-          88a                        Y8b     888L        888.    88P
-         aP                           Y8     _888      _a8P 8   a88
-        _8                             ~88a888~888_   a888yg'  a88'
-        88                               ~~~~    ~"8888       a88P
-       d8'                                           Y8,     888L
-       8E                                             88a___8"888
-      d8P                                              ~Y888   88L
-      88                                                        88
-      88                                                        88b
-  ____88a_      a8a                                           __881
-88""P~888       888b                              _         8888888888
-      888       888P                             d8b            88
-     _888b       ~           aaa.                888           d8P
- a888~"Y88                  88888                "P         8aa888_
-        Y8                  Y88P"                             88""888a
-        _8g8                 ~~                              a88    ~~
-    __a8"88_                                              a_a88
-   88"'   "88g                                             "88g_
-   ~        `88a_                                        _a8'"Y88gg,
-               "888a_.                                _a88"'     ~88
-                  ~~"8888aaa_____               ___a888P'
-                          ~~""""""888888888888888888""~~~
-                                   ~~~~~~~~~~~
 #
 # Asterisk Voice Changer Makefile
 #
-# Copyright (C) 2005-2007 J.A. Roberts Tunney
+# Copyright (C) 2005-2009 J.A. Roberts Tunney
 #
 # J.A. Roberts Tunney <jtunney@lobstertech.com>
 #
 PREFIX      = /usr
 MODULES_DIR = $(PREFIX)/lib/asterisk/modules
 
-MODS        = app_voicechangedial.so
+MODS        = app_voicechanger.so
 CFLAGS      = -O -g -D_GNU_SOURCE -shared -fpic
 LDFLAGS     = -lsoundtouch4c
 
 #
 # Asterisk Module Makefile Include
 #
-# Copyright (C) 2005-2007 J.A. Roberts Tunney
+# Copyright (C) 2005-2009 J.A. Roberts Tunney
 #
 # J.A. Roberts Tunney <jtunney@lobstertech.com>
 #
 	mv /tmp/$(NAME).tar.gz .
 
 start: install
-	for x in $(MODS); do asterisk -rx "load $$x" ; done
+	for x in $(MODS); do asterisk -rx "module load $$x" ; done
 
 stop:
-	for x in $(MODS); do asterisk -rx "unload $$x" ; done
+	for x in $(MODS); do asterisk -rx "module unload $$x" ; done
 
 restart: all stop start
 
          /.'`\ :;    /'       `-.
         -`    |     |
               :.; : |             Asterisk Voice Changer
-              |:    |                  Version o.5.1
+              |:    |                  Version o.7
               |     |
-              :. :  |   Copyright (c) 2005-2007 J.A. Roberts Tunney
+              :. :  |     Copyright (c) 2005-2009 Lobstertech, Inc.
             .jgs    ;            Keep it open source pigs
             /:::.    `\
 ----------------------------------------------------------------------
 
-J.A. Roberts Tunney <jtunney@lobstertech.com>
-http://www.lobstertech.com/code/voicechanger/
+http://lobstertech.com/code/voicechanger/
+jtunney@lobstertech.com
+
+This program is a voice changer module for Asterisk.  This allows you to
+change the pitch of your voice in real time when placing VoIP calls.
+This software is not intended to change the gender of your voice as no
+formant adjustments are not implemented.  This software however does an
+excellent job making you sound really creepy and oftentimes
+unrecognizable.  Furthermore this software is not intended to guarentee
+your privacy as pitch shifting is not a one-way algorithm and hence can
+be reversed.
+
+This version uses the audio-hooks API built into Asterisk >1.4.18 and
+removes certain DTMF-related features made available in previous
+releases.  If you are using a previous version of Asterisk or want those
+features, please download release 0.6.  These features may be added
+back in slowly or you can send me a patch.
+
+This has only been tested with Asterisk 1.4.x.  I welcome your patches
+if this doesn't work with Asterisk 1.6.x
 
 ----------------------------------------------------------------------
-DESCRIPTION
+INSTALLATION
 ----------------------------------------------------------------------
 
-This program is a voice changer module for Asterisk.  This allows you
-to change the pitch of you voice, or the voice of the called party in
-realtime, when making phone calls.
+For the most pain-free installation, please visit the web page.
 
-The application, VoiceChangeDial, functions as a Dial() replacement.
-Although the behavior of this application seeks to mimic Dial(), it is
-not perfect due to the fact that Asterisk does not properly abstract
-dial and bridging functionality.
+Requirements:
 
-----------------------------------------------------------------------
-MANUAL
-----------------------------------------------------------------------
+ - Asterisk 1.4 (maybe 1.6)
+ - Asterisk Development Package (If you installed Asterisk with a
+   package manager like apt-get)
+ - SoundTouch >= 1.3.0
+ - libsoundtouch4c
 
+Run the following commands while inside the source directory for this
+program.
 
-----------------------------------------------------------------------
+	make clean
+	make
+	make install
 
-               __                          ___           _aaa
-              d8888a,_                  a8888888a  __a8888888b
-             d8P   `88ba.               8P'~~~~Y88888P""~~~~88b
-            d8P     ~"Y88a____aaaa_____aP        88         Y88
-           d8P         ~Y88"8~~~~~~88888          8g         88
-          d8P                         88     ____ 88y__      88b
-          88                         a88   _a88~888"8M88a____888
-          88                         88P   88  a8"     `88888888b_
-          8P                         88    88 a88        88b    Y8,
-          88a                        Y8b     888L        888.    88P
-         aP                           Y8     _888      _a8P 8   a88
-        _8                             ~88a888~888_   a888yg'  a88'
-        88                               ~~~~    ~"8888       a88P
-       d8'                                           Y8,     888L
-       8E                                             88a___8"888
-      d8P                                              ~Y888   88L
-      88                                                        88
-      88                                                        88b
-  ____88a_      a8a                                           __881
-88""P~888       888b                              _         8888888888
-      888       888P                             d8b            88
-     _888b       ~           aaa.                888           d8P
- a888~"Y88                  88888                "P         8aa888_
-        Y8                  Y88P"                             88""888a
-        _8g8                 ~~                              a88    ~~
-    __a8"88_                                              a_a88
-   88"'   "88g                                             "88g_
-   ~        `88a_                                        _a8'"Y88gg,
-               "888a_.                                _a88"'     ~88
-                  ~~"8888aaa_____               ___a888P'
-                          ~~""""""888888888888888888""~~~
-                                   ~~~~~~~~~~~
+If that worked, the module should now be loaded in to Asterisk next
+time it is restarted.  If you want to load the Jukebox application in
+to a running instance of Asterisk without restart, then issue this
+command:
+
+	make start
+
+If you make a change any of the code, you can recompile, intall, and
+reload all the modules in to Asterisk with one command:
+
+	make restart
+
+To unload the modules:
+
+	make stop

app_voicechangedial.c

-/*
- * Voice Changer for Asterisk 1.2 and 1.4
- * Version 0.6
- *
- * Copyright (C) 2005-2007 J.A Roberts Tunney
- *
- * J.A. Roberts Tunney <jtunney@lobstertech.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License version 2.0.
- *
- * Keep it Open Source Pigs
- *
- * Special Thanks:
- *
- * Claude Patry <cpatry@gmail.com>
- * Anthony Minessale II <anthmct@yahoo.com>
- *
- */
-
-#define AST_MODULE "app_voicechangedial"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <soundtouch4c.h>
-#include <asterisk/file.h>
-#include <asterisk/logger.h>
-#include <asterisk/frame.h>
-#include <asterisk/channel.h>
-#include <asterisk/pbx.h>
-#include <asterisk/module.h>
-#include <asterisk/lock.h>
-#include <asterisk/options.h>
-#include <asterisk/app.h>
-#ifndef _ASTERISK_1_2_
-#include <asterisk/stringfields.h>
-#endif
-
-#ifdef _ASTERISK_1_2_
-#define ast_module_user localuser
-#define ast_module_user_remove LOCAL_USER_REMOVE
-#define ast_module_user_hangup_all() STANDARD_HANGUP_LOCALUSERS
-STANDARD_LOCAL_USER;
-LOCAL_USER_DECL;
-#endif
-
-static char *app = "VoiceChangeDial";
-static char *synopsis = "Voice Changer Dial Application";
-static char *desc = "\n"
-"Usage VoiceChangeDial(dialstring[|options])\n"
-"\n"
-"Usage:\n"
-"  This app fuctions pretty much the same way as Dial() only you can do\n"
-"  cool stuff like change the pitch of your voice.  Please note that\n"
-"  pitch changes are not very sophisticated, this will not make a man\n"
-"  sound like a woman or vice versa.  It will however do a great job of\n"
-"  masking your voice by making you sound either like a chimpmunk or\n"
-"  Jabba the Hut.\n"
-"\n"
-"  Because this application needs to mangle voice data, it will need to\n"
-"  pass through Asterisk back-to-back.  This means that if you are\n"
-"  switching SIP, the RTP will not pass from phone to phone, but will\n"
-"  be proxied through Asterisk.  Therefore, VoiceChangeDial() will use\n"
-"  considerably more CPU and bandwidth than a normal Dial() operation.\n"
-"\n"
-"Options:\n"
-"  p    -- Apply effect to peer channel instead\n"
-"  P(f) -- Voice pitch in semitones.  Negative is lower, positive\n"
-"          is higher.  Default is -5.0\n"
-"  T(n) -- Dial timeout in seconds.  If not set, waits 60 sec.\n"
-"          for other side to pickup\n"
-"  D(down:up[:delta]) -- Allow pitch changes during conversation by\n"
-"          pressing DTMF keys 'up' and 'down' with a semitones change\n"
-"          of 'delta'.  Examples:  D(*:#:5.0), D(1:2).  The default\n"
-"          delta is 5.0 semitones.\n"
-"  H(x) -- Allow caller to hangup the peer by pressing '*'.  This\n"
-"          is different from the behavior of 'h' in previous\n"
-"          releases of the voice changer.  This option trumps 'd'\n"
-"  S(x) -- Allow peer to hangup themself by pressing DTMF digit 'x'.\n"
-"          Mnemonic is 'suicide'.\n"
-"  d    -- **DEPRECATED** Allow pitch changes during conversation with\n"
-"          '*' and '#'\n"
-"  h    -- **DEPRECATED** Allow caller to hangup the peer by pressing\n"
-"          '*'.  This is different from the behavior of 'h' in previous\n"
-"          releases of the voice changer.  This option trumps 'd'\n"
-"  s    -- **DEPRECATED** Allow peer to hangup themself by pressing\n"
-"          '*'.  Mnemonic is 'suicide'.  This option trumps 'd'\n"
-"\n"
-"Recommended Invocation:\n"
-"\n"
-"  VoiceChangeDial(SIP/bandwidth/+12036660420|T(30)P(-5.0)D(8:9)H(*))\n"
-"\n"
-"    This will wait 30 seconds for the called party to pickup, make\n"
-"    voice sound lower, and allow you to change your voice down and up\n"
-"    with digits '8' and '9'.  You may also hang up the call with '*'.\n"
-;
-
-#define APP_VOICECHANGEDIAL_PITCH      (1 << 0)
-#define APP_VOICECHANGEDIAL_TIMEOUT    (1 << 1)
-#define APP_VOICECHANGEDIAL_PEEREFFECT (1 << 2)
-#define APP_VOICECHANGEDIAL_DYNAMIC    (1 << 3)
-#define APP_VOICECHANGEDIAL_HANGUP     (1 << 4)
-#define APP_VOICECHANGEDIAL_SUICIDE    (1 << 5)
-#define APP_VOICECHANGEDIAL_DYNAMIC_DEPRECATED    (1 << 6)
-#define APP_VOICECHANGEDIAL_HANGUP_DEPRECATED     (1 << 7)
-#define APP_VOICECHANGEDIAL_SUICIDE_DEPRECATED    (1 << 8)
-
-enum {
-	OPT_ARG_VOICECHANGEDIAL_PITCH = 0,
-	OPT_ARG_VOICECHANGEDIAL_TIMEOUT,
-	OPT_ARG_VOICECHANGEDIAL_DYNAMIC,
-	OPT_ARG_VOICECHANGEDIAL_HANGUP,
-	OPT_ARG_VOICECHANGEDIAL_SUICIDE,
-	/* note: this entry _MUST_ be the last one in the enum */
-	OPT_ARG_VOICECHANGEDIAL_ARRAY_SIZE
-} voicechangedial_option_args;
-
-AST_APP_OPTIONS(voicechangedial_options, {
-	AST_APP_OPTION('p', APP_VOICECHANGEDIAL_PEEREFFECT),
-	AST_APP_OPTION('d', APP_VOICECHANGEDIAL_DYNAMIC_DEPRECATED),
-	AST_APP_OPTION('h', APP_VOICECHANGEDIAL_HANGUP_DEPRECATED),
-	AST_APP_OPTION('s', APP_VOICECHANGEDIAL_SUICIDE_DEPRECATED),
-	AST_APP_OPTION_ARG('P', APP_VOICECHANGEDIAL_PITCH, OPT_ARG_VOICECHANGEDIAL_PITCH),
-	AST_APP_OPTION_ARG('T', APP_VOICECHANGEDIAL_TIMEOUT, OPT_ARG_VOICECHANGEDIAL_TIMEOUT),
-	AST_APP_OPTION_ARG('D', APP_VOICECHANGEDIAL_DYNAMIC, OPT_ARG_VOICECHANGEDIAL_DYNAMIC),
-	AST_APP_OPTION_ARG('H', APP_VOICECHANGEDIAL_HANGUP, OPT_ARG_VOICECHANGEDIAL_HANGUP),
-	AST_APP_OPTION_ARG('S', APP_VOICECHANGEDIAL_SUICIDE, OPT_ARG_VOICECHANGEDIAL_SUICIDE)
-});
-
-enum dtmfaction {
-	DTMFACTION_NULL = 0,
-	DTMFACTION_RAISEPITCH,
-	DTMFACTION_LOWERPITCH,
-	DTMFACTION_HANGUP
-};
-
-#define DTMFRANGE ('9' - '#' + 1)
-#define ASCII2DTMF(c) (c - '#')
-#define ISDTMFDIGIT(c) ((c >= '0' && c <= '9') || c == '*' || c == '#')
-struct voicechangedial_ops {
-	struct ast_channel *chan;
-	char *tech;
-	char *dest;
-	int options;
-	float pitch;
-	float pitchdelta;
-	int timeout; /* in milliseconds */
-	enum dtmfaction chan_dtmfactions[DTMFRANGE];
-	enum dtmfaction peer_dtmfactions[DTMFRANGE];
-};
-
-static struct soundtouch *soundtouch_create(float newPitch)
-{
-	struct soundtouch *snd;
-
-	ast_log(LOG_DEBUG, "Creating SoundTouch object...\n");
-	snd = SoundTouch_construct();
-	if (!snd) {
-		ast_log(LOG_WARNING, "Failed to create SoundTouch object\n");
-		return NULL;
-	}
-
-	SoundTouch_setChannels(snd, 1);
-	SoundTouch_setSampleRate(snd, 8000);
-	SoundTouch_setPitchSemiTonesFloat(snd, newPitch);
-	SoundTouch_setSetting(snd, SETTING_USE_QUICKSEEK, 1);
-	SoundTouch_setSetting(snd, SETTING_USE_AA_FILTER, 1);
-
-	return snd;
-}
-
-static void soundtouch_free(struct soundtouch *st)
-{
-	ast_log(LOG_DEBUG, "Freeing SoundTouch object...\n");
-	SoundTouch_destruct(st);
-}
-
-/*
- * Responsible for passing audio between channels
- */
-static int bridge_audio(const struct voicechangedial_ops *ops, struct ast_channel *peer)
-{
-	int res = 0;
-	struct ast_channel *chan = ops->chan;
-	struct ast_channel *active, *inactive;
-	struct ast_channel *channels[2] = { ops->chan, peer };
-	struct ast_frame *f;
-	int timeout = -1;
-	struct soundtouch *st;
-	float stout[256], stin[256];
-	int n;
-
-	float pitch = ops->pitch;
-	int op_peereffect = (ops->options & APP_VOICECHANGEDIAL_PEEREFFECT) == APP_VOICECHANGEDIAL_PEEREFFECT;
-
-	if (!(st = soundtouch_create(pitch)))
-		return -1;
-
-	while (!ast_check_hangup(channels[0]) && !ast_check_hangup(channels[1])) {
-		if (!(active = ast_waitfor_n(channels, 2, &timeout)))
-			continue;
-		inactive = active == channels[0] ? channels[1] : channels[0];
-		if (!(f = ast_read(active)))
-			break;
-		switch (f->frametype) {
-		case AST_FRAME_DTMF: {
-			enum dtmfaction action = DTMFACTION_NULL;
-			if (active == chan)
-				action = ops->chan_dtmfactions[ASCII2DTMF(f->subclass)];
-			else
-				action = ops->peer_dtmfactions[ASCII2DTMF(f->subclass)];
-			switch (action) {
-			case DTMFACTION_NULL:
-				break;
-			case DTMFACTION_RAISEPITCH:
-				pitch += ops->pitchdelta;
-				SoundTouch_setPitchSemiTonesFloat(st, pitch);
-				if (option_verbose > 3)
-					ast_verbose(VERBOSE_PREFIX_4 "New pitch is %f semitones\n", pitch);
-				break;
-			case DTMFACTION_LOWERPITCH:
-				pitch -= ops->pitchdelta;
-				SoundTouch_setPitchSemiTonesFloat(st, pitch);
-				if (option_verbose > 3)
-					ast_verbose(VERBOSE_PREFIX_4 "New pitch is %f semitones\n", pitch);
-				break;
-			case DTMFACTION_HANGUP:
-				goto BREAKBREAK;
-			}
-
-			ast_write(inactive, f);
-			break;
-		}
-		case AST_FRAME_VOICE:
-			if (pitch != 0.0 && active == (op_peereffect ? peer : chan)) {
-				SoundTouch_putSamples(st, f->data, f->samples);
-				memset(f->data, 0, f->datalen);
-				SoundTouch_receiveSamplesEx(st, f->data, f->samples);
-			}
-			ast_write(inactive, f);
-			break;
-		default:
-			break;
-		}
-		channels[0] = inactive;
-		channels[1] = active;
-		ast_frfree(f);
-		continue;
-	BREAKBREAK:
-		break;
-	}
-
-	soundtouch_free(st);
-
-	return res;
-}
-
-/*
- * In this method, we wait for control frames on the peer channel to
- * let us know if the person we're calling picks up, is busy, etc.
- *
- * We're also going to be snooping on the calling channel to make sure
- * we can stop ringing the peer if they cancel by hanging up.
- *
- * Returns:
- *  -1: Error
- *   0: Fail to bridge
- *   1: Answered
- */
-static int wait_for_answer(const struct voicechangedial_ops *ops, struct ast_channel *peer, int timeout, char *status, int len)
-{
-	struct ast_frame *f;
-
-	for (;;) {
-		if (ast_check_hangup(ops->chan)) {
-			snprintf(status, len, "CANCEL");
-			ast_log(LOG_NOTICE, "Caller canceled call\n");
-			return 0;
-		}
-		if (ops->chan->sched)
-			ast_sched_runq(ops->chan->sched);
-		timeout = ast_waitfor(peer, timeout);
-		if (timeout < 0) {
-			ast_log(LOG_NOTICE, "ast_waitfor() error\n");
-			return -1;
-		}
-		if (timeout == 0) {
-			snprintf(status, len, "NOANSWER");
-			ast_log(LOG_NOTICE, "Timeout waiting for answer\n");
-			return 0;
-		}
-		if (!(f = ast_read(peer))) {
-			ast_log(LOG_NOTICE, "ast_read() failed\n");
-			return -1;
-		}
-		switch (f->frametype) {
-		case AST_FRAME_VOICE:
-			if (ast_write(ops->chan, f))
-				ast_log(LOG_NOTICE, "Unable to forward frame\n");
-			break;
-		case AST_FRAME_CONTROL:
-			switch (f->subclass) {
-			case AST_CONTROL_RINGING:
-				ast_indicate(ops->chan, AST_CONTROL_RINGING);
-				break;
-			case AST_CONTROL_BUSY:
-				snprintf(status, len, "BUSY");
-				ast_frfree(f);
-				return 0;
-			case AST_CONTROL_CONGESTION:
-				snprintf(status, len, "CONGESTION");
-				ast_frfree(f);
-				return 0;
-			case AST_CONTROL_ANSWER:
-				snprintf(status, len, "ANSWERED");
-				if (option_verbose > 3)
-					ast_verbose(VERBOSE_PREFIX_4 "Call was answered!\n");
-				ast_frfree(f);
-				return 1;
-			}
-			break;
-		}
-		ast_frfree(f);
-	}
-}
-
-/*
- * Responsible for getting the callee and caller channels in the mood
- * to get down, make love.
- */
-static int initiate_call(const struct voicechangedial_ops *ops, struct ast_channel *peer, char *status, int len)
-{
-	int res;
-	struct ast_channel *chan = ops->chan;
-	int oldread, oldwrite;
-
-	oldread = chan->readformat;
-	oldwrite = chan->writeformat;
-
-	/* copy crap over from chan to peer, why isn't there a core function for this? */
-	ast_channel_inherit_variables(chan, peer);
-	ast_set_callerid(peer, chan->cid.cid_name, chan->cid.cid_num, chan->cid.cid_num);
-#ifdef _ASTERISK_1_2_
-	ast_copy_string(peer->language, chan->language, sizeof(peer->language));
-	ast_copy_string(peer->accountcode, chan->accountcode, sizeof(peer->accountcode));
-	if (ast_strlen_zero(peer->musicclass))
-		ast_copy_string(peer->musicclass, chan->musicclass, sizeof(peer->musicclass));
-#else
-	ast_string_field_set(peer, language, chan->language);
-	ast_string_field_set(peer, accountcode, chan->accountcode);
-	if (ast_strlen_zero(peer->musicclass))
-		ast_string_field_set(peer, musicclass, chan->musicclass);
-#endif
-	peer->cdrflags = chan->cdrflags;
-	if (chan->cid.cid_rdnis)
-		peer->cid.cid_rdnis = strdup(chan->cid.cid_rdnis);
-	peer->cid.cid_pres = chan->cid.cid_pres;
-	peer->cid.cid_ton = chan->cid.cid_ton;
-	peer->cid.cid_tns = chan->cid.cid_tns;
-	peer->adsicpe = chan->adsicpe;
-	peer->transfercapability = chan->transfercapability;
-	peer->appl = app;
-	peer->data = ast_strdupa(chan->name);
-	if (chan->cid.cid_num) {
-		peer->cid.cid_num = strdup(chan->cid.cid_num);
-		if (!peer->cid.cid_num)
-			ast_log(LOG_WARNING, "Out of memory\n");
-	}
-	if (chan->cid.cid_name) {
-		peer->cid.cid_name = strdup(chan->cid.cid_name);
-		if (!peer->cid.cid_name)
-			ast_log(LOG_WARNING, "Out of memory\n");
-	}
-	peer->cdrflags = chan->cdrflags;
-
-	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)  < 0 ||
-	    ast_set_read_format(peer, AST_FORMAT_SLINEAR)  < 0 ||
-	    ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0 ||
-	    ast_set_write_format(peer, AST_FORMAT_SLINEAR) < 0) {
-		ast_log(LOG_WARNING, "Unable to set channel i/o to slinear mode\n");
-		return -1;
-	}
-
-	/* call the mofo */
-	ast_indicate(chan, AST_CONTROL_RINGING);
-	if (chan->cdr)
-		ast_cdr_setdestchan(chan->cdr, peer->name);
-	if (ast_call(peer, ops->dest, 0) < 0) {
-		ast_log(LOG_ERROR, "ast_call() failed\n");
-		return -1;
-	}
-	res = wait_for_answer(ops, peer, ops->timeout, status, len);
-	if (res <= 0)
-		return res;
-	if (ast_channel_make_compatible(chan, peer) != 0) {
-		ast_log(LOG_ERROR, "failed to make remote_channel %s/%s Compatible\n", ops->tech, ops->dest);
-		return -1;
-	}
-
-	ast_answer(chan);
-	ast_indicate(chan, -1);
-
-	/* just in case */
-	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)  < 0 ||
-	    ast_set_read_format(peer, AST_FORMAT_SLINEAR)  < 0 ||
-	    ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0 ||
-	    ast_set_write_format(peer, AST_FORMAT_SLINEAR) < 0) {
-		ast_log(LOG_WARNING, "Unable to set channel i/o to slinear mode\n");
-		return -1;
-	}
-	
-	res = bridge_audio(ops, peer);
-
-	ast_playtones_stop(chan);
-	ast_set_read_format(chan, oldread);
-	ast_set_write_format(chan, oldwrite);
-
-	return res;
-}
-
-/*
- * Responsible for creating the peer 'callee' channel and managing
- * it's precense in the local user list.
- */
-static int make_call(const struct voicechangedial_ops *ops)
-{
-	int rc;
-	struct ast_module_user *peer;
-	struct ast_channel *peerchan;
-	char status[64] = "";
-	int cause = 0;
-
-	if (!(peerchan = ast_request(ops->tech, ops->chan->nativeformats, ops->dest, &cause))) {
-		ast_log(LOG_ERROR, "Error creating channel %s/%s\n", ops->tech, ops->dest);
-		ast_cdr_failed(ops->chan->cdr);
-		return -1;
-	}
-
-#ifdef _ASTERISK_1_2_
-	if (!(peer = malloc(sizeof(peer)))) {
-		ast_log(LOG_WARNING, "Out of memory\n");
-		return -1;
-	}
-	memset(peer, 0, sizeof(peer));
-	{
-		struct ast_channel *chan = peerchan;
-		LOCAL_USER_ADD(peer);
-	}
-#else
-	peer = ast_module_user_add(peerchan);
-#endif
-
-	rc = initiate_call(ops, peerchan, status, sizeof(status));
-	ast_indicate(ops->chan, -1);
-	ast_hangup(peerchan);
-
-	if (status[0]) {
-		if (strcmp(status, "BUSY") == 0)
-			ast_cdr_busy(ops->chan->cdr);
-		else if (strcmp(status, "ANSWERED") == 0)
-			/* ast_answer() should do this */;
-		else
-			ast_cdr_failed(ops->chan->cdr);
-		pbx_builtin_setvar_helper(ops->chan, "DIALSTATUS", status);
-		if (option_verbose > 3)
-			ast_verbose(VERBOSE_PREFIX_4 "Exiting with DIALSTATUS=%s.\n", status);
-	} else
-		ast_cdr_failed(ops->chan->cdr);
-
-	ast_module_user_remove(peer);
-
-	return rc;
-}
-
-/*
- * Responsible for managing the presence of the calling channel in the
- * local users list.
- */
-static int voicechangedial_exec(const struct voicechangedial_ops *ops)
-{
-	int rc;
-	struct ast_module_user *u;
-	struct ast_channel *chan = ops->chan;
-
-#ifdef _ASTERISK_1_2_
-	LOCAL_USER_ADD(u);
-#else
-	u = ast_module_user_add(chan);
-#endif
-
-	rc = make_call(ops);
-	ast_module_user_remove(u);
-	return rc;
-}
-
-/*
- * The sole purpose of this function is to parse the argument data and
- * then call voicechangedial_exec()
- */
-static int voicechangedial_app_exec(struct ast_channel *chan, void *data)
-{
-	int rc;
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(dialstr);
-		AST_APP_ARG(options);
-	);
-	char *parse;
-	struct ast_flags opts = { 0, };
-	char *opt_args[OPT_ARG_VOICECHANGEDIAL_ARRAY_SIZE];
-	struct voicechangedial_ops ops;
-
-	memset(&ops, 0, sizeof(ops));
-	ops.pitchdelta = 5.0;
-	ops.chan = chan;
-
-	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "VoiceChangeDial() requires an argument\n");
-		return -1;
-	}
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(args, parse);
-
-	if (ast_strlen_zero(args.dialstr)) {
-		ast_log(LOG_WARNING, "VoiceChangeDial() requires a dial string\n");
-		return -1;
-	}
-	ops.tech = args.dialstr;
-	if (!(ops.dest = strchr(args.dialstr, '/'))) {
-		ast_log(LOG_ERROR, "Invalid dial string %s\n", args.dialstr);
-		return -1;
-	}
-	*ops.dest++ = '\0';
-	if (!ast_strlen_zero(args.options)) {
-		if (ast_app_parse_options(voicechangedial_options, &opts, opt_args, args.options))
-			return -1;
-	}
-
-	ops.options |= ast_test_flag(&opts, APP_VOICECHANGEDIAL_PEEREFFECT) ? APP_VOICECHANGEDIAL_PEEREFFECT : 0;
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_DYNAMIC_DEPRECATED)) {
-		ops.options |= APP_VOICECHANGEDIAL_DYNAMIC_DEPRECATED;
-		if ((ops.options & APP_VOICECHANGEDIAL_PEEREFFECT) == APP_VOICECHANGEDIAL_PEEREFFECT) {
-			ops.peer_dtmfactions[ASCII2DTMF('*')] = DTMFACTION_LOWERPITCH;
-			ops.peer_dtmfactions[ASCII2DTMF('#')] = DTMFACTION_RAISEPITCH;
-		} else {
-			ops.chan_dtmfactions[ASCII2DTMF('*')] = DTMFACTION_LOWERPITCH;
-			ops.chan_dtmfactions[ASCII2DTMF('#')] = DTMFACTION_RAISEPITCH;
-		}
-	}
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_HANGUP_DEPRECATED)) {
-		ops.options |= APP_VOICECHANGEDIAL_HANGUP_DEPRECATED;
-		ops.chan_dtmfactions[ASCII2DTMF('*')] = DTMFACTION_HANGUP;
-	}
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_SUICIDE_DEPRECATED)) {
-		ops.options |= APP_VOICECHANGEDIAL_SUICIDE_DEPRECATED;
-		ops.peer_dtmfactions[ASCII2DTMF('*')] = DTMFACTION_HANGUP;
-	}
-
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_PITCH) && !ast_strlen_zero(opt_args[OPT_ARG_VOICECHANGEDIAL_PITCH])) {
-		ops.options |= APP_VOICECHANGEDIAL_PITCH;
-		ops.pitch = strtof(opt_args[OPT_ARG_VOICECHANGEDIAL_PITCH], NULL);
-	} else
-		ops.pitch = -5.0;
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_TIMEOUT) && !ast_strlen_zero(opt_args[OPT_ARG_VOICECHANGEDIAL_TIMEOUT])) {
-		ops.options |= APP_VOICECHANGEDIAL_TIMEOUT;
-		ops.timeout = strtol(opt_args[OPT_ARG_VOICECHANGEDIAL_TIMEOUT], NULL, 10);
-	}
-	if (ops.timeout > 0)
-		ops.timeout *= 1000;
-	else
-		ops.timeout = 60000;
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_DYNAMIC) && !ast_strlen_zero(opt_args[OPT_ARG_VOICECHANGEDIAL_DYNAMIC])) {
-		char *down, *up, *delta;
-		ops.options |= APP_VOICECHANGEDIAL_DYNAMIC;
-		down = ast_strdupa(opt_args[OPT_ARG_VOICECHANGEDIAL_DYNAMIC]);
-		if (!(up = strchr(down, ':'))) {
-			ast_log(LOG_ERROR, "Invalid D() argument format\n");
-			return -1;
-		}
-		*up++ = '\0';
-		if ((delta = strchr(up, ':'))) {
-			*delta++ = '\0';
-			ops.pitchdelta = strtof(delta, NULL);
-			ast_verbose(VERBOSE_PREFIX_4 "Setting pitch delta to %f semitones\n",
-				    ops.pitchdelta);
-		}
-		if (strlen(down) != 1 || !ISDTMFDIGIT(down[0])) {
-			ast_log(LOG_ERROR, "Invalid DTMF digit for D(down)\n");
-			return -1;
-		}
-		if (strlen(up) != 1 || !ISDTMFDIGIT(up[0])) {
-			ast_log(LOG_ERROR, "Invalid DTMF digit for D(up)\n");
-			return -1;
-		}
-		if ((ops.options & APP_VOICECHANGEDIAL_PEEREFFECT) == APP_VOICECHANGEDIAL_PEEREFFECT) {
-			ops.peer_dtmfactions[ASCII2DTMF(down[0])] = DTMFACTION_LOWERPITCH;
-			ops.peer_dtmfactions[ASCII2DTMF(up[0])]   = DTMFACTION_RAISEPITCH;
-		} else {
-			ops.chan_dtmfactions[ASCII2DTMF(down[0])] = DTMFACTION_LOWERPITCH;
-			ops.chan_dtmfactions[ASCII2DTMF(up[0])]   = DTMFACTION_RAISEPITCH;
-		}
-	}
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_HANGUP) && !ast_strlen_zero(opt_args[OPT_ARG_VOICECHANGEDIAL_HANGUP])) {
-		const char *s;
-		ops.options |= APP_VOICECHANGEDIAL_HANGUP;
-		s = opt_args[OPT_ARG_VOICECHANGEDIAL_HANGUP];
-		if (strlen(s) != 1 || !ISDTMFDIGIT(s[0])) {
-			ast_log(LOG_ERROR, "Invalid DTMF digit for H()\n");
-			return -1;
-		}
-		ops.chan_dtmfactions[ASCII2DTMF(s[0])] = DTMFACTION_HANGUP;
-	}
-	if (ast_test_flag(&opts, APP_VOICECHANGEDIAL_SUICIDE) && !ast_strlen_zero(opt_args[OPT_ARG_VOICECHANGEDIAL_SUICIDE])) {
-		const char *s;
-		ops.options |= APP_VOICECHANGEDIAL_SUICIDE;
-		s = opt_args[OPT_ARG_VOICECHANGEDIAL_SUICIDE];
-		if (strlen(s) != 1 || !ISDTMFDIGIT(s[0])) {
-			ast_log(LOG_ERROR, "Invalid DTMF digit for H()\n");
-			return -1;
-		}
-		ops.peer_dtmfactions[ASCII2DTMF(s[0])] = DTMFACTION_HANGUP;
-	}
-
-	rc = voicechangedial_exec(&ops);
-
-	return rc;
-}
-
-int load_module(void)
-{
-	return ast_register_application(app, voicechangedial_app_exec, synopsis, desc);
-}
-
-int unload_module(void)
-{
-	ast_module_user_hangup_all();
-	return ast_unregister_application(app);
-}
-
-#ifdef _ASTERISK_1_2_
-
-int usecount(void)
-{
-	int res;
-	STANDARD_USECOUNT(res);
-	return res;
-}
-
-char *key()
-{
-	return ASTERISK_GPL_KEY;
-}
-
-char *description(void)
-{
-	return "Voice Changer Dial Application";
-}
-
-#else /* #ifdef _ASTERISK_1_2_ */
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Voice Changer Dial Application");
-
-#endif /* #ifdef _ASTERISK_1_2_ */

app_voicechanger.c

+/*
+ * Asterisk Voice Changer 0.7
+ *
+ * Copyright (C) 2005-2009 Lobstertech, Inc.
+ *
+ * J.A. Roberts Tunney <jtunney@lobstertech.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License version 2.0.
+ *
+ * Keep it Open Source Pigs
+ *
+ */
+
+#define AST_MODULE "app_voicechanger"
+
+#include "asterisk.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <soundtouch4c.h>
+
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/audiohook.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/cli.h"
+#include "asterisk/options.h"
+#include "asterisk/app.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/utils.h"
+
+static const char *app = "VoiceChanger";
+static const char *synopsis = "Adjusts the pitch of your voice";
+static const char *desc = ""
+"  VoiceChanger(<pitch>)\n\n"
+"Specify a pitch in semitones.  Like -5 for deeper and 5 for higher.\n"
+"";
+
+static const char *stop_app = "StopVoiceChanger";
+static const char *stop_synopsis = "Removes voice changer";
+static const char *stop_desc = ""
+"  StopVoiceChanger()\n\n"
+"Removes the voice change effect from a channel, if there is any.\n"
+"";
+
+static struct soundtouch *soundtouch_create(float pitch)
+{
+	struct soundtouch *snd;
+
+	ast_log(LOG_DEBUG, "Creating SoundTouch object...\n");
+	snd = SoundTouch_construct();
+	if (!snd) {
+		ast_log(LOG_WARNING, "Failed to create SoundTouch object\n");
+		return NULL;
+	}
+
+	SoundTouch_setChannels(snd, 1);
+	SoundTouch_setSampleRate(snd, 8000);
+	SoundTouch_setPitchSemiTonesFloat(snd, pitch);
+	SoundTouch_setSetting(snd, SETTING_USE_QUICKSEEK, 1);
+	SoundTouch_setSetting(snd, SETTING_USE_AA_FILTER, 1);
+
+	return snd;
+}
+
+struct voice_changer {
+	struct soundtouch *st;
+	struct ast_audiohook *ah;
+};
+
+static void voicechanger_free(void *data)
+{
+	struct voice_changer *vc;
+	if (!data)
+		return;
+	vc = (struct voice_changer *)data;
+	if (vc->ah) {
+		ast_log(LOG_DEBUG, "Freeing AudioHook object...\n");
+		ast_free(vc->ah);
+	}
+	if (vc->st) {
+		ast_log(LOG_DEBUG, "Freeing SoundTouch object...\n");
+		SoundTouch_destruct(vc->st);
+	}
+	ast_free(vc);
+	ast_log(LOG_DEBUG, "Done!\n");
+}
+
+static const struct ast_datastore_info voice_change_ds = {
+	.type    = "VoiceChanger",
+	.destroy = voicechanger_free,
+};
+
+static int audio_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
+			  struct ast_frame *frame, enum ast_audiohook_direction direction)
+{
+	struct ast_datastore *ds;
+	struct voice_changer *vc;
+
+	if (chan && frame && direction == AST_AUDIOHOOK_DIRECTION_READ) {
+		ds = ast_channel_datastore_find(chan, &voice_change_ds, "VoiceChanger");
+		if (!ds) {
+			ast_log(LOG_WARNING, "Could not fetch voice changer datastore!\n");
+			return -1;
+		}
+		vc = (struct voice_changer *)ds->data;
+		if (!ds) {
+			ast_log(LOG_WARNING, "SoundTouch object missing from datastore!\n");
+			return -1;
+		}
+		SoundTouch_putSamples(vc->st, frame->data, frame->samples);
+		memset(frame->data, 0, frame->datalen);
+		SoundTouch_receiveSamplesEx(vc->st, frame->data, frame->samples);
+	}
+
+	return 0;
+}
+
+static int attach_audiohook(struct ast_channel *chan, struct ast_audiohook *audiohook) 
+{
+	struct ast_channel *peer;
+	int rc;
+
+	rc = ast_audiohook_attach(chan, audiohook);
+	if (!rc && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
+		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
+
+	return rc;
+}
+
+static int install_vc(struct ast_channel *chan, float pitch)
+{
+	struct ast_datastore *ds;
+	struct voice_changer *vc;
+
+	if (pitch < 0.1 && pitch > -0.1)
+		return 0;
+
+	/* create soundtouch object */
+	vc = ast_calloc(1, sizeof(struct voice_changer));
+	if (!(vc->st = soundtouch_create(pitch))) {
+		voicechanger_free(vc);
+		return -1;
+	}
+
+	/* create audiohook */
+	ast_log(LOG_DEBUG, "Creating AudioHook object...\n");
+	vc->ah = ast_calloc(1, sizeof(struct ast_audiohook));
+	if (ast_audiohook_init(vc->ah, AST_AUDIOHOOK_TYPE_MANIPULATE, "VoiceChanger")) {
+		voicechanger_free(vc);
+		return -1;
+	}
+	vc->ah->manipulate_callback = audio_callback;
+	if (attach_audiohook(chan, vc->ah) != 0) {
+		ast_log(LOG_WARNING, "Unable to add '%s' audiohook to channel '%s'\n", "VoiceChanger", chan->name);
+		voicechanger_free(vc);
+		return -1;
+	}
+
+	/* attach these renegade pointers to the channel */
+	ds = ast_channel_datastore_alloc(&voice_change_ds, "VoiceChanger");
+	ds->data = vc;
+	ast_channel_datastore_add(chan, ds);
+
+	return 0;
+}
+
+static int voicechanger_exec(struct ast_channel *chan, void *data)
+{
+	int rc;
+	struct ast_module_user *u;
+	float pitch;
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "Voicechanger requires an argument (pitch)\n");
+		return -1;
+	}
+	pitch = strtof(data, NULL);
+
+	u = ast_module_user_add(chan);
+	rc = install_vc(chan, pitch);
+	ast_module_user_remove(u);
+
+	return rc;
+}
+
+static int uninstall_vc(struct ast_channel *chan)
+{
+	struct ast_datastore *ds;
+	struct voice_changer *vc;
+	struct ast_audiohook *audiohook = NULL;
+	int found = 0;
+
+	ds = ast_channel_datastore_find(chan, &voice_change_ds, "VoiceChanger");
+	if (!ds) 
+		return 0;
+	vc = (struct voice_changer *)ds->data;
+
+	ast_log(LOG_DEBUG, "Detaching Voice Changer from channel...\n");
+
+	if (ast_audiohook_detach_source(chan, "VoiceChanger") != 0)
+		ast_log(LOG_WARNING, "could not find audiohook :(\n");
+
+	/* change uid of datastore so it doesn't conflict with voice changer instances */
+	free(ds->uid);
+	ds->uid = ast_malloc(32);
+	snprintf(ds->uid, 32, "VOICHG_%d", ast_random());
+
+	return 0;
+}
+
+static int stop_voicechanger_exec(struct ast_channel *chan, void *data)
+{
+	int rc;
+	struct ast_module_user *u;
+
+	u = ast_module_user_add(chan);
+	rc = uninstall_vc(chan);
+	ast_module_user_remove(u);
+
+	return rc;
+}
+
+static int unload_module(void)
+{
+	int res;
+	res  = ast_unregister_application(app);
+	res |= ast_unregister_application(stop_app);
+	ast_module_user_hangup_all();
+	return res;
+}
+
+static int load_module(void)
+{
+	int res;
+	res  = ast_register_application(app, voicechanger_exec, synopsis, desc);
+	res |= ast_register_application(stop_app, stop_voicechanger_exec, stop_synopsis, stop_desc);
+	return res;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hooked Voice Changer");

mkdep

-#!/bin/sh -
-#
-#	$OpenBSD: mkdep.gcc.sh,v 1.8 1998/09/02 06:40:07 deraadt Exp $
-#	$NetBSD: mkdep.gcc.sh,v 1.9 1994/12/23 07:34:59 jtc Exp $
-#
-# Copyright (c) 1991, 1993
-#	The Regents of the University of California.  All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-#    must display the following acknowledgement:
-#	This product includes software developed by the University of
-#	California, Berkeley and its contributors.
-# 4. Neither the name of the University nor the names of its contributors
-#    may be used to endorse or promote products derived from this software
-#    without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-#	@(#)mkdep.gcc.sh	8.1 (Berkeley) 6/6/93
-#
-
-D=.depend			# default dependency file is .depend
-append=0
-pflag=
-
-while :
-	do case "$1" in
-		# -a appends to the depend file
-		-a)
-			append=1
-			shift ;;
-
-		# -f allows you to select a makefile name
-		-f)
-			D=$2
-			shift; shift ;;
-
-		# the -p flag produces "program: program.c" style dependencies
-		# so .o's don't get produced
-		-p)
-			pflag=p
-			shift ;;
-		*)
-			break ;;
-	esac
-done
-
-if [ $# = 0 ] ; then
-	echo 'usage: mkdep [-p] [-f depend_file] [cc_flags] file ...'
-	exit 1
-fi
-
-DTMP=/tmp/mkdep$$
-TMP=$DTMP/mkdep
-
-um=`umask`
-umask 022
-if ! mkdir $DTMP ; then
-	echo failed to create tmp dir $DTMP
-	exit 1
-fi
-
-umask $um
-trap 'rm -rf $DTMP ; trap 2 ; kill -2 $$' 1 2 3 13 15
-
-if [ x$pflag = x ]; then
-	${CC:-cc} -M "$@" | sed -e 's; \./; ;g' > $TMP
-else
-	${CC:-cc} -M "$@" | sed -e 's;\.o :; :;' -e 's; \./; ;g' > $TMP
-fi
-
-if [ $? != 0 ]; then
-	echo 'mkdep: compile failed.'
-	rm -rf $DTMP
-	exit 1
-fi
-
-if [ $append = 1 ]; then
-	cat $TMP >> $D
-	if [ $? != 0 ]; then
-		echo 'mkdep: append failed.'
-		rm -rf $DTMP
-		exit 1
-	fi
-else
-	mv $TMP $D
-	if [ $? != 0 ]; then
-		echo 'mkdep: rename failed.'
-		rm -rf $DTMP
-		exit 1
-	fi
-fi
-
-rm -rf $DTMP
-exit 0